过滤器
MVC有4种过滤器。
过滤器 接口 默认实现
Authorization IAuthorizationFilter AuthorizeAttribute
Action IActionFilter ActionFilterAttribute
Result IResultFilter ActionFilterAttribute
Exception IExceptionFilter HandleErrorAttribute
在生成过滤器时,可以直接实现过滤器的接口;也可以派生自默认实现,再重载里面的处理方法。
一、动作和结果过滤器(Action和Result)
动作过滤器内的方法有两个:
OnActionExecuting()
OnActionExecuted()
结果过滤器内的方法有两个:
OnResultExecuting()
OnResultExecuted()
执行时,在使用了过滤器的动作方法之前先执行OnActionExecuting(),然后执行动作方法,最后执行OnActionExecuted()。
再然后,开始执行OnResultExecuting(),接着执行动作方法中返回的视图(实际就是ActionResult大类),最后执行OnResultExecuted()。
例,新建MVC3项目13-21MvcFilters,在解决方案中新建目录 Infrastructure -> Filters,在此存放要建立的各个过滤器的类文件。
1、直接实现Action过滤器接口和Result过滤器接口
两个类放在一个文件中。
namespace _13_21MvcFilters.Infrastructure.Filters { public class MyActionFilterAttribute : FilterAttribute, IActionFilter { public void OnActionExecuting(ActionExecutingContext filterContext) { ... ... } public void OnActionExecuted(ActionExecutedContext filterContext) { ... ... } } public class MyResultFilterAttribute : FilterAttribute, IResultFilter { public void OnResultExecuting(ResultExecutingContext filterContext) { ... ... } public void OnResultExecuted(ResultExecutedContext filterContext) { ... ... } } }
2、也可以派生自动作、结果过滤器接口的默认实现ActionFilterAttribute
编写ActionFilterAttribute的派生类,然后重载里面的OnActionExecuting()、OnActionExecuted()、OnResultExecuting()、OnResultExecuted()方法。
namespace _13_21MvcFilters.Infrastructure.Filters { public class ProfileAllAttribute : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext filterContext) { ... ... } public override void OnActionExecuted(ActionExecutedContext filterContext) { ... ... } public override void OnResultExecuting(ResultExecutingContext filterContext) { ... ... } public override void OnResultExecuted(ResultExecutedContext filterContext) { ... ... } } }
例,在Infrastructure/Filters下新建类文件ProfileAllAttribute.cs,内容如下:
namespace _13_21MvcFilters.Infrastructure.Filters { public class ProfileAllAttribute : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext filterContext) { filterContext.HttpContext.Response.Write( string.Format("OnActionExecuting<br>")); } public override void OnActionExecuted(ActionExecutedContext filterContext) { filterContext.HttpContext.Response.Write( string.Format("OnActionExecuted<br>")); } public override void OnResultExecuting(ResultExecutingContext filterContext) { filterContext.HttpContext.Response.Write( string.Format("OnResultExecuting<br>")); } public override void OnResultExecuted(ResultExecutedContext filterContext) { filterContext.HttpContext.Response.Write( string.Format("OnResultExecuted<br>")); } } }
新建控制器HomeController:
namespace _13_21MvcFilters.Controllers { public class HomeController : Controller { [ProfileAll] public ActionResult Index() { Response.Write("Action Method is running...<br>"); return View(); } } }
添加视图Index.cshtml:
@{ ViewBag.Title = "Index"; } <h2>Index</h2>
结果显示为:
3、全局过滤器;同一个过滤器带参数重复施加在一个动作方法上;施加在同一个动作方法上的过滤器执行顺序
(1)在Infrastructure/Filters目录下,定义过滤器如下:
namespace _13_21MvcFilters.Infrastructure.Filters { [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true)] public class SimpleMessageAttribute : ActionFilterAttribute { public string Message { get; set; } public override void OnActionExecuting(ActionExecutingContext fileterContext) { fileterContext.HttpContext.Response.Write( string.Format("[OnActionExecuting:{0}]<br>", Message)); } public override void OnActionExecuted(ActionExecutedContext filterContext) { filterContext.HttpContext.Response.Write( string.Format("[OnActionExecuted:{0}]<br>", Message)); } } }
如果要在同一个Action method上重复使用一个过滤器,那么在定义该过滤器时,需要加上属性:
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true)]
如果没有此属性,会产生Duplicate attribute错误。
(2)在HomeController的Index()动作方法上,以注解属性使用过滤器:
namespace _13_21MvcFilters.Controllers { public class HomeController : Controller { [SimpleMessage(Message = "A", Order = 1)] [SimpleMessage(Message = "B", Order = 2)] public ActionResult Index() { Response.Write("Action Method is running...<br>"); return View(); } } }
Index.cshtml视图为:
@{ ViewBag.Title = "Index"; } <h2>Index</h2>
(3)在Global.asax中,将过滤器SimpleMessageAttribute注册为全局过滤器,成为全局过滤器后,不需要显式的用注解属性来使用它,所有的动作方法都会自动施加该过滤器。
public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErrorAttribute()); filters.Add(new SimpleMessageAttribute() { Message = "Global" , Order = 1}); }
这样一来,施加在HomeController中,动作方法Index上的过滤器就相当于有3处,他们都设定了Order,按照Order的升序依次执行。最先执行的是全局过滤器。
如果没有设置Order,最先执行的是全局过滤器,而按照注解属性来使用的过滤器,执行顺序是不确定的(并不是按照出现的先后顺序来执行)
-lyj