- Filter就是特性,特性是定义在类或者属性上的,另外提一下,MVC的Filter是在控制器实例化之后反射获取的,比一般HttpModule扩展的方法要靠后执行且能具体到类以及其方法;
- Filter 接口及其默认实现类,4种接口,3种实现类,下面将通过继承实现类,复写响应的方法实现自定义MVC过滤器
Filter类型 | 接口 | MVC的默认实现 | Description |
---|
Authorization | IAuthorizationFilter | AuthorizeAttribute | 最先执行,在其他类型的filter和action方法前执行 |
Action | IActionFilter | ActionFilterAttribute | 在action方法执行前和执行后执行 |
Result | IResultFilter | ActionFilterAttribute | 在result执行前和执行后执行 |
Exception | IExceptionFilter | HandleErrorAttribute | 在抛出异常时执行,(异常发生在action/result/filter) |
-
AuthorizeAttribute
权限过滤器
- 新增一个自定义类,继承自
AuthorizeAttribute
类,重写OnAuthorization()
方法,注意细节:
- 全局注册:在
Global.asax
里的Application_Start()
方法里的过滤器注册里注册,即在FilterConfig.RegisterGlobalFilters()
里新增一行代码:filters.Add(new CustomAuthorizeAttribute("~/Login/index"));
- 允许自定义登录页的URL,即没有登录的请求,自动跳转到指定登录页去,并设有登录页URL默认值;
- 首先判断有没有匿名特性,要判断方法和控制器上是否有
filterContext.ActionDescriptor.IsDefined(typeof(AllowHtmlAttribute), true) || filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowHtmlAttribute), true)
,如果允许匿名则直接return
; - 如果登录失败,除了跳转到登录页,还要考虑是否是ajax请求,如果是则:
if(httpContext.Request.IsAjaxRequest())
并返回filterContext.Result = new JsonResult(){data={}}
,否则跳转页面(return view()
或return Redirect()
或return RedirectToAction()
) - 如果登录失败,记录初始请求的URL在
Session
里,然后再登录页面后台代码里,如果登录成功,判断Seesion
里是否有指定名称的URL,如果有则跳转到这个URL里,否则跳转到首页; - 登录成功,直接
return;
,只有验证失败,才需要给httpContext.result
赋值,成功不用赋值(null),MVC自动会进入action
里;
public override void OnAuthorization(AuthorizationContext filterContext)
{
bool re = filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true) || filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true);
if (re)
{
return;
}
var session = filterContext.HttpContext.Session["CurrentUser"];
if (session != null)
{
return;
}
else
{
filterContext.HttpContext.Session["PreUrl"] = filterContext.HttpContext.Request.Url;
filterContext.Result = new RedirectResult(_LoginUrl);
}
}
-
HandleErrorAttribute
异常过滤器
- 与权限过滤器类似,先新增一个类,继承自
HandleErrorAttribute
,重写OnExceptionHandle()
方法; - 全局注册,也是在
FilterConfig.RegisterGlobalFilters()
新增一行:filters.Add(new MyHandleErrorAttribute());
; - 一般记录日志,错误信息在这个属性里:
filterContext.Exception
,然后将exceptionHandled
设置为true
,表示已处理了这个异常,同理处理这个异常前,也要判断这个属性exceptionHandled
,为false
才表示还未处理此异常; - 过滤器
filter
的生效是在控制器controller
实例化且方法调用后才生效的,所以控制器实例化的错误不能被捕获到,同理,URL错误也不会被捕获; - 还有一种可以捕获MVC所有异常的方法,在
Global.asax
里新增protected void Application_Error(object sender, EventArgs e){ Exception error = Server.GetLastError(); //日志记录; Server.ClearError();}
,但此异常捕获,比较粗犷;
public override void OnException(ExceptionContext filterContext)
{
if (!filterContext.ExceptionHandled)
{
LogHelper.WriteLog($"{filterContext.HttpContext.Request.Url.ToString()}", filterContext.Exception);
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
filterContext.Result = new JsonResult()
{
Data = new AjaxResult()
{
Result = DoResult.Failed,
PromptMsg = filterContext.Exception.Message,
}
};
}
else
{
filterContext.Result = new RedirectResult("~/common/error");
}
filterContext.ExceptionHandled = true;
}
}
-
ActionFilterAttribute
方法过滤器
- ActionFilterAttribute类既实现了IactionFilter接口,也实现IResultFilter接口。
- 与之前的2个过滤器类似,新增类,继承类;
- 不过里面有4个方法,分别时Action执行前,Action执行后,Result前,Result后;
- 也可以全局注册或只在某个控制器或某个方法上,比如压缩响应结果;
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var acceptEncoding = filterContext.HttpContext.Request.Headers["Accept-Encoding"];
if (string.IsNullOrEmpty(acceptEncoding))
{
return;
}
if (acceptEncoding.IndexOf("gzip", StringComparison.OrdinalIgnoreCase) >= 0)
{
filterContext.HttpContext.Response.Filter = new GZipStream(filterContext.HttpContext.Response.Filter, CompressionLevel.Optimal);
filterContext.HttpContext.Response.Headers.Add("Content-encoding", "gzip");
}
else if (acceptEncoding.IndexOf("deflate", StringComparison.OrdinalIgnoreCase) >= 0)
{
filterContext.HttpContext.Response.Filter = new DeflateStream(filterContext.HttpContext.Response.Filter, CompressionLevel.Fastest);
filterContext.HttpContext.Response.Headers.Add("Content-encoding", "deflate");
}
}
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new MyHandleErrorAttribute());
filters.Add(new MyAuthorizeAttribute());
filters.Add(new MyCompressAttribute());
}
AOP与MVC的Filter
- MVC的Filter就是AOP的实现,MVC的Filter最细只能到Action级别,而第三方的AOP可以细到Action内部的方法,只要这个方法实现了指定的接口;