這篇文章主要講解了“ASP.NET MVC的篩選器詳細介紹”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“ASP.NET MVC的篩選器詳細介紹”吧!
創(chuàng)新互聯(lián)公司技術(shù)團隊十年來致力于為客戶提供成都網(wǎng)站建設(shè)、成都網(wǎng)站設(shè)計、成都品牌網(wǎng)站建設(shè)、營銷型網(wǎng)站、搜索引擎SEO優(yōu)化等服務(wù)。經(jīng)過多年發(fā)展,公司擁有經(jīng)驗豐富的技術(shù)團隊,先后服務(wù)、推廣了成百上千網(wǎng)站,包括各類中小企業(yè)、企事單位、高校等機構(gòu)單位。目錄
一、Filter
二、FilterProvider
三、FilterAttribute與FilterAttributeFilterProvider
四、Controller與ControllerInstanceFilterProvider
五、GlobalFilterCollection
六、實例演示:驗證Filter的提供機制和執(zhí)行順序
一、Filter
雖然ASP.NET MVC提供的四種類型的篩選器具有各自實現(xiàn)的接口,但是對于篩選器的提供體系來說所有的篩選器都通過具有如下定義的Filter類型表示。Filter的核心是Instance屬性,因為它代表真正實施篩選功能的對象,該對象實現(xiàn)了一個或者多個基于上述四種篩選器類型的接口。
public class Filter { public const int DefaultOrder = -1; public Filter(object instance, FilterScope scope, int? order); public object Instance { get; protected set; } public int Order { get; protected set; } public FilterScope Scope { get; protected set; } } public enum FilterScope { Action = 30, Controller = 20, First = 0, Global = 10, Last = 100 }
注:由于System.Web.Mvc.Filter和實現(xiàn)了IAuthorizationFilter、IActionFilter、IResultFilter和IExceptionFilter的類型均可以被稱為“篩選器”,為了不至于造成混淆,在沒有做明確說明的情況下,我們使用英文“Filter”和中文“篩選器”分別來表示它們。
Filter的Order和Scope屬性最終決定了篩選器的執(zhí)行順序。Order屬性對應(yīng)數(shù)值越小,執(zhí)行的優(yōu)先級越高,該屬性的默認值為-1(對應(yīng)著Filter中定義的常量DefaultOrder)。如果兩個Filter具有相同的Order屬性值,那么Scope屬性最終決定哪個被優(yōu)先執(zhí)行。Filter的Scope屬性類型是一個類型為FilterScope的枚舉。該枚舉表示應(yīng)用Filter的范圍,Action和Controller代表Action方法和Controller類級別;First和Last意味著希望被作為第一個和最后一個Filter來執(zhí)行;Global代表一個全局的Filter。
通過上面的代碼片斷我們可以看到FilterScope的5個枚舉選項均被設(shè)置了一個值,這個值決定了Filter的執(zhí)行順序,具有更小的枚舉值會被優(yōu)先執(zhí)行。從FilterScope的定義可以得到這樣的結(jié)論:對于具有相同Order屬性值的多個Filter,應(yīng)用在Controller上的Filter比應(yīng)用在Action方法上的Filter具有更高的執(zhí)行優(yōu)先級,而一個全局的Filter的執(zhí)行優(yōu)先級又高于基于Action的Filter。
二、FilterProvider
Filter的提供機制與之前我們介紹的基于ModelBinder和ModelValidator的提供機制比較類似,均是通過相應(yīng)的Provider來提供的。提供篩選器的FilterProvider實現(xiàn)了接口IFilterProvider,如下面的代碼片斷所示,該接口定義了的方法GetFilters根據(jù)指定的Controller上下文和用于描述目標Action的ActionDescriptor對象獲取一個Filter對象集合。
public interface IFilterProvider { IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor); }
我們可以通過靜態(tài)類型FilterProviders注冊或者獲取當前應(yīng)用使用的FilterProvider。如下面的代碼片斷所示,F(xiàn)ilterProviders具有一個類型為FilterProviderCollection的只讀屬性Providers,表示基于整個Web應(yīng)用范圍內(nèi)被使用的FilterProvider列表。FilterProviderCollection是元素類型為IFilterProvider的集合,GetFilters方法用于或者該集合中所有FilterProvider對象提供的Filter對象。
public static class FilterProviders { public static FilterProviderCollection Providers { get; } } public class FilterProviderCollection : Collection<IFilterProvider> { //其他成員 public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor); }
ASP.NET MVC提供了三種原生的FilterProvider,分別是FilterAttributeFilterProvider、ControllerInstanceFilterProvider和GlobalFilterCollection,接下來我們對它們進行單獨介紹。
三、FilterAttribute與FilterAttributeFilterProvider
我們通常將篩選器定義成特性以聲明的方式應(yīng)用到Controller類型或者Action方法上,而抽象類型FilterAttribute是所有篩選器的基類。如下面的代碼片斷所示,F(xiàn)ilterAttribute特性實現(xiàn)了IMvcFilter接口,該接口定義了Order和AllowMultiple兩個只讀屬性,分別用于控制篩選器的執(zhí)行順序以及多個同類的篩選器能夠同時應(yīng)用到同一個目標元素(類或者方法)。
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited=true, AllowMultiple=false)] public abstract class FilterAttribute : Attribute, IMvcFilter { protected FilterAttribute(); public bool AllowMultiple { get; } public int Order { get; set; } } public interface IMvcFilter { bool AllowMultiple { get; } int Order { get; } }
從應(yīng)用在FilterAttribute上的AttributeUsageAttribute的定義可以看出該特性可以應(yīng)用在類型和方法上,這意味著篩選器一般都可以應(yīng)用在Controller類型和Action方法上。只讀屬性AllowMultiple實際上返回的是AttributeUsageAttribute的同名屬性,通過上面的定義我們可以看到默認情況下該屬性值為False。
用于描述Controller和Action的ControllerDescriptor和ActionDescriptor均實現(xiàn)了ICustomAttributeProvider接口,我們可以直接利用它們獲取應(yīng)用在對應(yīng)的Controller類型或者Action方法上包括FilterAttribute在內(nèi)的所有特性。實際上,這兩個描述類型提供了單獨的方法GetFilterAttributes專門用于獲取FilterAttribute特性列表。如下面的代碼片斷所示,該方法具有一個布爾類型的參數(shù)useCache,表示是否需要對解析出來的FilterAttribute特性進行緩存以緩解頻繁的反射操作對性能造成的影響。
public abstract class ControllerDescriptor : ICustomAttributeProvider, IUniquelyIdentifiable { //其他成員 public virtual IEnumerable<FilterAttribute> GetFilterAttributes(bool useCache); } public abstract class ActionDescriptor : ICustomAttributeProvider, IUniquelyIdentifiable { //其他成員 public virtual IEnumerable<FilterAttribute> GetFilterAttributes(bool useCache); }
針對FilterAttribute特性的Filter通過FilterAttributeFilterProvider對象來提供。FilterAttributeFilterProvider直接調(diào)用當前ControllerDescriptor和ActionDescriptor的GetFilterAttributes方法獲取所有應(yīng)用在Controller類型和當前Action方法的FilterAttribute特性,并借此創(chuàng)建相應(yīng)的Filter對象。FilterAttributeFilterProvider構(gòu)造函數(shù)的參數(shù)cacheAttributeInstances表示是否啟用針對FilterAttribute的緩存,它將作為調(diào)用GetFilterAttributes方法的參數(shù)。在默認的情況下(通過調(diào)用默認無參的構(gòu)造函數(shù)創(chuàng)建的FilterAttributeFilterProvider)會采用針對FilterAttribute的緩存。
public class FilterAttributeFilterProvider : IFilterProvider { public FilterAttributeFilterProvider(); public FilterAttributeFilterProvider(bool cacheAttributeInstances); protected virtual IEnumerable<FilterAttribute> GetActionAttributes(ControllerContext controllerContext, ActionDescriptor actionDescriptor); protected virtual IEnumerable<FilterAttribute> GetControllerAttributes(ControllerContext controllerContext, ActionDescriptor actionDescriptor); public virtual IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor); }
對于通過調(diào)用GetFilters得到的Filter,對應(yīng)的FilterAttribute特性作為其Instance屬性。Order屬性來源于FilterAttribute的同名屬性,而Scope屬性則取決于FilterAttribute特性是應(yīng)用在Controller類型上(Scope屬性值為Controller)還是當前的Action方法上(Scope屬性值為Action)。
四、Controller與ControllerInstanceFilterProvider
提到ASP.NET MVC的篩選器,大部分的都只會想到通過FilterAttribute特性,實際上Controller本身(繼承自抽象類Controller)就是一個篩選器。如下面的代碼片斷所示,抽象類Controller實現(xiàn)了IActionFilter、IAuthorizationFilter、IExceptionFilter和IResultFilter這四個對應(yīng)著不同篩選器類型的接口。
public abstract class Controller : ControllerBase, IActionFilter, IAuthorizationFilter, IExceptionFilter, IResultFilter, ... { //省略成員 }
針對Controller對象這種獨特篩選器的FilterProvider類型為具有如下定義的ControllerInstanceFilterProvider。在實現(xiàn)的GetFilters方法中,它會根據(jù)指定的Controller上下文獲取對應(yīng)的Controller對象,并以此創(chuàng)建一個Filter(Controller對象作為Filter對象的Instance屬性值)。該Filter的Scope不是Controller,而是First,而Order的值為-2147483648(Int32.MinValue),毫無疑問這樣的Filter肯定第一個被執(zhí)行。
public class ControllerInstanceFilterProvider : IFilterProvider { public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor); }
五、GlobalFilterCollection
通過FilterAttribute的形式定義的篩選器需要顯式地標注到目標Controller類型或者Action方法上,而在有些情況下需要一種全局的Filter。所謂全局篩選器,就是不需要顯式與某個Controller或者Action進行匹配,而是默認使用到所有的Action執(zhí)行過程中。用于提供這種全局Filter的FilterProvider對應(yīng)的類型為具有如下定義的GlobalFilterCollection。
public sealed class GlobalFilterCollection : IEnumerable<Filter>, IEnumerable, IFilterProvider { public GlobalFilterCollection(); public void Add(object filter); public void Add(object filter, int order); private void AddInternal(object filter, int? order); public void Clear(); public bool Contains(object filter); public IEnumerator<Filter> GetEnumerator(); public void Remove(object filter); IEnumerator IEnumerable.GetEnumerator(); IEnumerable<Filter> IFilterProvider.GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor); public int Count { get; } }
通過命名以及上面給出的定義可以看出GlobalFilterCollection就是一個Filter的列表而已,實現(xiàn)的GetFilters方法返回的就是它自己。通過GlobalFilterCollection提供的方法我們可以實現(xiàn)對全局Filter的添加、刪除和清除操作。用于添加Filter的Add方法的參數(shù)filter不是一個Filter對象,而是一個具體篩選器(實現(xiàn)了相應(yīng)的篩選器接口),添加的Filter對象根據(jù)該篩選器對象創(chuàng)建,其Scope屬性被設(shè)置成Global。我們通過在Add方法指定添加Filter對象的Order屬性,如果沒有顯示指定Order并且指定的篩選器是一個FilterAttribute特性,那么該特性的Order將會作為Filter對象的Order;否則使用-1作為Order屬性值。
針對整個Web應(yīng)用的全局Filter(或者說全局FilterProvider)的注冊和獲取可以通過靜態(tài)類型GlobalFilters來實現(xiàn)。如下面的代碼片斷所示,GlobalFilters具有一個靜態(tài)只讀屬性Filters返回一個GlobalFilterCollection對象。
public static class GlobalFilters { public static GlobalFilterCollection Filters { get; } }
到目前為止,我們已經(jīng)介紹了ASP.NET MVC默認提供的三種FilterProvider,以及各自采用得Filter提供機制。當用于注冊FilterProvider的靜態(tài)類型在加載的時候,會默認創(chuàng)建這三種類型的對象并將其作為表示全局FilterProvider集合的Providers屬性值,具體的邏輯體現(xiàn)在如下的代碼片斷中。也就是說,在默認的情況下ASP.NET MVC會采用這三種FilterProvider來提供所有的Filter對象。
public static class FilterProviders { static FilterProviders() { Providers = new FilterProviderCollection(); Providers.Add(GlobalFilters.Filters); Providers.Add(new FilterAttributeFilterProvider()); Providers.Add(new ControllerInstanceFilterProvider()); } public static FilterProviderCollection Providers{get;private set;} }
六、實例演示:驗證Filter的提供機制和執(zhí)行順序
為了讓讀者對上面介紹的Filter提供機制具有一個更加深刻的映像,我們來做一個簡單的實例演示。在一個通過Visual Studio的ASP.NET MVC項目模板創(chuàng)建的空Web項目中,我們定義了如下一個幾個FilterAttribute。FilterBaseAttribute是一個實現(xiàn)了IActionFilter接口的抽象類型,三個具體的FilterAttribute(FooAttribute、BarAttribute和BazAttribute)是它的繼承者。
public abstract class FilterBaseAttribute:FilterAttribute, IActionFilter { public void OnActionExecuted(ActionExecutedContext filterContext) {} public void OnActionExecuting(ActionExecutingContext filterContext) {} } public class FooAttribute : FilterBaseAttribute {} public class BarAttribute : FilterBaseAttribute {} public class BazAttribute : FilterBaseAttribute {}
我們首先在Global.asax中通過如下的方式將BazAttribute注冊為一個全局篩選器。需要注意的是定義在默認創(chuàng)建的Global.asax中的Application_Start方法會調(diào)用RegisterGlobalFilters方法注冊一個類型為HandleErrorAttribute的ExceptionFilter,我們需要將這行代碼注釋。
public class MvcApplication : System.Web.HttpApplication { //其他成員 protected void Application_Start() { //其他操作 //RegisterGlobalFilters(GlobalFilters.Filters); GlobalFilters.Filters.Add(new BazAttribute()); } }
最后我們創(chuàng)建如下一個默認的HomeController,一個空的Action方法Data上應(yīng)用了我們定義的BarAttribute特性,而HomeController類上則應(yīng)用了FooAttribute特性。在默認的Action方法Index中,我們通過FilterProviders的靜態(tài)屬性Providers表示的全局FilterProvider列表得到針對于Action方法Data的所有Filter對象,并將它們的基本信息(類型、Order和Scope屬性)呈現(xiàn)出來。
[Foo] public class HomeController : Controller { public void Index() { ReflectedControllerDescriptor controllerDescriptor = new ReflectedControllerDescriptor(typeof(HomeController)); ActionDescriptor actionDescriptor = controllerDescriptor.FindAction(ControllerContext, "Data"); foreach (var filter in FilterProviders.Providers.GetFilters(ControllerContext, actionDescriptor)) { Response.Write(string.Format("{0}<br/>",filter.Instance)); Response.Write(string.Format(" {0}: {1}<br/>", "Order",filter.Order)); Response.Write(string.Format(" {0}: {1}<br/><br/>", "Scope",filter.Scope)); } } [Bar] public void Data() { } }
運行我們的程序之后會在瀏覽器中呈現(xiàn)如圖7-5所示的結(jié)果。我們可以清楚地看到,不僅僅應(yīng)用在自身Action方法的FilterAttribute會應(yīng)用到目標Action上,應(yīng)用在Controller類的FilterAttribute、全局注冊的Filter以及Controller對象本身體現(xiàn)的Filter都回最終應(yīng)用在所有的Action上面。
上圖將應(yīng)用于Action方法Data的4個Filter的Order和Scope屬性顯示出來。我們在前面提到這兩個屬性決定了同類篩選器執(zhí)行的順序,我們現(xiàn)在利用這個程序要證實這一點。為此我們需要對FilterBaseAttribute作如下的修改,在OnActionExecuting中我們將當前執(zhí)行的FilterAttribute的類型的方法名呈現(xiàn)出來。
public abstract class FilterBaseAttribute:FilterAttribute, IActionFilter { public void OnActionExecuted(ActionExecutedContext filterContext) {} public void OnActionExecuting(ActionExecutingContext filterContext) { filterContext.HttpContext.Response.Write(string.Format("{0}.OnActionExecuting()<br/>", this.GetType())); } }
然后我們按照相同的方式重寫了HomeController的OnActionExecuting方法,將HomeController自身的類型的當前方法名稱呈現(xiàn)出來。
[Foo] public class HomeController : Controller { //其他成員 protected override void OnActionExecuting(ActionExecutingContext filterContext) { Response.Write("HomeController.OnActionExecuting()<br/>"); } [Bar] public void Data() { } }
我們再次運行我們的程序,并在瀏覽器上指定正確的地址訪問定義在HomeController的Action方法Data,會在瀏覽器中呈現(xiàn)如下圖所示的結(jié)果。輸出的結(jié)果體現(xiàn)了應(yīng)用到Action方法Data上的四個ActionFilter執(zhí)行的順序,而這是和Filter對應(yīng)的Order和Scope屬性值是一致的。
關(guān)于Filter的提供還另一個值得深究的問題:我們在定義FilterAttribute的時候可以將應(yīng)用在該類型上的AttributeUsageAttribute的AllowMultiple屬性設(shè)置為False使它只能在同一個目標元素上應(yīng)用一次。但是,我們依然可以在Action方法和所在的Controller類型上應(yīng)用它們,甚至可以將它們注冊為全局Filter,那么這些FilterAttribute都將有效嗎?
我們現(xiàn)在就來通過實例來驗證這一點。現(xiàn)在我們刪除所有的FilterAttribute,定義如下一個類型為FooAttribute的ActionFilter,我們將應(yīng)用在它上面的AttributeUsageAttribute特性的AllowMultiple屬性設(shè)置為False。
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)] public class FooAttribute : FilterAttribute, IActionFilter { public void OnActionExecuted(ActionExecutedContext filterContext) { } public void OnActionExecuting(ActionExecutingContext filterContext) { } }
現(xiàn)在我們將該FooAttribute特性同時應(yīng)用在HomeController類型和Action方法Data上,然后在Global.asax中注冊一個針對FooAttribute特性的全局Filter。
[Foo] public class HomeController : Controller { //其他成員 [Foo] public void Data() { } } public class MvcApplication : System.Web.HttpApplication { //其他成員 protected void Application_Start() { //其他操作 //RegisterGlobalFilters(GlobalFilters.Filters); GlobalFilters.Filters.Add(new FooAttribute()); } }
現(xiàn)在我們直接運行我們的程序,開啟的瀏覽器中會呈現(xiàn)出如圖7-7所示的結(jié)果。可以清楚地看到雖然我們 在三個地方注冊了FooAttribute,但是由于該特性的AllowMultiple屬性為False,所以只有其中一個FooAttribute最終是有效的。
對于AllowMultiple屬性為False的FilterAttribute來說,如果我們以不同的Scope注冊了多個,最終有效的是哪個呢?從上圖可以看出,應(yīng)用在Action方法(Scope為Action)上的FooAttribute是有效的。其實具體的邏輯是這樣的:所有被創(chuàng)建的Filter按照Order+Scope進行排序(即Filter執(zhí)行的順序),取排在最后一個。對于我們的例子來說,提供的三個Filter具有相同的Order屬性值(-1),所有最終會按照Scope(Scope、Controller和Action)進行排序,排在最后一個的自然是Scope為Action的Filter。
感謝各位的閱讀,以上就是“ASP.NET MVC的篩選器詳細介紹”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對ASP.NET MVC的篩選器詳細介紹這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是創(chuàng)新互聯(lián)網(wǎng)站建設(shè)公司,,小編將為大家推送更多相關(guān)知識點的文章,歡迎關(guān)注!
分享名稱:ASP.NETMVC的篩選器詳細介紹-創(chuàng)新互聯(lián)
瀏覽地址:http://aaarwkj.com/article30/gdcso.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站營銷、靜態(tài)網(wǎng)站、App設(shè)計、網(wǎng)站排名、服務(wù)器托管、網(wǎng)站設(shè)計公司
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容