在上一篇中我們講到控制器的執行過程系列,這個系列要擱置一段時間了,因為在控制器執行的過程中包含的信息都是要單獨的用一個系列來描述的,就如今天的這個篇幅就是在上面內容之后所看到的一個知識要點之一。
下面就來講解一下在ASP.NET Web API框架中過濾器的創建、執行過程。
過濾器所在的位置
圖1
圖1所示的就是控制器執行過程很粗略的表示。
通過上一篇內容我們了解到控制器方法選擇器最后返回的并不是控制器方法,而是對于控制器方法描述的類型HttpActionDescriptor,HttpActionDescriptor包含了控制器方法的一切信息,今天要講的就是HttpActionDescriptor對象中生成的過濾器管道執行的這么一個順序,當然其中就已經包含了創建的時候。
在介紹HttpActionDescriptor類型生成過濾器管道之前,我們先來對著其中會涉及到的一些類型進行一個基礎的了解。
基礎類型一覽
FilterInfo 過濾器對象封裝信息(System.Web.Http.Filters)
示例代碼1-1
public sealed class FilterInfo { public FilterInfo(IFilter instance, FilterScope scope); public IFilter Instance { get; } public FilterScope Scope { get; } }
在代碼1-1中想必大家也看到了,FilterInfo類型中有兩屬性,一個是有著過濾器類型的實例對象的引用也就是IFilter類型的Instance屬性,還有一個是FilterScope類型的Scope屬性表示當前這個過濾器在項目中的應用范圍,這個值很重要,在過濾器管道中可是根據這個值來排序的。
FilterScope 過濾器應用范圍(System.Web.Http.Filters)
示例代碼1-2
public enum FilterScope { // 摘要: // 在 Controller 之前指定一個操作。 Global = 0, // // 摘要: // 在 Action 之前和 Global 之后指定一個順序。 Controller = 10, // // 摘要: // 在 Controller 之后指定一個順序。 Action = 20, }
從代碼1-2中一目了然了,這里就不多說了。
IFilter 過濾器頂層接口(System.Web.Http.Filters)
示例代碼1-3
public interface IFilter { // 摘要: // 獲取或設置一個值,該值指示是否可以為單個程序元素指定多個已指示特性的實例。 // // 返回結果: // 如果可以指定多個實例,則為 true;否則為 false。默認值為 false。 bool AllowMultiple { get; } }
FilterAttribute 過濾器默認實現特性類(System.Web.Http.Filters)
// 摘要: // 表示操作-篩選器特性的基類。 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)] public abstract class FilterAttribute : Attribute, IFilter { // 摘要: // 初始化 System.Web.Http.Filters.FilterAttribute 類的新實例。 PRotected FilterAttribute(); // 摘要: // 獲取用于指示是否允許多個篩選器的值。 // // 返回結果: // 如果允許多個篩選器,則為 true;否則為 false。 public virtual bool AllowMultiple { get; } }
示例代碼1-4中我們可以看到FilterAttribute類型為過濾器默認的特性類型,而我們如果要想實現自定義的過濾器僅僅靠繼承自FilterAttribute是不行的,因為FilterAttribute特性類只是屬于過濾器概念中的“屬性”,而過濾器中的行為則是由過濾器類型來控制器的,也就是下面要說的。
IActionFilter 行為過濾器接口(System.Web.Http.Filters)
示例代碼1-5
public interface IActionFilter : IFilter { // 摘要: // 異步執行篩選器操作。 // // 參數: // actionContext: // 操作上下文。 // // cancellationToken: // 為此任務分配的取消標記。 // // continuation: // 在調用操作方法之后,委托函數將繼續。 // // 返回結果: // 為此操作新建的任務。 Task<System.Net.Http.HttpResponseMessage> ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<System.Net.Http.HttpResponseMessage>> continuation); }
這里暫時不對行為過濾器接口類型做什么講解,在最后的示例中會有運用到,而對于剩下的驗證過濾器和異常過濾器接口也都差不多了,這里就單獨的演示一個行為過濾器。
過濾器管道生成過程
這里我們還是要說到之前說過的HttpActionDescriptor類型,我來說一下大概的過程,首先呢在HttpActionDescriptor類型中有個內部字段叫_filterPipeline,從命名上就可以看出來大概的意思了,對的,過濾器管道的信息就是在這個字段中的,而它是個Lazy<Collection<FilterInfo>>類型。
在ApiController的執行中有個私有類型是FilterGrouping類型,它這個類型的作用是對過濾器管道中的所有過濾器進行分類,就是驗證歸驗證的,行為是行為的。
而實例化FilterGrouping類型的時候構造函數需要Collection<FilterInfo>類型的參數(也就是過濾器管道)來進行實例化,這個時候就是HttpActionDescriptor類型一展身手的時候了,看代碼1-6就是HttpActionDescriptor類型重的函數。
示例代碼1-6
public virtual Collection<FilterInfo> GetFilterPipeline() { return this._filterPipeline.Value; }
在上面我們也說到了_filterPipeline這個字段,那么它的Value在這個時候做了什么呢?
代碼1-6.1
this._filterPipeline = new Lazy<Collection<FilterInfo>>(new Func<Collection<FilterInfo>>(this.InitializeFilterPipeline));
看到這里我們只需要關注InitializeFilterPipeline這個函數的實現。
代碼1-6.2
private Collection<FilterInfo> InitializeFilterPipeline() { return new Collection<FilterInfo>(RemoveDuplicates((from fp in this._configuration.Services.GetFilterProviders() select fp.GetFilters(this._configuration, this)).OrderBy<FilterInfo, FilterInfo>(f => f, FilterInfoComparer.Instance).Reverse<FilterInfo>()).Reverse<FilterInfo>().ToList<FilterInfo>()); }
首先我們從這里看到的是,會從HttpConfiguration中的服務容器中獲取基礎服務,也就是實現了IFilterProvider的服務,而在其中也是有兩個過濾器提供程序,下面我直接貼上源碼
示例代碼1-7
public class ConfigurationFilterProvider : IFilterProvider { // Methods public IEnumerable<FilterInfo> GetFilters(HttpConfiguration configuration, HttpActionDescriptor actionDescriptor) { if (configuration == null) { throw Error.ArgumentNull("configuration"); } return configuration.Filters; } }
在代碼1-7中返回的就是HttpConfiguration中的Filters屬性中的值。這里了解一下繼續往下看,
代碼1-8
public class ActionDescriptorFilterProvider : IFilterProvider { // Methods public IEnumerable<FilterInfo> GetFilters(HttpConfiguration configuration, HttpActionDescriptor actionDescriptor) { if (configuration == null) { throw Error.ArgumentNull("configuration"); } if (actionDescriptor == null) { throw Error.ArgumentNull("actionDescriptor"); } IEnumerable<FilterInfo> first = from instance in actionDescriptor.ControllerDescriptor.GetFilters() select new FilterInfo(instance, FilterScope.Controller); IEnumerable<FilterInfo> second = from instance in actionDescriptor.GetFilters() select new FilterInfo(instance, FilterScope.Action); return first.Concat<FilterInfo>(second); } }
在代碼1-7中返回的是注冊在全局范圍使用的過濾器,而在代碼1-8中則是控制器和控制器方法范圍的過濾器。
這個時候我們再看代碼1-6.2中的FilterInfoComparer.Instance的默認實現。
代碼1-9
public int Compare(FilterInfo x, FilterInfo y) { if ((x == null) && (y == null)) { return 0; } if (x == null) { return -1; } if (y == null) { return 1; } return (int) (x.Scope - y.Scope); }
過濾器管道生成結果示例
看到這里大家想必已經知道了返回的過濾器管道中是什么樣子的了吧,如果不清楚也沒關系,下面的示例來說明一下。
同種類型過濾器覆蓋面的執行優先級:
服務端(SelfHost):
代碼1-10
using System.Web.Http.Controllers;using System.Web.Http.Filters;using NameSpaceControllerThree;namespace SelfHost{ class Program { static void Main(string[] args) { HttpSelfHostConfiguration selfHostConfiguration = new HttpSelfHostConfiguration("http://localhost/selfhost"); using (HttpSelfHostServer selfHostServer = new HttpSelfHostServer(selfHostConfiguration)) { selfHostServer.Configuration.Routes.MapHttpRoute( "DefaultApi", "api/{controller}/{id}", new { id = RouteParameter.Optional }); selfHostServer.Configuration.Services.Replace(typeof(IAssembliesResolver), new CustomAssembliesResolver.LoadSpecifiedAssembliesResolver()); //添加全局過濾器 selfHostServer.Configuration.Filters.Add(new WebAPIController.Filter.CustomConfigurationActionFilterAttribute()); selfHostServer.OpenAsync(); Console.WriteLine("服務器端服務監聽
新聞熱點
疑難解答