并不是全部的异常都须要 try-catch 进行重复的处理,这会致使大量的重复性代码,一旦后续系统出现异常处理机制的修改,随着代码量增多,修改也会变的更加困难。css
ASP.NET Web API 中特别增长了全局异常过滤器功能,诸如于此的还有不少过滤器可供开发者选择,以实现面向切面编程,它们在取代重复性编码这一目标的路上,做出不少贡献,同时下降了后期维护代码的难度,提高了可读性。编程
大多数异常处理的 try-catch 都一般是一样的写法(记录异常日志、返回错误信息等),所以咱们能够将他们统一写在一个过滤器中,让 API 在出现异常时,即便没有使用 try-catch 嵌套异常位置和解决方案,也可以自动进入指望的异常处理方法。服务器
注意:这是专门针对 Web API 所使用的全局异常处理器。若是是 Controller,则它有另一套全局异常处理机制,由于一般状况下 MVC 的控制器不仅返回Json字符串,一般要涉及页面View,文件File,Json字符串等。ide
Get Start工具
下面咱们以一个最简单的异常处理过滤器代码为例,来讲明应当如何使全局异常处理器生效:编码
1.建立一个类 MyExceptionFilterAttribute,继承 ExceptionFilterAttribute, System.Web.Mvc.IExceptionFilter 并实现接口方法spa
using Newtonsoft.Json;
using System.Net.Http;
using System.Web.Http.Filters;
using System.Web.Mvc;日志
namespace WebAPITest.Filters
{
public class MyExceptionFilterAttribute : ExceptionFilterAttribute, System.Web.Mvc.IExceptionFilter
{
//MVC过滤器要求必须继承此接口才容许注册,但咱们能够继承、实现但不写它。
public void OnException(ExceptionContext filterContext)
{
throw new NotImplementedException();
}继承
//真正能让API全局异常过滤器在出现异常时生效的是这个家伙:
public override void OnException(HttpActionExecutedContext actionExecutedContext)
{
base.OnException(actionExecutedContext);接口
actionExecutedContext.Response = new HttpResponseMessage() { Content = new StringContent("出现异常") };
return;
}
}
2.为此全局异常处理器进行注册:
打开文件夹 App_Start 下的 FilterConfig.cs 为过滤器注册,由此才能使得过滤器生效。
特别说明:一旦进行了全局注册,则全部方法出现异常时,过滤器都会生效。
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new MyExceptionFilterAttribute());
}
做为特性标签使用
固然,上述 MyExceptionFilterAttribute 除了可注册为全局异常过滤器之外,也能够单独为 API 中的某些方法使用:(注意,方法自己就是"try",过滤器是"catch"。因此再也不须要在方法体内再次 try-catch)
using System.Net.Http;
using System.Web.Http;
using WebAPITest.Filters;
using WebAPITest.Models;
namespace WebAPITest.Controllers
{
//你也能够把过滤器标签打在这个地方,这表明该API类下的全部接口均接受[MyExceptionFilter]接管异常处理。
public class TestController : ApiController
{
[MyExceptionFilter] //特性标签打在此处,则 UserException 方法出现异常时会触发 MyExceptionFilterAttribute 中的异常处理方法。
public HttpResponseMessage UserException()
{
throw new UserException("用户异常");
}
[MyExceptionFilter] //同上,这一特性标签将帮助 SystemException 方法处理异常。
public HttpResponseMessage SystemException()
{
throw new Exception();
}
}
}
标签与全局注册的优先级问题
多个特性标签,能够全局注册,能够单独在方法名称上、类名上混合使用,那么若是一个标签被全局注册,另外一个标签被单独打在方法名上或者类名上,则最终哪个处理器的方法会被触发?
这些家伙的优先级其实和 css 层叠样式表的优先级相仿。
即:若是咱们全局注册过一个过滤器A,又在 ApiController 类的最顶端打了另一个B、又在Action方法上打了第三个异常处理器C,那么默认只会执行最靠近 Action 的C处理器,也就是说:ActionFilter > ClassFilter > GlobalFilter。
另外若是须要屡次执行所有生效,即:全局一次,Controller类一次,Action一次,那么则须要为过滤器顶端加那么一个标签 [AttributeUsage(AttributeTargets.All,AllowMultiple = true)],而后当异常触发时,他们就可以支持屡次执行。
固然,真正的异常处理还会涉及不少复杂的内容,这只是一个概览。例如返回值须要被标准化(包含状态码、消息、响应流等内容),调用异常处理工具向服务器发送异常信息记录,记录请求参数,对GET/POST请求致使异常的差别化处理方法等。
但咱们在这里提供的是一个思路,让你知道,精简代码、提高开发效率其实能够有更多的方法和可能性。而没必要非要使用同一种方式,当你以为某些步骤一直在不断重复,则应当已经有早期的开发者给出了解决方案,而你须要去发现他们。