程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> ASP.NET >> 關於ASP.NET >> 深入探討ASP.NET MVC的篩選器

深入探討ASP.NET MVC的篩選器

編輯:關於ASP.NET

在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: public class Filter
2: {
3: public const int DefaultOrder = -1;
4: public Filter(object instance, FilterScope scope, int? order);
5:
6: public object Instance { get; protected set; }
7: public int Order { get; protected set; }
8: public FilterScope Scope { get; protected set; }
9: }
10:
11: public enum 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: public interface IFilterProvider
2: {
3: IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor);
4: }

我們可以通過靜態類型FilterProviders注冊或者獲取當前應用使用的FilterProvider。如下面的代碼片斷所示,FilterProviders具有一個類型為FilterProviderCollection的只讀屬性Providers,表示基於整個Web應用范圍內被使用的FilterProvider列表。FilterProviderCollection是元素類型為IFilterProvider的集合,GetFilters方法用於或者該集合中所有FilterProvider對象提供的Filter對象。

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

ASP.NET MVC提供了三種原生的FilterProvider,分別是FilterAttributeFilterProvider、ControllerInstanceFilterProvider和GlobalFilterCollection,接下來我們對它們進行單獨介紹。

三、FilterAttribute與FilterAttributeFilterProvider

我們通常將篩選器定義成特性以聲明的方式應用到Controller類型或者Action方法上,而抽象類型FilterAttribute是所有篩選器的基類。如下面的代碼片斷所示,FilterAttribute特性實現了IMvcFilter接口,該接口定義了Order和AllowMultiple兩個只讀屬性,分別用於控制篩選器的執行順序以及多個同類的篩選器能夠同時應用到同一個目標元素(類或者方法)。

   1: [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited=true, AllowMultiple=false)]
2: public abstract class FilterAttribute : Attribute, IMvcFilter
3: {
4: protected FilterAttribute();
5:
6: public bool AllowMultiple { get; }
7: public int Order { get; set; }
8: }
9:
10: public interface IMvcFilter
11: {
12: bool AllowMultiple { get; }
13: int Order { get; }
14: }

從應用在FilterAttribute上的AttributeUsageAttribute的定義可以看出該特性可以應用在類型和方法上,這意味著篩選器一般都可以應用在Controller類型和Action方法上。只讀屬性AllowMultiple實際上返回的是AttributeUsageAttribute的同名屬性,通過上面的定義我們可以看到默認情況下該屬性值為False。

用於描述Controller和Action的ControllerDescriptor和ActionDescriptor均實現了ICustomAttributeProvider接口,我們可以直接利用它們獲取應用在對應的Controller類型或者Action方法上包括FilterAttribute在內的所有特性。實際上,這兩個描述類型提供了單獨的方法GetFilterAttributes專門用於獲取FilterAttribute特性列表。如下面的代碼片斷所示,該方法具有一個布爾類型的參數useCache,表示是否需要對解析出來的FilterAttribute特性進行緩存以緩解頻繁的反射操作對性能造成的影響。

   1: public abstract class ControllerDescriptor : ICustomAttributeProvider, IUniquelyIdentifiable
2: {
3: //其他成員
4: public virtual IEnumerable<FilterAttribute> GetFilterAttributes(bool useCache);
5: }
6: public abstract class ActionDescriptor : ICustomAttributeProvider, IUniquelyIdentifiable
7: {
8: //其他成員
9: public virtual IEnumerable<FilterAttribute> GetFilterAttributes(bool useCache);
10: }

針對FilterAttribute特性的Filter通過FilterAttributeFilterProvider對象來提供。FilterAttributeFilterProvider直接調用當前ControllerDescriptor和ActionDescriptor的GetFilterAttributes方法獲取所有應用在Controller類型和當前Action方法的FilterAttribute特性,並借此創建相應的Filter對象。FilterAttributeFilterProvider構造函數的參數cacheAttributeInstances表示是否啟用針對FilterAttribute的緩存,它將作為調用GetFilterAttributes方法的參數。在默認的情況下(通過調用默認無參的構造函數創建的FilterAttributeFilterProvider)會采用針對FilterAttribute的緩存。

   1: public class FilterAttributeFilterProvider : IFilterProvider
2: {
3: public FilterAttributeFilterProvider();
4: public FilterAttributeFilterProvider(bool cacheAttributeInstances);
5: protected virtual IEnumerable<FilterAttribute> GetActionAttributes(ControllerContext controllerContext, ActionDescriptor actionDescriptor);
6: protected virtual IEnumerable<FilterAttribute> GetControllerAttributes(ControllerContext controllerContext, ActionDescriptor actionDescriptor);
7: public virtual IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor);
8: }

對於通過調用GetFilters得到的Filter,對應的FilterAttribute特性作為其Instance屬性。Order屬性來源於FilterAttribute的同名屬性,而Scope屬性則取決於FilterAttribute特性是應用在Controller類型上(Scope屬性值為Controller)還是當前的Action方法上(Scope屬性值為Action)。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved