天天看點

ASP.NET Web API 過濾器建立、執行過程(二)ASP.NET Web API 過濾器建立、執行過程(二)

前言

前面一篇中講解了過濾器執行之前的建立,通過實作IFilterProvider注冊到目前的HttpConfiguration裡的服務容器中,當然預設的基礎服務也是有的,并且根據這些提供程式所獲得的的過濾器資訊集合進行排序。本篇就會對過濾器在建立完之後所做的一系列操作進行講解。

ASP.NETWeb API 過濾器建立、執行過程(二)

FilterGrouping過濾器分組類型

FilterGrouping類型是ApiController類型中的私有類型,它的作用就如同它的命名一樣,用來對過濾器集合進行分組,在上一篇中我們看到,在經過調用HttpActionDescriptor類型的GetFilterPipeline()方法之後回去擷取到排序過後的過濾器資訊集合Collection<FilterInfo>。下面我們看一下FilterGrouping類型定義:

示例代碼1-1

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

<code>   </code><code>privateclassFilterGrouping</code>

<code>   </code><code>{</code>

<code>        </code><code>//Fields</code>

<code>        </code><code>privateList&lt;IActionFilter&gt;_actionFilters=newList&lt;IActionFilter&gt;();</code>

<code>        </code><code>privateList&lt;IAuthorizationFilter&gt;_authorizationFilters=newList&lt;IAuthorizationFilter&gt;();</code>

<code>        </code><code>privateList&lt;IExceptionFilter&gt;_exceptionFilters=newList&lt;IExceptionFilter&gt;();</code>

<code> </code> 

<code>        </code><code>//Methods</code>

<code>        </code><code>publicFilterGrouping(IEnumerable&lt;FilterInfo&gt;filters)</code>

<code>        </code><code>{</code>

<code>            </code><code>foreach</code> <code>(FilterInfoinfoinfilters)</code>

<code>            </code><code>{</code>

<code>                </code><code>IFilterinstance=info.Instance;</code>

<code>                </code><code>Categorize&lt;IActionFilter&gt;(instance, </code><code>this</code><code>._actionFilters);</code>

<code>                </code><code>Categorize&lt;IAuthorizationFilter&gt;(instance, </code><code>this</code><code>._authorizationFilters);</code>

<code>                </code><code>Categorize&lt;IExceptionFilter&gt;(instance, </code><code>this</code><code>._exceptionFilters);</code>

<code>            </code><code>}</code>

<code>        </code><code>}</code>

<code>        </code><code>privatestaticvoidCategorize&lt;T&gt;(IFilterfilter, List&lt;T&gt;list) </code><code>where</code> <code>T : </code><code>class</code>

<code>            </code><code>T item=filteras T;</code>

<code>            </code><code>if</code> <code>(item!=</code><code>null</code><code>)</code>

<code>                </code><code>list.Add(item);</code>

<code>        </code><code>//Properties</code>

<code>        </code><code>publicIEnumerable&lt;IActionFilter&gt;ActionFilters</code>

<code>            </code><code>get</code>

<code>                </code><code>returnthis._actionFilters;</code>

<code>        </code><code>publicIEnumerable&lt;IAuthorizationFilter&gt;AuthorizationFilters</code>

<code>                </code><code>returnthis._authorizationFilters;</code>

<code>        </code><code>publicIEnumerable&lt;IExceptionFilter&gt;ExceptionFilters</code>

<code>                </code><code>returnthis._exceptionFilters;</code>

<code>}</code>

在代碼1-1中我們看到在FilterGrouping類型的構造函數中便會對過濾器資訊集合進行分組了,當然了分組的時候是調用FilterGrouping類型中的放吧,在Categorize()方法中就是根據執行個體的類型來進行判斷的,最後由FilterGrouping類型中的三個公共屬性來表示分組過後的不同類型的過濾器集合。

過濾器執行過程

在上個篇幅中我們通過示例了解到過濾器管道的生成過程以及結果,我們就來看一下執行的過程,順帶再看下過濾器管道的結果是不是如上篇上所說的那樣。

先看伺服器端(Selfhost)的代碼:

代碼1-2

<code>usingSystem.Web.Http.Controllers;</code>

<code>usingSystem.Web.Http.Filters;</code>

<code>usingNameSpaceControllerThree;</code>

<code>namespaceSelfHost</code>

<code>{</code>

<code>   </code><code>classProgram</code>

<code>        </code><code>staticvoidMain(</code><code>string</code><code>[] args)</code>

<code>           </code> 

<code>            </code><code>HttpSelfHostConfigurationselfHostConfiguration=</code>

<code>                </code><code>newHttpSelfHostConfiguration(</code><code>"http://localhost/selfhost"</code><code>);</code>

<code>            </code><code>using</code> <code>(HttpSelfHostServerselfHostServer=newHttpSelfHostServer(selfHostConfiguration))</code>

<code>                </code><code>selfHostServer.Configuration.Routes.MapHttpRoute(</code>

<code>                    </code><code>"DefaultApi"</code><code>, </code><code>"api/{controller}/{id}"</code><code>, </code><code>new</code> <code>{ id=RouteParameter.Optional });</code>

<code>                </code><code>selfHostServer.Configuration.Services.Replace(</code><code>typeof</code><code>(IAssembliesResolver),</code>

<code>                    </code><code>newCustomAssembliesResolver.LoadSpecifiedAssembliesResolver());</code>

<code>                </code><code>//添加全局過濾器</code>

<code>                </code><code>selfHostServer.Configuration.Filters.Add(newWebAPIController.Filter.CustomConfigurationActionFilterAttribute());</code>

<code>                </code><code>selfHostServer.OpenAsync();</code>

<code>                </code><code>Console.WriteLine(</code><code>"伺服器端服務監聽已開啟"</code><code>);</code>

<code>                </code><code>Console.Read();</code>

<code>   </code><code>}</code>

這裡隻有一個添加全局行為過濾器的這麼一句代碼,其餘的部分就不解釋了。

然後我們接着看控制器部分,如下示例代碼:

代碼1-3

<code>namespaceNameSpaceControllerThree</code>

<code>   </code><code>[CustomControllerAuthorizationFilter]</code>

<code>   </code><code>[CustomControllerActionFilter]</code>

<code>   </code><code>publicclassWriterAndReadController : ApiController</code>

<code>        </code><code>[CustomActionFilter]</code>

<code>        </code><code>[CustomControllerActionAuthorizationFilter]</code>

<code>        </code><code>publicstringGet()</code>

<code>            </code><code>StringBuilderstrBuilder=newStringBuilder();</code>

<code>            </code><code>HttpActionDescriptoractionDescriptor=</code><code>this</code><code>.Configuration.Services.GetActionSelector().SelectAction(</code><code>this</code><code>.ControllerContext);</code>

<code>            </code><code>System.Collections.ObjectModel.Collection&lt;FilterInfo&gt;filtersInfo=actionDescriptor.GetFilterPipeline();</code>

<code>            </code><code>foreach</code> <code>(varfilterinfiltersInfo)</code>

<code>                </code><code>strBuilder.AppendLine(</code><code>"【FilterName:"</code><code>+filter.Instance.GetType().Name+</code><code>",FilterScope:"</code><code>+filter.Scope.ToString()+</code><code>"】"</code><code>);</code>

<code>            </code><code>returnstrBuilder.ToString();</code>

對于上一篇,這裡的修改隻是在控制器類型和控制器方法上各自新增了一個授權過濾器,下面我們就來看一下過濾器的定義,如下示例代碼:

代碼1-4

54

55

56

57

58

59

60

61

62

63

64

<code>/// &lt;summary&gt;</code>

<code>   </code><code>/// 全局的行為過濾器</code>

<code>   </code><code>/// &lt;/summary&gt;</code>

<code>   </code><code>publicclassCustomConfigurationActionFilterAttribute : FilterAttribute, IActionFilter</code>

<code>        </code><code>publicTask&lt;System.Net.Http.HttpResponseMessage&gt;ExecuteActionFilterAsync(System.Web.Http.Controllers.HttpActionContextactionContext, System.Threading.CancellationTokencancellationToken, Func&lt;Task&lt;System.Net.Http.HttpResponseMessage&gt;&gt;continuation)</code>

<code>            </code><code>Console.WriteLine(</code><code>this</code><code>.GetType().Name);</code>

<code>            </code><code>returncontinuation();</code>

<code>   </code><code>/// &lt;summary&gt;</code>

<code>   </code><code>/// 控制器級行為過濾器</code>

<code>   </code><code>publicclassCustomControllerActionFilterAttribute : FilterAttribute, IActionFilter</code>

<code>   </code><code>/// 控制器方法級行為過濾器</code>

<code>   </code><code>publicclassCustomActionFilterAttribute : FilterAttribute, IActionFilter</code>

<code>   </code><code>/// 控制器級授權通路過濾器</code>

<code>   </code><code>publicclassCustomControllerAuthorizationFilterAttribute : FilterAttribute, IAuthorizationFilter</code>

<code>        </code><code>publicTask&lt;System.Net.Http.HttpResponseMessage&gt;ExecuteAuthorizationFilterAsync(System.Web.Http.Controllers.HttpActionContextactionContext, System.Threading.CancellationTokencancellationToken, Func&lt;Task&lt;System.Net.Http.HttpResponseMessage&gt;&gt;continuation)</code>

<code>   </code><code>/// 控制器方法級授權通路過濾器</code>

<code>   </code><code>publicclassCustomControllerActionAuthorizationFilterAttribute : FilterAttribute, IAuthorizationFilter</code>

在代碼1-4中,我們可以看到代碼1-3中所有使用到的過濾器類型和代碼1-2中添加全局過濾器類型。

現在我們看一下最後的結果

圖1

<a href="http://s3.51cto.com/wyfs02/M00/49/94/wKioL1QVgHvwFFXaAANvgLXZvmM195.jpg" target="_blank"></a>

黑色框的結果為SelfHost伺服器端過濾器執行過程的輸出,在代碼1-4中我們可以看到,這個得出的一個結論是授權過濾器不管是什麼應用範圍的都是優于行為過濾器的,而在同一種類型的過濾器中是根據應用範圍來确定執行順序的,這個跟下面的浏覽器裡的内容有點關系,浏覽器裡顯示的就是所有過濾器在排序後的管道裡的樣子,可以看到管道裡單純的就是按照應用範圍的級别來排序的,至于這個過濾器是什麼類型在處理排序的時候則是一點都不關心的。

過濾器執行過程-代碼分析

首先看一下如下示意圖,可以代表了在控制器執行的過程中過濾器的執行過程。

圖2

<a href="http://s3.51cto.com/wyfs02/M02/49/94/wKioL1QVgJaycworAALwTSFI6Pw560.jpg" target="_blank"></a>

上面通過示例來說明了過濾器的執行過程,現在我們來看一下在架構的源碼中是什麼樣的,因為在過濾器執行過程中還包含了其它方面的知識點,是以這個是遲早都要看的,下面我們就來看一下吧。

代碼1-5

<code>    </code><code>returnInvokeActionWithExceptionFilters(InvokeActionWithAuthorizationFilters(actionContext, cancellationToken, authorizationFilters, ()=&gt;actionDescriptor.ActionBinding.ExecuteBindingAsync(actionContext, cancellationToken).Then&lt;HttpResponseMessage&gt;(</code><code>delegate</code> <code>{</code>

<code>            </code><code>this</code><code>._modelState=actionContext.ModelState;</code>

<code>            </code><code>returnInvokeActionWithActionFilters(actionContext, cancellationToken, actionFilters, () =&gt;controllerServices.GetActionInvoker().InvokeActionAsync(actionContext, cancellationToken))();</code>

<code>        </code><code>}, newCancellationToken(), </code><code>false</code><code>))(), actionContext, cancellationToken, exceptionFilters);</code>

在代碼1-5中涉及到三個靜态方法,我們先來看一下:

InvokeActionWithExceptionFilters()

InvokeActionWithAuthorizationFilters()

InvokeActionWithActionFilters()

示例代碼如下:

代碼1-6

<code>   </code><code>internalstaticTask&lt;HttpResponseMessage&gt;InvokeActionWithExceptionFilters(Task&lt;HttpResponseMessage&gt;actionTask, HttpActionContextactionContext, CancellationTokencancellationToken, IEnumerable&lt;IExceptionFilter&gt;filters)</code>

<code>        </code><code>returnactionTask.Catch&lt;HttpResponseMessage&gt;(</code><code>delegate</code> <code>(CatchInfo&lt;HttpResponseMessage&gt;info) {</code>

<code>            </code><code>HttpActionExecutedContextexecutedContext=newHttpActionExecutedContext(actionContext, info.Exception);</code>

<code>            </code><code>filters=filters.Reverse&lt;IExceptionFilter&gt;();</code>

<code>            </code><code>IEnumerable&lt;Task&gt;asyncIterator=fromfilterinfiltersselectfilter.ExecuteExceptionFilterAsync(executedContext, cancellationToken);</code>

<code>            </code><code>boolrunSynchronously=</code><code>true</code><code>;</code>

<code>            </code><code>Task&lt;HttpResponseMessage&gt;task=TaskHelpers.Iterate(asyncIterator, cancellationToken, </code><code>true</code><code>).Then&lt;HttpResponseMessage&gt;(</code><code>delegate</code> <code>{</code>

<code>                </code><code>if</code> <code>(executedContext.Response!=</code><code>null</code><code>)</code>

<code>                </code><code>{</code>

<code>                    </code><code>returnTaskHelpers.FromResult&lt;HttpResponseMessage&gt;(executedContext.Response);</code>

<code>                </code><code>}</code>

<code>                </code><code>returnTaskHelpers.FromError&lt;HttpResponseMessage&gt;(executedContext.Exception);</code>

<code>            </code><code>}, newCancellationToken(), runSynchronously);</code>

<code>            </code><code>returninfo.Task(task);</code>

<code>        </code><code>}, newCancellationToken());</code>

代碼1-7

<code>   </code><code>internalstaticFunc&lt;Task&lt;HttpResponseMessage&gt;&gt;InvokeActionWithAuthorizationFilters(HttpActionContextactionContext, CancellationTokencancellationToken, IEnumerable&lt;IAuthorizationFilter&gt;filters, Func&lt;Task&lt;HttpResponseMessage&gt;&gt;innerAction)</code>

<code>        </code><code>filters=filters.Reverse&lt;IAuthorizationFilter&gt;();</code>

<code>        </code><code>returnfilters.Aggregate&lt;IAuthorizationFilter, Func&lt;Task&lt;HttpResponseMessage&gt;&gt;&gt;(innerAction, (continuation, filter) =&gt; () =&gt;filter.ExecuteAuthorizationFilterAsync(actionContext, cancellationToken, continuation));</code>

代碼1-8

<code>   </code><code>internalstaticFunc&lt;Task&lt;HttpResponseMessage&gt;&gt;InvokeActionWithActionFilters(HttpActionContextactionContext, CancellationTokencancellationToken, IEnumerable&lt;IActionFilter&gt;filters, Func&lt;Task&lt;HttpResponseMessage&gt;&gt;innerAction)</code>

<code>        </code><code>filters=filters.Reverse&lt;IActionFilter&gt;();</code>

<code>        </code><code>returnfilters.Aggregate&lt;IActionFilter, Func&lt;Task&lt;HttpResponseMessage&gt;&gt;&gt;(innerAction, (continuation, filter) =&gt; () =&gt;filter.ExecuteActionFilterAsync(actionContext, cancellationToken, continuation));</code>

這裡我們先看代碼1-5表示了過濾器執行的所有過程,突然的看起來這1-5代碼的可讀性太低了,可能是跟我水準的關系,我看起來很是吃力也比較煩躁,不過這個爛骨頭也要啃阿,放過去可能就少學會一點東西。

首先我們看到代碼1-5中調用了InvokeActionWithExceptionFilters()方法,也就是代碼1-6,那我們就看看這個InvokeActionWithExceptionFilters()方法,在個InvokeActionWithExceptionFilters()方法中有四個參數,第一個參數是Task&lt;HttpResponseMessage&gt;類型的,這裡打住不往下看了,回到代碼1-5中調用個InvokeActionWithExceptionFilters()方法的時候,我們看代碼的最後部分依次往前推,最後發現

代碼1-9

<code>InvokeActionWithAuthorizationFilters(actionContext, cancellationToken, authorizationFilters, ()=&gt;actionDescriptor.ActionBinding.ExecuteBindingAsync(actionContext, cancellationToken).Then&lt;HttpResponseMessage&gt;(</code><code>delegate</code> <code>{</code>

<code>        </code><code>}, newCancellationToken(), </code><code>false</code><code>))(),</code>

發現代碼1-9的部分就是InvokeActionWithExceptionFilters()方法的參數,我們看命名也都知道InvokeActionWithExceptionFilters()方法執行的是異常過濾器的内容,第一個參數類型也說過了是Task&lt;HttpResponseMessage&gt;說明在這之前操作已經處理完成了不管是成功了還是有異常了咱先不管,反正代碼1-9最後生成傳回的就是Task&lt;HttpResponseMessage&gt;類型的執行個體,那我們就來拆開代碼1-9.

從代碼1-9中可以看到首先調用的是代碼1-7的内容也就是調用了InvokeActionWithAuthorizationFilters()方法,我們看一下代碼1-7.

首先代碼1-7中的方法有四個參數(HttpActionContext actionContext,CancellationToken cancellationToken, IEnumerable&lt;IAuthorizationFilter&gt;filters, Func&lt;Task&lt;HttpResponseMessage&gt;&gt; innerAction),第一個控制器方法執行上下文對象,跟HttpControllerContext性質都是一樣的,不說這個,第二個CancellationToken用于并行開發在并行的任務中,可以把這個類型想象成一個鈎子,你可以設定這個鈎子的狀态和行為,在任務中遇到你的鈎子會根據你的鈎子做一些操作可以是繼續任務可以是終止任務額外再執行一些其他操作(不知道了解的對不對沒深入過,有誤的話望大家指正謝謝),至于第三個參數,就是授權過濾器集合類型了,在上面說到的FilterGrouping類型中的AuthorizationFilters屬性就是用在這裡,第四個參數就比較重要了,這是一個傳回Task&lt;HttpResponseMessage&gt;類型的委托,現在我們把代碼1-9也就是調用了InvokeActionWithAuthorizationFilters()方法的代碼中的第四個參數剝出來,然後再看下面的代碼。

代碼1-10

<code>InvokeActionWithAuthorizationFilters</code>

<code>(</code>

<code>actionContext, </code>

<code>cancellationToken, </code>

<code>authorizationFilters,)()</code>

從上面說的也知道現在的代碼1-10的部分隻是傳回一個Task&lt;HttpResponseMessage&gt;類型的執行個體作為代碼1-6的第一個參數,按照這樣的思路我們看一下剝離出來的第四個參數。

代碼1-11

<code>() =&gt;actionDescriptor.ActionBinding.ExecuteBindingAsync(actionContext, cancellationToken).Then&lt;HttpResponseMessage&gt;(</code><code>delegate</code> <code>{</code>

<code>        </code><code>}, newCancellationToken(), </code><code>false</code><code>)</code>

在代碼1-11裡主要會先調用actionDescriptor的ActionBinding屬性下的ExecuteBindingAsync()方法,這裡的方法就是Model綁定Model驗證所在的地方了這個後面的篇幅會講,有的朋友會發現ExecuteBindingAsync()方法傳回的是Task類型,跟上面所說的所需參數的類型是Fun&lt;Task&lt;HttpResponseMessage&gt;&gt;,而這裡明顯就是Fun&lt;Task&gt;,是不符合的,而且按照邏輯上說也不符合阿,在授權過濾器執行完畢後應該是行為過濾器的執行阿,這裡就涉及到了一個Task的擴充方法調用,就是Then&lt;&gt;()方法了。

代碼1-12

<code>internalstaticTask&lt;TOuterResult&gt;Then&lt;TOuterResult&gt;(thisTasktask, Func&lt;Task&lt;TOuterResult&gt;&gt;continuation, CancellationTokencancellationToken=newCancellationToken(), boolrunSynchronously=</code><code>false</code><code>)</code>

<code>   </code><code>returntask.ThenImpl&lt;Task, TOuterResult&gt;(t=&gt;continuation(), cancellationToken, runSynchronously);</code>

用有擴充方法的類型是私有的結構類型,這裡就不往下深入了,就在通過這裡将Task轉換成Task&lt;HttpResponseMessage&gt;類型的。最後我們在拆一下把這個匿名委托從代碼1-11裡面剝出來。

代碼1-13

<code>delegate</code> <code>{</code>

看到這裡有actionContext.ModelState屬性值表示Model驗證的結果值,而這個this._modelState的this就是目前的ApiController,_modelState字段對應的是ApiController類型中的ModelState值,在這之後調用最後的1-8代碼,在上面的1-13中我們可以看到最後是由什麼對象去執行最後的操作的,這個一系列的過程後面篇幅會講解到。

在這些所有都執行完畢了之後才會執行到代碼1-6,最後就是形成最後的代碼1-5那樣。

     本文轉自jinyuan0829 51CTO部落格,原文連結http://blog.51cto.com/jinyuan/1552724:,如需轉載請自行聯系原作者

繼續閱讀