深入探讨ASP.NET MVC的筛选器

在ActionInvoker对Action的执行过程中,除了通过利用 ActionDescriptor对Action方法的执行,以及之前进行的Model绑定与验证之外,还具有一个重要的工作,那就是对相关筛选器 (Filter)的执行。ASP.NET MVC的筛选器是一种基于AOP(面向方面编程)的设计,我们将一些非业务的逻辑实现在相应的筛选器中,然后以一种横切(Crosscutting)的方 式应用到对应的Action方法。当Action方法执行前后,这些筛选器会自动执行。ASP.NET MVC提供了四种类型的筛选器(AuthorizationFilter、ActionFilter、ResultFilter和 ExceptionFilter),它们对应着相应的筛选器接口(IAuthorizationFilter、IActionFilter、 IResultFilter和IExceptionFilter)。

一、Filter

虽然ASP.NET MVC提供的四种类型的筛选器具有各自实现的接口,但是对于筛选器的提供体系来说所有的筛选器都通过具有如下定义的Filter类型表示。Filter的核心是Instance属性,因为它代表真正实施筛选功能的对象,该对象实现了一个或者多个基于上述四种筛选器类型的接口。

   1:publicclass Filter
   2: {    
   3:publicconstint DefaultOrder = -1;   
   4:public Filter(object instance, FilterScope scope, int? order);
   5:
   6:publicobject Instance { get; protected set; }
   7:publicint Order { get; protected set; }
   8:public FilterScope Scope { get; protected set; }
   9: }
  10:  
  11:publicenum FilterScope
  12: {
  13:     Action        = 30,
  14:     Controller    = 20,
  15:     First         = 0,
  16:     Global        = 10,
  17:     Last          = 100
  18: }

注: 由于System.Web.Mvc.Filter和实现了IAuthorizationFilter、IActionFilter、 IResultFilter和IExceptionFilter的类型均可以被称为“筛选器”,为了不至于造成混淆,在没有做明确说明的情况下,我们使用 英文“Filter”和中文“筛选器”分别来表示它们。
Filter的Order和 Scope属性最终决定了筛选器的执行顺序。Order属性对应数值越小,执行的优先级越高,该属性的默认值为-1(对应着Filter中定义的常量 DefaultOrder)。如果两个Filter具有相同的Order属性值,那么Scope属性最终决定哪个被优先执行。Filter的Scope属 性类型是一个类型为FilterScope的枚举。该枚举表示应用Filter的范围,Action和Controller代表Action方法和Controller类级别;First和Last意味着希望被作为第一个和最后一个Filter来执行;Global代表一个全局的Filter。
通 过上面的代码片断我们可以看到FilterScope的5个枚举选项均被设置了一个值,这个值决定了Filter的执行顺序,具有更小的枚举值会被优先执 行。从FilterScope的定义可以得到这样的结论:对于具有相同Order属性值的多个Filter,应用在Controller上的Filter 比应用在Action方法上的Filter具有更高的执行优先级,而一个全局的Filter的执行优先级又高于基于Action的Filter。

二、FilterProvider

Filter的提供机制与之前我们介绍的基于ModelBinder和ModelValidator的提供机制比较类似,均是通过相应的Provider来提供的。提供筛选器的FilterProvider实现了接口IFilterProvider,如下面的代码片断所示,该接口定义了唯一的方法GetFilters根据指定的Controller上下文和用于描述目标Action的ActionDescriptor对象获取一个Filter对象集合。

   1:publicinterface IFilterProvider
   2: {   
   3:     IEnumerable<Filter> GetFilters(ControllerContext controllerContext,
ActionDescriptor actionDescriptor);
   4: }

我们可以通过静态类型FilterProviders注册或者获取当前应用使用的FilterProvider。如下面的代码片断所示,FilterProviders具有一个类型为FilterProviderCollection的 只读属性Providers,表示基于整个Web应用范围内被使用的FilterProvider列表。 FilterProviderCollection是元素类型为IFilterProvider的集合,GetFilters方法用于或者该集合中所有 FilterProvider对象提供的Filter对象。

   1:publicstaticclass FilterProviders
   2: {    
   3:publicstatic FilterProviderCollection Providers { get; }
   4: }
   5:  
   6:publicclass FilterProviderCollection : Collection<IFilterProvider>
   7: {   
   8:
   9://其他成员
  10:public IEnumerable<Filter> GetFilters(ControllerContext controllerContext,
 ActionDescriptor actionDescriptor);   
  11: }