Filter與FilterProvider之間的關係緩存
根據用途和執行時機的不一樣,MVC主要分爲如下5種類型的過慮器:AuthenticationFilter、AuthorizationFilter、ActionFilter、ExceptionFilter、ResultFilter。下面咱們來看一個IFilter接口,以下所示:mvc
public class Filter { public const int DefaultOrder = -1; public Filter(object instance, FilterScope scope, int? order) { //省略 if (order == null) { IMvcFilter mvcFilter = instance as IMvcFilter; if (mvcFilter != null) { order = mvcFilter.Order; } } Instance = instance; Order = order ?? DefaultOrder; Scope = scope; } public object Instance { get; protected set; } public int Order { get; protected set; } public FilterScope Scope { get; protected set; } } public enum FilterScope { First = 0, Global = 10, Controller = 20, Action = 30, Last = 100, }
一個Filter對象就是對一個過濾器的封裝,它將過濾器對象封裝在Instance屬性中。表示排序的Order屬性,默認爲-1,值越小越優先。還有一個表示範圍的Scope屬性,它是一個枚舉類型。其中Global、Controller、Action分別表示應用到整個應用範圍內、某個Controller上、某個Action上,另兩個First、Last代表是應用的第一個仍是最後一個。若是前面的Order屬性的值同樣大,那麼相同的Order的Filter則會按照Scope屬性值越小越優先。ide
全部的Filter均是經過FilterProvider來提供的,該接口的定義以下所示:函數
public interface IFilterProvider { IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor); }
該接口只定義了一個GetFilters方法,用於獲取某個Action方法上全部的Filter。它具備兩個參數ControllerContext表示當前的Controller的上下文,ActionDescriptor描述目標Action方法。性能
用於提供Filter的FilterProvider是經過靜態類型FilterProviders來註冊的。以下所示:
this
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; } }
從上咱們看到MVC提供了三種原生的FilterProvider,它們分別是:GlobalFilters.Filters用於提供全局、FilterAttributeFilterProvider用於提供Controller類和Action方法上、ControllerInstanceFilterProvider用於提供Controller這個別特的過濾器。下面來看FilterProvider是如何提供Filter的。spa
一、FilterAttributeFilterProvider
咱們一般是將過濾器定義成特性的方式標註到某個Controller或Action上。這樣的過濾器特性通常以FilterAttribute做爲基類。它實現了IMvcFilter接口,IMvcFilter只有兩個只讀屬性成員Order和AllowMultiple。在上面的Filter類中咱們看到若是實例能夠轉換爲IMvcFilter接口,那麼則將IMvcFilter的Order值賦給Filter的Order屬性。咱們在某個Action方法或Controller上標記某個特性時,能夠在上面指定Order值,如[Authorize(Order =3)]。以下所示:code
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)] public abstract class FilterAttribute : Attribute, IMvcFilter { private static readonly ConcurrentDictionary<Type, bool> _multiuseAttributeCache = new ConcurrentDictionary<Type, bool>(); private int _order = Filter.DefaultOrder; public bool AllowMultiple { get { return AllowsMultiple(GetType()); } } public int Order { get { return _order; } set { if (value < Filter.DefaultOrder) { throw new ArgumentOutOfRangeException("value", MvcResources.FilterAttribute_OrderOutOfRange); } _order = value; } } private static bool AllowsMultiple(Type attributeType) { return _multiuseAttributeCache.GetOrAdd( attributeType, type => type.GetCustomAttributes(typeof(AttributeUsageAttribute), true) .Cast<AttributeUsageAttribute>() .First() .AllowMultiple); } } public interface IMvcFilter { bool AllowMultiple { get; } int Order { get; } }
從應用在FilterAttribute的AttributeUsageAttribute特性上咱們能夠看到此特性能夠應用到類和方法上,AllowMultiple默認爲false,不容許多個。
獲取Controller類和Action方法上的特性是經過FilterAttributeFilterProvider來提供的。以下所示:對象
public class FilterAttributeFilterProvider : IFilterProvider { private readonly bool _cacheAttributeInstances; public FilterAttributeFilterProvider() : this(true) { } public FilterAttributeFilterProvider(bool cacheAttributeInstances) { _cacheAttributeInstances = cacheAttributeInstances; } protected virtual IEnumerable<FilterAttribute> GetActionAttributes(ControllerContext controllerContext, ActionDescriptor actionDescriptor) { return actionDescriptor.GetFilterAttributes(_cacheAttributeInstances); } protected virtual IEnumerable<FilterAttribute> GetControllerAttributes(ControllerContext controllerContext, ActionDescriptor actionDescriptor) { return actionDescriptor.ControllerDescriptor.GetFilterAttributes(_cacheAttributeInstances); } public virtual IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) { // Results are low in number in the common case so use yield return to avoid creating intermediate collections or nested enumerables if (controllerContext.Controller != null) { foreach (FilterAttribute attr in GetControllerAttributes(controllerContext, actionDescriptor)) { yield return new Filter(attr, FilterScope.Controller, order: null); } foreach (FilterAttribute attr in GetActionAttributes(controllerContext, actionDescriptor)) { yield return new Filter(attr, FilterScope.Action, order: null); } } } }
從上面的靜態類FilterProviders中,咱們能夠看到MVC默認註冊的是FilterAttributeFilterProvider的無參構造函數,而後它傳一個true調用有參構造函數,該_cacheAttributeInstances字段表示是否緩存獲取到的Filter。由於是經過反射獲取Controller和Action上的Filter,因此MVC默認緩存獲取到的Filter,提升性能。blog
該類實現的GetFilters方法,它會前後調用GetControllerAttributes方法和GetActionAttributes方法,分別獲取Cotroller和Action上Filter。分別用於描述 Controller和Action的ControllerDescriptor和ActionDescriptor類實現了ICustomAttributeProvider接口。咱們能夠調用相應的方法獲取應用在對應的Controller類型或Action方法上包括FilterAttribute在內的全部特性。以下所示:
public abstract class ControllerDescriptor : ICustomAttributeProvider, IUniquelyIdentifiable { public virtual object[] GetCustomAttributes(Type attributeType, bool inherit) { if (attributeType == null) { throw new ArgumentNullException("attributeType"); } return (object[])Array.CreateInstance(attributeType, 0); } public virtual IEnumerable<FilterAttribute> GetFilterAttributes(bool useCache) { return GetCustomAttributes(typeof(FilterAttribute), inherit: true).Cast<FilterAttribute>(); } } public abstract class ActionDescriptor : ICustomAttributeProvider, IUniquelyIdentifiable { public virtual object[] GetCustomAttributes(Type attributeType, bool inherit) { if (attributeType == null) { throw new ArgumentNullException("attributeType"); } return (object[])Array.CreateInstance(attributeType, 0); } public virtual IEnumerable<FilterAttribute> GetFilterAttributes(bool useCache) { return GetCustomAttributes(typeof(FilterAttribute), inherit: true).Cast<FilterAttribute>(); } }
二、ControllerInstanceFilterProvider
Controller自己就是一個過濾器,以下所示:
public abstract class Controller : ControllerBase, IActionFilter, IAuthenticationFilter, IAuthorizationFilter, IDisposable, IExceptionFilter, IResultFilter, IAsyncController, IAsyncManagerContainer { //省略 }
對於Controller這個特殊的過濾器,其對應的FilterProvider類型,以下所示:
public class ControllerInstanceFilterProvider : IFilterProvider { public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) { if (controllerContext.Controller != null) { // Use FilterScope.First and Order of Int32.MinValue to ensure controller instance methods always run first yield return new Filter(controllerContext.Controller, FilterScope.First, Int32.MinValue); } } }
它的GetFilter方法跟據ControllerContext獲取對應的Controller對象,並以此建立對應的Filter。
三、GlobalFilters.Filters
全局過濾器,它不是顯示的應用於某個Controller、某個Action上,而是默認應用到整個程序的全部Controller類型的Action方法上。以下所示:
public static class GlobalFilters { static GlobalFilters() { Filters = new GlobalFilterCollection(); } public static GlobalFilterCollection Filters { get; private set; } }
GlobalFilters就只有一個屬性GlobalFilterCollection,GlobalFilterCollection它是一個元素類型爲Filter的集合,它顯示地實現了IFilterProvider接口的GetFilters方法,返回的就是它本身,以下所示:
public sealed class GlobalFilterCollection : IEnumerable<Filter>, IFilterProvider { private List<Filter> _filters = new List<Filter>(); public void Add(object filter) { AddInternal(filter, order: null); } public void Add(object filter, int order) { AddInternal(filter, order); } private void AddInternal(object filter, int? order) { ValidateFilterInstance(filter); _filters.Add(new Filter(filter, FilterScope.Global, order)); } IEnumerable<Filter> IFilterProvider.GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) { return this; } //省略 }
到目前爲止,MVC默認提供的3種原生的FilterProvider以及各自採用的Filter提供機制介紹完畢。MVC的5種過濾器最終被封裝成相應的Filter對象,可是它們的執行時機和方式是不一樣的,因此在執行以前須要根據被封裝的過濾器類型對全部的Filter進行分組。就是當ControllerActionInvoker被調用時,它會利用靜態類型FilterProviders獲得全部註冊的IFilterProvider類型,而後利用當前的ControllerContext和ActionDescriptor對象獲得Filter,而後根據其Instance屬性表示的過濾器類型,將它分組,最終獲得一個具備以下所示FilterInfo類型的對象。
public class FilterInfo { public IList<IActionFilter> ActionFilters { get; } public IList<IAuthenticationFilter> AuthenticationFilters { get; } public IList<IAuthorizationFilter> AuthorizationFilters { get; } public IList<IExceptionFilter> ExceptionFilters { get; } public IList<IResultFilter> ResultFilters { get; } }