ASP.NET Web API 過濾器創建、執行過程(二)
前言
前面一篇中講解了過濾器執行之前的創建,通過實現IFilterProvider注冊到當前的HttpConfiguration里的服務容器中,當然默認的基礎服務也是有的,並且根據這些提供程序所獲得的的過濾器信息集合進行排序。本篇就會對過濾器在創建完之后所做的一系列操作進行講解。
ASP.NET Web API 過濾器創建、執行過程(二)
FilterGrouping過濾器分組類型
FilterGrouping類型是ApiController類型中的私有類型,它的作用就如同它的命名一樣,用來對過濾器集合進行分組,在上一篇中我們看到,在經過調用HttpActionDescriptor類型的GetFilterPipeline()方法之后回去獲取到排序過后的過濾器信息集合Collection<FilterInfo>。下面我們看一下FilterGrouping類型定義:
示例代碼1-1
private class FilterGrouping { // Fields private List<IActionFilter> _actionFilters = new List<IActionFilter>(); private List<IAuthorizationFilter> _authorizationFilters = new List<IAuthorizationFilter>(); private List<IExceptionFilter> _exceptionFilters = new List<IExceptionFilter>(); // Methods public FilterGrouping(IEnumerable<FilterInfo> filters) { foreach (FilterInfo info in filters) { IFilter instance = info.Instance; Categorize<IActionFilter>(instance, this._actionFilters); Categorize<IAuthorizationFilter>(instance, this._authorizationFilters); Categorize<IExceptionFilter>(instance, this._exceptionFilters); } } private static void Categorize<T>(IFilter filter, List<T> list) where T : class { T item = filter as T; if (item != null) { list.Add(item); } } // Properties public IEnumerable<IActionFilter> ActionFilters { get { return this._actionFilters; } } public IEnumerable<IAuthorizationFilter> AuthorizationFilters { get { return this._authorizationFilters; } } public IEnumerable<IExceptionFilter> ExceptionFilters { get { return this._exceptionFilters; } } }
在代碼1-1中我們看到在FilterGrouping類型的構造函數中便會對過濾器信息集合進行分組了,當然了分組的時候是調用FilterGrouping類型中的放吧,在Categorize()方法中就是根據實例的類型來進行判斷的,最后由FilterGrouping類型中的三個公共屬性來表示分組過后的不同類型的過濾器集合。
過濾器執行過程
在上個篇幅中我們通過示例了解到過濾器管道的生成過程以及結果,我們就來看一下執行的過程,順帶再看下過濾器管道的結果是不是如上篇上所說的那樣。
先看服務器端(Selfhost)的代碼:
代碼1-2
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("服務器端服務監聽已開啟"); Console.Read(); } } } }
這里只有一個添加全局行為過濾器的這么一句代碼,其余的部分就不解釋了。
然后我們接着看控制器部分,如下示例代碼:
代碼1-3
namespace NameSpaceControllerThree { [CustomControllerAuthorizationFilter] [CustomControllerActionFilter] public class WriterAndReadController : ApiController { [CustomActionFilter] [CustomControllerActionAuthorizationFilter] public string Get() { StringBuilder strBuilder = new StringBuilder(); HttpActionDescriptor actionDescriptor = this.Configuration.Services.GetActionSelector().SelectAction(this.ControllerContext); System.Collections.ObjectModel.Collection<FilterInfo> filtersInfo = actionDescriptor.GetFilterPipeline(); foreach (var filter in filtersInfo) { strBuilder.AppendLine("【FilterName:"+filter.Instance.GetType().Name+",FilterScope:"+filter.Scope.ToString()+"】"); } return strBuilder.ToString(); } } }
對於上一篇,這里的修改只是在控制器類型和控制器方法上各自新增了一個授權過濾器,下面我們就來看一下過濾器的定義,如下示例代碼:
代碼1-4
/// <summary> /// 全局的行為過濾器 /// </summary> public class CustomConfigurationActionFilterAttribute : FilterAttribute, IActionFilter { public Task<System.Net.Http.HttpResponseMessage> ExecuteActionFilterAsync(System.Web.Http.Controllers.HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken, Func<Task<System.Net.Http.HttpResponseMessage>> continuation) { Console.WriteLine(this.GetType().Name); return continuation(); } } /// <summary> /// 控制器級行為過濾器 /// </summary> public class CustomControllerActionFilterAttribute : FilterAttribute, IActionFilter { public Task<System.Net.Http.HttpResponseMessage> ExecuteActionFilterAsync(System.Web.Http.Controllers.HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken, Func<Task<System.Net.Http.HttpResponseMessage>> continuation) { Console.WriteLine(this.GetType().Name); return continuation(); } } /// <summary> /// 控制器方法級行為過濾器 /// </summary> public class CustomActionFilterAttribute : FilterAttribute, IActionFilter { public Task<System.Net.Http.HttpResponseMessage> ExecuteActionFilterAsync(System.Web.Http.Controllers.HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken, Func<Task<System.Net.Http.HttpResponseMessage>> continuation) { Console.WriteLine(this.GetType().Name); return continuation(); } } /// <summary> /// 控制器級授權訪問過濾器 /// </summary> public class CustomControllerAuthorizationFilterAttribute : FilterAttribute, IAuthorizationFilter { public Task<System.Net.Http.HttpResponseMessage> ExecuteAuthorizationFilterAsync(System.Web.Http.Controllers.HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken, Func<Task<System.Net.Http.HttpResponseMessage>> continuation) { Console.WriteLine(this.GetType().Name); return continuation(); } } /// <summary> /// 控制器方法級授權訪問過濾器 /// </summary> public class CustomControllerActionAuthorizationFilterAttribute : FilterAttribute, IAuthorizationFilter { public Task<System.Net.Http.HttpResponseMessage> ExecuteAuthorizationFilterAsync(System.Web.Http.Controllers.HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken, Func<Task<System.Net.Http.HttpResponseMessage>> continuation) { Console.WriteLine(this.GetType().Name); return continuation(); } }
在代碼1-4中,我們可以看到代碼1-3中所有使用到的過濾器類型和代碼1-2中添加全局過濾器類型。
現在我們看一下最后的結果
圖1
黑色框的結果為SelfHost服務器端過濾器執行過程的輸出,在代碼1-4中我們可以看到,這個得出的一個結論是授權過濾器不管是什么應用范圍的都是優於行為過濾器的,而在同一種類型的過濾器中是根據應用范圍來確定執行順序的,這個跟下面的瀏覽器里的內容有點關系,瀏覽器里顯示的就是所有過濾器在排序后的管道里的樣子,可以看到管道里單純的就是按照應用范圍的級別來排序的,至於這個過濾器是什么類型在處理排序的時候則是一點都不關心的。
過濾器執行過程-代碼分析
首先看一下如下示意圖,可以代表了在控制器執行的過程中過濾器的執行過程。
圖2
上面通過示例來說明了過濾器的執行過程,現在我們來看一下在框架的源碼中是什么樣的,因為在過濾器執行過程中還包含了其它方面的知識點,所以這個是遲早都要看的,下面我們就來看一下吧。
代碼1-5
return InvokeActionWithExceptionFilters(InvokeActionWithAuthorizationFilters(actionContext, cancellationToken, authorizationFilters, () => actionDescriptor.ActionBinding.ExecuteBindingAsync(actionContext, cancellationToken).Then<HttpResponseMessage>(delegate { this._modelState = actionContext.ModelState; return InvokeActionWithActionFilters(actionContext, cancellationToken, actionFilters, () => controllerServices.GetActionInvoker().InvokeActionAsync(actionContext, cancellationToken))(); }, new CancellationToken(), false))(), actionContext, cancellationToken, exceptionFilters);
在代碼1-5中涉及到三個靜態方法,我們先來看一下:
InvokeActionWithExceptionFilters()
InvokeActionWithAuthorizationFilters()
InvokeActionWithActionFilters()
示例代碼如下:
代碼1-6
internal static Task<HttpResponseMessage> InvokeActionWithExceptionFilters(Task<HttpResponseMessage> actionTask, HttpActionContext actionContext, CancellationToken cancellationToken, IEnumerable<IExceptionFilter> filters) { return actionTask.Catch<HttpResponseMessage>(delegate (CatchInfo<HttpResponseMessage> info) { HttpActionExecutedContext executedContext = new HttpActionExecutedContext(actionContext, info.Exception); filters = filters.Reverse<IExceptionFilter>(); IEnumerable<Task> asyncIterator = from filter in filters select filter.ExecuteExceptionFilterAsync(executedContext, cancellationToken); bool runSynchronously = true; Task<HttpResponseMessage> task = TaskHelpers.Iterate(asyncIterator, cancellationToken, true).Then<HttpResponseMessage>(delegate { if (executedContext.Response != null) { return TaskHelpers.FromResult<HttpResponseMessage>(executedContext.Response); } return TaskHelpers.FromError<HttpResponseMessage>(executedContext.Exception); }, new CancellationToken(), runSynchronously); return info.Task(task); }, new CancellationToken()); }
代碼1-7
internal static Func<Task<HttpResponseMessage>> InvokeActionWithAuthorizationFilters(HttpActionContext actionContext, CancellationToken cancellationToken, IEnumerable<IAuthorizationFilter> filters, Func<Task<HttpResponseMessage>> innerAction) { filters = filters.Reverse<IAuthorizationFilter>(); return filters.Aggregate<IAuthorizationFilter, Func<Task<HttpResponseMessage>>>(innerAction, (continuation, filter) => () => filter.ExecuteAuthorizationFilterAsync(actionContext, cancellationToken, continuation)); }
代碼1-8
internal static Func<Task<HttpResponseMessage>> InvokeActionWithActionFilters(HttpActionContext actionContext, CancellationToken cancellationToken, IEnumerable<IActionFilter> filters, Func<Task<HttpResponseMessage>> innerAction) { filters = filters.Reverse<IActionFilter>(); return filters.Aggregate<IActionFilter, Func<Task<HttpResponseMessage>>>(innerAction, (continuation, filter) => () => filter.ExecuteActionFilterAsync(actionContext, cancellationToken, continuation)); }
這里我們先看代碼1-5表示了過濾器執行的所有過程,突然的看起來這1-5代碼的可讀性太低了,可能是跟我水平的關系,我看起來很是吃力也比較煩躁,不過這個爛骨頭也要啃阿,放過去可能就少學會一點東西。
首先我們看到代碼1-5中調用了InvokeActionWithExceptionFilters()方法,也就是代碼1-6,那我們就看看這個InvokeActionWithExceptionFilters()方法,在個InvokeActionWithExceptionFilters()方法中有四個參數,第一個參數是Task<HttpResponseMessage>類型的,這里打住不往下看了,回到代碼1-5中調用個InvokeActionWithExceptionFilters()方法的時候,我們看代碼的最后部分依次往前推,最后發現
代碼1-9
InvokeActionWithAuthorizationFilters(actionContext, cancellationToken, authorizationFilters, () => actionDescriptor.ActionBinding.ExecuteBindingAsync(actionContext, cancellationToken).Then<HttpResponseMessage>(delegate { this._modelState = actionContext.ModelState; return InvokeActionWithActionFilters(actionContext, cancellationToken, actionFilters, () => controllerServices.GetActionInvoker().InvokeActionAsync(actionContext, cancellationToken))(); }, new CancellationToken(), false))(),
發現代碼1-9的部分就是InvokeActionWithExceptionFilters()方法的參數,我們看命名也都知道InvokeActionWithExceptionFilters()方法執行的是異常過濾器的內容,第一個參數類型也說過了是Task<HttpResponseMessage>說明在這之前操作已經處理完成了不管是成功了還是有異常了咱先不管,反正代碼1-9最后生成返回的就是Task<HttpResponseMessage>類型的實例,那我們就來拆開代碼1-9.
從代碼1-9中可以看到首先調用的是代碼1-7的內容也就是調用了InvokeActionWithAuthorizationFilters()方法,我們看一下代碼1-7.
首先代碼1-7中的方法有四個參數(HttpActionContext actionContext, CancellationToken cancellationToken, IEnumerable<IAuthorizationFilter> filters, Func<Task<HttpResponseMessage>> innerAction),第一個控制器方法執行上下文對象,跟HttpControllerContext性質都是一樣的,不說這個,第二個CancellationToken用於並行開發在並行的任務中,可以把這個類型想象成一個鈎子,你可以設置這個鈎子的狀態和行為,在任務中遇到你的鈎子會根據你的鈎子做一些操作可以是繼續任務可以是終止任務額外再執行一些其他操作(不知道理解的對不對沒深入過,有誤的話望大家指正謝謝),至於第三個參數,就是授權過濾器集合類型了,在上面說到的FilterGrouping類型中的AuthorizationFilters屬性就是用在這里,第四個參數就比較重要了,這是一個返回Task<HttpResponseMessage>類型的委托,現在我們把代碼1-9也就是調用了InvokeActionWithAuthorizationFilters()方法的代碼中的第四個參數剝出來,然后再看下面的代碼。
代碼1-10
InvokeActionWithAuthorizationFilters(actionContext, cancellationToken, authorizationFilters, )()
從上面說的也知道現在的代碼1-10的部分只是返回一個Task<HttpResponseMessage>類型的實例作為代碼1-6的第一個參數,按照這樣的思路我們看一下剝離出來的第四個參數。
代碼1-11
() => actionDescriptor.ActionBinding.ExecuteBindingAsync(actionContext, cancellationToken).Then<HttpResponseMessage>(delegate { this._modelState = actionContext.ModelState; return InvokeActionWithActionFilters(actionContext, cancellationToken, actionFilters, () => controllerServices.GetActionInvoker().InvokeActionAsync(actionContext, cancellationToken))(); }, new CancellationToken(), false)
在代碼1-11里主要會先調用actionDescriptor的ActionBinding屬性下的ExecuteBindingAsync()方法,這里的方法就是Model綁定Model驗證所在的地方了這個后面的篇幅會講,有的朋友會發現ExecuteBindingAsync()方法返回的是Task類型,跟上面所說的所需參數的類型是Fun<Task<HttpResponseMessage>>,而這里明顯就是Fun<Task>,是不符合的,而且按照邏輯上說也不符合阿,在授權過濾器執行完畢后應該是行為過濾器的執行阿,這里就涉及到了一個Task的擴展方法調用,就是Then<>()方法了。
代碼1-12
internal static Task<TOuterResult> Then<TOuterResult>(this Task task, Func<Task<TOuterResult>> continuation, CancellationToken cancellationToken = new CancellationToken(), bool runSynchronously = false) { return task.ThenImpl<Task, TOuterResult>(t => continuation(), cancellationToken, runSynchronously); }
用有擴展方法的類型是私有的結構類型,這里就不往下深入了,就在通過這里將Task轉換成Task<HttpResponseMessage>類型的。最后我們在拆一下把這個匿名委托從代碼1-11里面剝出來。
代碼1-13
delegate { this._modelState = actionContext.ModelState; return InvokeActionWithActionFilters(actionContext, cancellationToken, actionFilters, () => controllerServices.GetActionInvoker().InvokeActionAsync(actionContext, cancellationToken))(); }
看到這里有actionContext.ModelState屬性值表示Model驗證的結果值,而這個this._modelState的this就是當前的ApiController,_modelState字段對應的是ApiController類型中的ModelState值,在這之后調用最后的1-8代碼,在上面的1-13中我們可以看到最后是由什么對象去執行最后的操作的,這個一系列的過程后面篇幅會講解到。
在這些所有都執行完畢了之后才會執行到代碼1-6,最后就是形成最后的代碼1-5那樣。
作者:金源
出處:http://www.cnblogs.com/jin-yuan/
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面