基于.Net Framework 4.0 Web API开发(3):ASP.NET Web APIs 异常的统一处理Attribute 和统一写Log 的Attribute的实现
2016-07-05 17:43
891 查看
概述:
ASP.NET Web API 的好用使用过的都知道,没有复杂的配置文件,一个简单的ApiController加上需要的Action就能工作。但是项目,总有异常发生,本节就来谈谈API的异常的统一处理和写统一写log逻辑的解决方案。问题:
在ASP.NET Web API编写时,如果每个API都写异常处理逻辑,不但加大了开发工作量,且每个开发人员处理异常返回的数据结构也不尽相同,在异常发生情况下,客户端处理异常的逻辑就不再通用,也同时加大了对接接口人员的工作量,好的API错误码和错误信息都是固定格式,并后台应该有相应的异常记录。异常的统一处理的实现:
1. 首先定义异常处理Attribute,继承System.Web.Http.Filters.ExceptionAttribute, 重写OnException, 代码如下public class LogAttribute : ActionFilterAttribute { private string _msg = string.Empty; private string _token = string.Empty; private string _remark = string.Empty; public LogAttribute() { } public LogAttribute(string msg) { this._msg = msg; } //http://www.cnblogs.com/shan333chao/p/5002054.html private static readonly string key = "enterTime"; private const string UserToken = "token"; public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext) { if (actionContext.Request.Method != HttpMethod.Options) { // 标记log var logAction = actionContext.ActionDescriptor.GetCustomAttributes<NoLogAttribute>(); if (!logAction.Any()) { actionContext.Request.Properties[key] = DateTime.Now.ToBinary(); this._token = GetToken(actionContext, out this._remark); } } base.OnActionExecuting(actionContext); } public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) { if (actionExecutedContext.Request.Method != HttpMethod.Options) { object beginTime = null; if (actionExecutedContext.Request.Properties.TryGetValue(key, out beginTime)) { DateTime time = DateTime.FromBinary(Convert.ToInt64(beginTime)); var request = HttpContext.Current.Request; var logDetail = new LogDetail { //获取action名称 ActionName = actionExecutedContext.ActionContext.ActionDescriptor.ActionName, //获取Controller 名称 ControllerName = actionExecutedContext.ActionContext.ActionDescriptor.ControllerDescriptor.ControllerName, //获取action开始执行的时间 EnterTime = time, //获取执行action的耗时 CostTime = (DateTime.Now - time).TotalMilliseconds, Navigator = request.UserAgent, Token = this._token, //获取用户ID UId = UserTokenManager.GetUId(this._token), //获取访问的ip IP = request.UserHostAddress, UserHostName = request.UserHostName, UrlReferrer = request.UrlReferrer != null ? request.UrlReferrer.AbsoluteUri : "", Browser = request.Browser.Browser + " - " + request.Browser.Version + " - " + request.Browser.Type, //获取request提交的参数 Paramaters = GetRequestValues(actionExecutedContext), //获取response响应的结果 ExecuteResult = GetResponseValues(actionExecutedContext), AttrTitle = this._msg, Remark = this._remark, RequestUri = request.Url.AbsoluteUri }; // 登录log var logRep = ContainerManager.Resolve<ISysLogRepository>(); var log = new Log() { Action = actionExecutedContext.ActionContext.ActionDescriptor.ControllerDescriptor.ControllerName + "/" + actionExecutedContext.ActionContext.ActionDescriptor.ActionName, CreateDate = DateTime.Now, CreatorLoginName = RISContext.Current.CurrentUserInfo.UserName, IpAddress = request.UserHostAddress, Detail = Utility.JsonSerialize<LogDetail>(logDetail) }; logRep.Add(log); } } base.OnActionExecuted(actionExecutedContext); } private string GetToken(System.Web.Http.Controllers.HttpActionContext actionContext, out string msg) { Dictionary<string, object> actionArguments = actionContext.ActionArguments; HttpMethod type = actionContext.Request.Method; msg = ""; var token = ""; if (type == HttpMethod.Post) { if (actionArguments.ContainsKey(UserToken)) { if (actionArguments[UserToken] != null) token = actionArguments[UserToken].ToString(); } else { foreach (var value in actionArguments.Values) { if (value != null && value.GetType().GetProperty(UserToken) != null) token = value.GetType().GetProperty(UserToken).GetValue(value, null).ToString(); } } if (string.IsNullOrEmpty(token)) msg = "匿名用户"; } else if (type == HttpMethod.Get) { if (!actionArguments.ContainsKey(UserToken)) msg = "匿名用户"; // throw new HttpException(401, "还未登录"); if (actionArguments[UserToken] != null) token = actionArguments[UserToken].ToString(); else msg = "匿名用户"; } else if (type == HttpMethod.Options) { } else { throw new HttpException(404, "暂未开放除POST,GET之外的访问方式!"); } return token; } /// <summary> /// 读取request 的提交内容 /// </summary> /// <param name="actionExecutedContext"></param> /// <returns></returns> public string GetRequestValues(HttpActionExecutedContext actionExecutedContext) { Stream stream = actionExecutedContext.Request.Content.ReadAsStreamAsync().Result; Encoding encoding = Encoding.UTF8; /* 这个StreamReader不能关闭,也不能dispose, 关了就傻逼了 因为你关掉后,后面的管道 或拦截器就没办法读取了 */ var reader = new StreamReader(stream, encoding); string result = reader.ReadToEnd(); /* 这里也要注意: stream.Position = 0; 当你读取完之后必须把stream的位置设为开始 因为request和response读取完以后Position到最后一个位置,交给下一个方法处理的时候就会读不到内容了。 */ stream.Position = 0; return result; } /// <summary> /// 读取action返回的result /// </summary> /// <param name="actionExecutedContext"></param> /// <returns></returns> public string GetResponseValues(HttpActionExecutedContext actionExecutedContext) { Stream stream = actionExecutedContext.Response.Content.ReadAsStreamAsync().Result; Encoding encoding = Encoding.UTF8; /* 这个StreamReader不能关闭,也不能dispose, 关了就傻逼了 因为你关掉后,后面的管道 或拦截器就没办法读取了 */ var reader = new StreamReader(stream, encoding); string result = reader.ReadToEnd(); /* 这里也要注意: stream.Position = 0; 当你读取完之后必须把stream的位置设为开始 因为request和response读取完以后Position到最后一个位置,交给下一个方法处理的时候就会读不到内容了。 */ stream.Position = 0; return result; } }
View Code
2. 接下来定义不需要记录log的Attribute,代码如下:
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true)] public class NoErrorHandlerAttribute : Attribute { }
3. 注意不要在HttpConfiguration中注册使用 LogAttribute,除非你想所有的请求都写log,在不需要写log的Action上添加[NoLog],否则只需要在需要记录log的Action添加[Log]就可以完成写log的功能。
此篇到此结束,相对比较简单,欢迎大家讨论!
相关文章推荐
- 未将对象引用设置到对象实例(转)
- ASP.NET MVC Html.BeginForm
- asp.net spring.net+mvc 和j2ee spring mvc的思考
- 微信公众号token的asp.net脚本
- 搭建你的Spring.Net+Nhibernate+Asp.Net Mvc 框架 (六)写在后面的话
- 搭建你的Spring.Net+Nhibernate+Asp.Net Mvc 框架 (五)测试你的成果
- 搭建你的Spring.Net+Nhibernate+Asp.Net Mvc 框架 (四)配置全攻略
- 搭建你的Spring.Net+Nhibernate+Asp.Net Mvc 框架 (三)实现数据库接口层和业务逻辑层
- 搭建你的Spring.Net+Nhibernate+Asp.Net Mvc 框架 (二)创建你的项目
- 让整个table居于页面正中,(上下左右居中)。
- 搭建你的Spring.Net+Nhibernate+Asp.Net Mvc 框架 (一)搭建你的环境
- ASP.NET Core 介绍
- ASP.NET Core 介绍
- asp.net : 拒绝频繁的IP访问
- 使用jasperreports-5.6.0.jar导致的问题
- ASP.NET的缓存机制
- Android AOP 之AspectJ(一)
- asp.net Core开启全新的时代,用视频来告诉你,学习就是这么SO easy。
- 『ExtJS』表单(二)表单行为与Asp.NET页面的消息回复
- TimesTen 数据库复制学习:11. ASP带缓存组复制的几种固定架构模式