WebApi捕捉异常的一套方案
public class ExceptionFilter:ExceptionFilterAttribute { NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); public override void OnException(HttpActionExecutedContext actionExecutedContext) { actionExecutedContext?.Request?.Content?.ReadAsStreamAsync().Result.Seek(0, System.IO.SeekOrigin.Begin); StringBuilder sb = new StringBuilder(); sb.AppendLine($"请求路径:{actionExecutedContext?.Request?.RequestUri}" ); sb.AppendLine($"请求方法:{actionExecutedContext?.Request?.Method}" ); sb.AppendLine($"请求正文:{actionExecutedContext?.Request?.Content?.ReadAsStringAsync().Result}" ); //错误日志 var ex = actionExecutedContext.Exception; while (ex.InnerException != null) { ex = ex.InnerException; } sb.AppendLine($"异常类型:{ex.GetType().Name}"); sb.AppendLine($"异常说明:{ex.Message}"); sb.AppendLine($"异常堆栈:{ex.StackTrace}"); logger.Error(sb.ToString()); } }
简单说明一下上面的代码:
继承ExceptionFilterAttribute类,并重写OnException方法。
因为要获取请求中的正文,正文已经被之前的管道读取过,所以要把流的位置定位到最开始:actionExecutedContext?.Request?.Content?.ReadAsStreamAsync().Result.Seek(0, System.IO.SeekOrigin.Begin);
sb.AppendLine($"请求路径:{actionExecutedContext?.Request?.RequestUri}" ); sb.AppendLine($"请求方法:{actionExecutedContext?.Request?.Method}" ); sb.AppendLine($"请求正文:{actionExecutedContext?.Request?.Content?.ReadAsStringAsync().Result}" );
这三段就是简单的把请求的url,Method,Content记录下来以便我们程序异常后根据日志重现问题。
var ex = actionExecutedContext.Exception; while (ex.InnerException != null) { ex = ex.InnerException; }
获取到最里面的Exception,将错误信息记录下来。这样就能获得比较全面的错误日志了。
最后,要将我们的ExceptionFilter类替换掉api默认的Exception实现,找到WebApiConfig类,在HttpConfiguration的Filters中添加ExceptionFilter,代码如下:
public static class WebApiConfig { public static void Register(HttpConfiguration config) { //跨域配置 config.EnableCors(new EnableCorsAttribute("*", "*", "*")); // Web API 路由 config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); config.Filters.Add(new ExceptionFilter()); } }
大功告成!