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