关于MVC过滤器的介绍,网上的文章很多,可以看一下这个:《MVC过滤器详解》
在使用之前,先梳理一下过滤器的执行顺序:
一般的过滤器执行顺序
- IAuthorizationFilter->OnAuthorization(授权)
- IActionFilter ->OnActionExecuting(行为)
- Action
- IActionFilter ->OnActionExecuted(行为)
- IResultFilter ->OnResultExecuting(结果)
- View
- IResultFilter ->OnResultExecuted(结果)
- *IExceptionFilter ->OnException(异常),此方法并不在以上的顺序执行中,有异常发生时即会执行,有点类似于中断
当同时在Controller和Action中都设置了过滤器后,执行顺序一般是由外到里,即“全局”->“控制器”->“行为”
- Controller->IAuthorizationFilter->OnAuthorization
- Action ->IAuthorizationFilter->OnAuthorization
- Controller->IActionFilter ->OnActionExecuting
- Action ->IActionFilter ->OnActionExecuting
- Action
- Action ->IActionFilter ->OnActionExecuted
- Controller->IActionFilter ->OnActionExecuted
- Controller->IResultFilter ->OnResultExecuting
- Action ->IResultFilter ->OnActionExecuting
- Action ->IResultFilter ->OnActionExecuted
- Controller->IResultFilter ->OnActionExecuted
因为异常是从里往外抛,因次异常的处理顺序则刚好相反,一般是由里到外,即“行为”->“控制器”->“全局”
- Action ->IExceptionFilter->OnException
- Controller->IExceptionFilter->OnException
所以,为了精简代码量,只要在程序启动时注册全局过滤器就OK了;
过滤器代码如下:
[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)]
public class LogExceptionAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
if (!filterContext.ExceptionHandled)
{
string controllerName = (string)filterContext.RouteData.Values["controller"];
string actionName = (string)filterContext.RouteData.Values["action"];
string msgTemplate = "在执行 controller[{0}] 的 action[{1}] 时产生异常";
Exception ex = filterContext.Exception;
//doing some log
}
if (filterContext.Result is JsonResult)
{
//当结果为json时,设置异常已处理
filterContext.ExceptionHandled = true;
}
else
{
//否则调用原始设置
base.OnException(filterContext);
}
}
}
LogExceptionAttribute继承了HandleErrorAttribute,重写的OnException方法在记录异常日志后,通过调用base.OnException回到了系统默认的异常处理上,实现了向错误页面的跳转。
代码中增加了对JsonResult的判断,可以在此基础上进行条件的扩充,对一些特殊的情况进行处理。
注册全局过滤器代码:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new LogExceptionAttribute());
//filters.Add(new HandleErrorAttribute());
}
}
这种处理模式是还是比较通用的。在没有特定需求的情况下,控制器,逻辑层,数据访问层等,都不需要增加额外的异常处理的代码,产生异常后直接外抛,最终都会被异常过滤器拦截并进行处理,特别适合于站点上线后的运维;
当然,如果在开发时,使用try catch 会比较直接,但是会严重导致代码的臃肿!!!
这里只是举了一个过滤器的使用案例,我们可以举一反三,使用过滤器做更多的事情,比如说权限控制、站点操作日志记录等,后续再补充权限控制的内容