概述: 

  ASP.NET Web API 的好用使用过的都知道,没有复杂的配置文件,一个简单的ApiController加上需要的Action就能工作。但是项目,总有异常发生,本节就来谈谈API的异常的统一处理和写统一写log逻辑的解决方案。

问题:

   在ASP.NET Web API编写时,如果每个API都写异常处理逻辑,不但加大了开发工作量,且每个开发人员处理异常返回的数据结构也不尽相同,在异常发生情况下,客户端处理异常的逻辑就不再通用,也同时加大了对接接口人员的工作量,好的API错误码和错误信息都是固定格式,并后台应该有相应的异常记录。

异常的统一处理的实现:

1. 首先定义异常处理Attribute,继承System.Web.Http.Filters.ExceptionAttribute, 重写OnException, 代码如下

 1   public class ErrorHandleAttribute : System.Web.Http.Filters.ExceptionFilterAttribute
 2     {
 3         private string _msg = string.Empty;
 4 
 5         public ErrorHandleAttribute() { }
 6 
 7         public ErrorHandleAttribute(string msg)
 8         {
 9             this._msg = msg;
10         }
11         public override void OnException(System.Web.Http.Filters.HttpActionExecutedContext actionExecutedContext)
12         {
13             base.OnException(actionExecutedContext);
14             // 取得发生异常时的错误讯息
15             //var errorMessage = actionExecutedContext.Exception.Message;
16             // 标记log
17             var logAction = actionExecutedContext.ActionContext.ActionDescriptor.GetCustomAttributes<NoErrorHandlerAttribute>();
18             if (logAction.Any())
19             {
20                 actionExecutedContext.Response = actionExecutedContext.Request.CreateResponse(System.Net.HttpStatusCode.InternalServerError, new ResultData(ResultType.SystemException, actionExecutedContext.Exception.Message));
21                 return;
22             }
23 
24             var request = HttpContext.Current.Request;
25             var logDetail = new LogDetail
26             {
27                 //获取action名称
28                 ActionName = actionExecutedContext.ActionContext.ActionDescriptor.ActionName,
29                 //获取Controller 名称
30                 ControllerName = actionExecutedContext.ActionContext.ActionDescriptor.ControllerDescriptor.ControllerName,
31                 Navigator = request.UserAgent,
32                 //获取访问的ip
33                 IP = request.UserHostAddress,
34                 UserHostName = request.UserHostName,
35                 UrlReferrer = request.UrlReferrer != null ? request.UrlReferrer.AbsoluteUri : "",
36                 Browser = request.Browser.Browser + " - " + request.Browser.Version + " - " + request.Browser.Type,
37                 //获取request提交的参数
38                 Paramaters = GetRequestValues(actionExecutedContext),
39                 //获取response响应的结果
40                 //ExecuteResult = GetResponseValues(actionExecutedContext),  //这句会报错,异常没有处理结果
41                 AttrTitle = this._msg,
42                 ErrorMsg = string.Format("错误信息:{0}, 异常跟踪:{1}", actionExecutedContext.Exception.Message, actionExecutedContext.Exception.StackTrace),
43                 RequestUri = request.Url.AbsoluteUri
44             };
45 
46             // 写log
47             var logRep = ContainerManager.Resolve<ISysLogRepository>();
48             var log = new Log()
49             {
50                 Action = actionExecutedContext.ActionContext.ActionDescriptor.ControllerDescriptor.ControllerName + "/" + actionExecutedContext.ActionContext.ActionDescriptor.ActionName,
51                 CreateDate = DateTime.Now,
52                 CreatorLoginName = RISContext.Current.CurrentUserInfo.UserName,
53                 IpAddress = request.UserHostAddress,
54                 Detail = Utility.JsonSerialize<LogDetail>(logDetail)
55             };
56 
57             logRep.Add(log);
58             actionExecutedContext.Response = actionExecutedContext.Request.CreateResponse(System.Net.HttpStatusCode.InternalServerError, new ResultData(ResultType.SystemException, actionExecutedContext.Exception.Message));
59         }
60         
61         /// <summary>
62         /// 读取request 的提交内容
63         /// </summary>
64         /// <param name="actionExecutedContext"></param>
65         /// <returns></returns>
66         public string GetRequestValues(HttpActionExecutedContext actionExecutedContext)
67         {
68 
69             Stream stream = actionExecutedContext.Request.Content.ReadAsStreamAsync().Result;
70             Encoding encoding = Encoding.UTF8;
71             /*
72                 这个StreamReader不能关闭,也不能dispose, 关了就傻逼了
73                 因为你关掉后,后面的管道  或拦截器就没办法读取了
74             */
75             var reader = new StreamReader(stream, encoding);
76             string result = reader.ReadToEnd();
77             /*
78             这里也要注意:   stream.Position = 0;
79             当你读取完之后必须把stream的位置设为开始
80             因为request和response读取完以后Position到最后一个位置,交给下一个方法处理的时候就会读不到内容了。
81             */
82             stream.Position = 0;
83             return result;
84         }
85     }
View Code

相关文章: