ASP.NET MVC 中的过滤器
这里用实例说明各种过滤器的用法,有不对的地方还请大神指出,共同探讨。
1. ActionFilter 方法过滤器:
接口名为 IActionFilter ,在控制器方法调用前/后执行。
在新建的MVC程序中,添加一个类 MyFilter1Attribute 并继承ActionFilterAttribute抽象类
从上图可以看到 ActionFilterAttribute 中的所有方法,且有相应的介绍,我们可以通过继承 ActionFilterAttribute 类,并重写(override)它的方法,从而实现自定义Filter
public class MyFilter1Attribute: ActionFilterAttribute { /// <summary> /// 该方法会在Action方法执行之前调用 /// </summary> /// <param name="filterContext"></param> public override void OnActionExecuting(ActionExecutingContext filterContext) { filterContext.HttpContext.Response.Write("我是OnActionExecuting,我在Ation方法调用前执行<br/>"); base.OnActionExecuting(filterContext); } /// <summary> /// 该方法会在Action方法执行之后调用 /// </summary> /// <param name="filterContext"></param> public override void OnActionExecuted(ActionExecutedContext filterContext) { filterContext.HttpContext.Response.Write("我是OnActionExecuted,我在Action方法调用后执行<br/>"); base.OnActionExecuted(filterContext); } }
然后创建一个HomeController控制器,并添加FilterTest的测试Action
public class HomeController : Controller { public ActionResult Index() { return View(); } [MyFilter1] public void FilterTest() { Response.Write("我是Action方法,我在这里执行了.....<br/>"); } }
运行程序并访问FilterTest方法:
上图可看出它的一个执行顺序
但是有时候也有可能有这样的场景:当检查到Action有标识某个Attribute的时候,我们需要跳出,并不执行后续的方法的情况,我们可以通过filterContext中ActionDescriptior类中的IsDefained方法进行判断检查
/// <summary> /// 该方法会在Action方法执行之前调用 /// </summary> /// <param name="filterContext"></param> public override void OnActionExecuting(ActionExecutingContext filterContext) { filterContext.HttpContext.Response.Write("我是OnActionExecuting,我在Ation方法调用前执行<br/>"); //判断Action方法时是否有贴上MyFilter1Attribute标签 if (filterContext.ActionDescriptor.IsDefined(typeof(MyFilter1Attribute), false)) { //如果有,为该Action方法直接返回ContentResult,则该Action方法在这里就有了返回值,相当于在这里就结束了,不会再去执行之后的方法,例如:OnActionExecuted filterContext.Result = new ContentResult(); } base.OnActionExecuting(filterContext); }
2.ResultFilter 结果过滤器:
接口名为 IResultFilter,在控制器方法调用完,跳转至View页面前/后调用
同样在 MyFilter1Attribute 类中重写 OnResultExecuting 方法和 OnResultExecuted 方法
/// <summary> /// 该方法在Action方法返回结果之前执行 /// </summary> /// <param name="filterContext"></param> public override void OnResultExecuting(ResultExecutingContext filterContext) { filterContext.HttpContext.Response.Write("我是OnResultExecuting,我在Action方法返回结果前执行<br/>"); base.OnResultExecuting(filterContext); } /// <summary> /// 该方法在Action方法返回结果之后执行 /// </summary> /// <param name="filterContext"></param> public override void OnResultExecuted(ResultExecutedContext filterContext) { filterContext.HttpContext.Response.Write("我是OnResultExecuted,我在Action方法返回结果后执行<br/>"); base.OnResultExecuted(filterContext); }
然后在HomeController控制器中添加 FilterTest1
[MyFilter1] public ActionResult FilterTest1() { Response.Write("我是测试Action1方法,我在这里执行了.....<br/>"); return View(); }
运行程序,并访问 FilterTest1 ,执行结果如下:
可以看出OnResultExecuting 方法是在返回结果页面之前执行的,而OnResultExecuted是返回结果页面之后执行的
3.ExceptionFilter 异常操作过滤器:
接口名为 IExceptionFilter,在控制器的Action方法抛出异常时执行
可以通过异常过滤器捕获Controller中发生的异常,并记录到日志。
添加MyExceptionAttribute类,并继承HandleErrorAttribute,如下:
/// <summary> /// /// </summary> /// <param name="filterContext"></param> public override void OnException(ExceptionContext filterContext) { filterContext.HttpContext.Response.Write("我是OnException,在Controller中发生异常时进入<br/>"); //获取到异常对象 Exception ex = filterContext.Exception; //获取请求的Controller和Action string controllerName = filterContext.RouteData.Values["controller"].ToString(); string actionName = filterContext.RouteData.Values["action"].ToString(); //记录日志 string errMessage = string.Format("异常消息:控制器为:{0},Action为:{1},异常信息为:{2};", controllerName, actionName, ex.Message); OutPutLog(errMessage); //标记异常已做处理 filterContext.ExceptionHandled = true; base.OnException(filterContext); } /// <summary> /// 输出日志 /// </summary> /// <param name="message"></param> public void OutPutLog(string message) { string path = AppDomain.CurrentDomain.BaseDirectory + "/Logs.txt"; using (StreamWriter sw = new StreamWriter(path, true, Encoding.Default)) { sw.Flush(); sw.WriteLine("时间:" + DateTime.Now); sw.WriteLine("内容:" + message); sw.WriteLine("---------------------------------------------"); } }
在HomeController中添加FilterTest3
[MyException] public ActionResult FilterTest3() { Response.Write("我是测试Action3方法,我在这里执行了.....<br/>"); string str = "131464ddddd"; int i = int.Parse(str); return View(); }
运行程序并访问 FilterTest3方法,将会在 str 转换成int类型时抛出异常,随后将进入OnException方法,并记录日志如下:
4.AuthorizationFilter 授权过滤器:
接口名为 IauthorizationFilter,在所有过滤器中最先执行
添加一个MyFilter2Attribute类,并继承AuthorizeAttribute类,然后重写其OnAuthorization方法:
public class MyFilter2Attribute: AuthorizeAttribute
{
/// <summary>
/// 在所有的Action方法过滤之前执行
/// </summary>
/// <param name="filterContext"></param>
public override void OnAuthorization(AuthorizationContext filterContext)
{
filterContext.HttpContext.Response.Write("我是OnAuthorization,在所有Action方法过滤器之前执行<br/>");//base.OnAuthorization(filterContext);
}
}
在HoneController控制器中添加 FilterTest2
[MyFilter1]
[MyFilter2]
public ActionResult FilterTest2()
{
Response.Write("我是测试Action2方法,我在这里执行了.....<br/>");
return View();
}
运行程序并访问 FilterTest2 结果如下:
从上图执行结果可以看出,OnAuthorization 权重是最高的,将会在其他所有过滤器之前执行。
注意:
ActionFilter 和 ResultFilter 不仅可以对单个方法进行操作,也能对整个Controller进行操作,将过滤的头部属性移至控制名称上面即可。