ASP.NET Core 2.2 十八.各種Filter的內部處理機制及執行順序


ASP.NET core 的Filter是系統中經常用到的,本文詳細分享一下各種Filter定義、執行的內部機制以及執行順序。(ASP.NET Core 系列目錄

一、 概述

ASP.NET Core MVC 中有好幾種常用的篩選器,例如Authorization filters 、Resource filters、Action filters 、Exception filters 、Result filters,他們運行在請求處理管道中的特定階段,例如Authorization filters當前請求的用戶是否已授權。 如果請求未獲授權,則中止執行后面的請求處理。其他幾種filters也類似,只是執行階段不同。如下圖:

              圖一

Filter從定義到執行,本文通過四個階段說明,如下圖:

                                                          圖二

1.定義:以為例,可以通過繼承ActionFilterAttribute並override它的OnActionExecuting和OnActionExecuted方法實現。

2.注冊:主要有三種方式:在Startup的AddMvc、Controller、Action中注冊。

3.獲取:上一章有介紹,在確定了處理請求的Endpoint后,下一步就是創建創建invoker,它有個關鍵的屬性就是filters,它由FilterFactory的GetAllFilters方法獲取到。

4.執行:invoker的執行階段,會進入InvokeFilterPipelineAsync,在這里,各種Filter按照圖一的方式逐一被執行。

 

二、Filter的定義

Filter有好幾種,但由於本文主要是分享Filter的運行機制,所以只以ActionFilter一種來舉例,現在定義一個Test1Filter如下:

    public class Test1Filter : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            base.OnActionExecuting(context);
            //do.....
        }

        public override void OnActionExecuted(ActionExecutedContext context)
        {
            base.OnActionExecuted(context);
            //do......
        }
    }

很簡單,可以很方便的通過繼承系統提供的ActionFilterAttribute並override 它的相應方法即可。

 

三、Filter的注冊

Filter定義好之后就是將其插入到處理管道中,可以在Startup的AddMvc、Controller、Action中注冊。

1.全局:在Startup的AddMvc中注冊

services.AddMvc(
    options => { options.Filters.Add(new Test6Filter()); options.Filters.Add(new Test4Filter()); }
).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

2.只對指定的Controller生效

[Test5Filter]
[Test3Filter]
public class FlyLoloController : Controller

3.只對指定的Action生效

 [Test2Filter]
 [Test1Filter]
  public JsonResult Index()

在實際業務中,我們可以根據具體的需求來確定Filter的作用范圍。

 

四、Filter的獲取

Filter的獲取是在FilterFactory的GetAllFilters方法中,

        public static FilterFactoryResult GetAllFilters(IFilterProvider[] filterProviders,            ActionContext actionContext)
        {
            //省略……
            var orderedFilters = actionDescriptor.FilterDescriptors.OrderBy(filter => filter,FilterDescriptorOrderComparer.Comparer).ToList();
            //省略....
            return new FilterFactoryResult(staticFilterItems, filters);
        }

 保留了關鍵的一句話,那就是根據actionDescriptor來獲取到它對應的所有Filter(無論是針對全局、Controller還是Action),然后對這些Filter進行排序,這里用到了排序方法FilterDescriptorOrderComparer,它用來定義Filter的執行順序,詳細內容見后文。

 

五、Filter的執行

Filter的執行在invoker的執行階段,會進入InvokeFilterPipelineAsync,在這里,各種Filter按照圖一的方式逐一被執行。具體內容上一章已經進行了詳細的描述。它是通過兩個while循環實現了如圖一的順序逐一執行。

           while (!isCompleted)
            {
                await Next(ref next, ref scope, ref state, ref isCompleted);
            }

具體不再贅述。

 

六、Filter的執行順序

Filter的執行順序由三部分決定:

1.對於不同種的Filter,按照圖一的順序執行,例如Authorization filters會最先被執行。

2.對於同種的Filter,執行順序由其Order和Scope來決定。

在Filter的獲取一節提到了Filter的排序方法FilterDescriptorOrderComparer,它擁有對Filter定的排序。

    

    public class FilterDescriptorOrderComparer : IComparer<FilterDescriptor>
    {
        public static FilterDescriptorOrderComparer Comparer { get; } = new FilterDescriptorOrderComparer();

        public int Compare(FilterDescriptor x, FilterDescriptor y)
        {
            if (x == null)
            {
                throw new ArgumentNullException(nameof(x));
            }

            if (y == null)
            {
                throw new ArgumentNullException(nameof(y));
            }

            if (x.Order == y.Order)
            {
                return x.Scope.CompareTo(y.Scope);
            }
            else
            {
                return x.Order.CompareTo(y.Order);
            }
        }
    }

 

從這個方法可以看到Filter的執行順序,按照先Order后Scope的方式排序。對於繼承默認的內置Filter的,Order默認為0,所有對於這樣的Filter來說覺得他們順序的是Scope,也就是作用域,默認情況下,全局的為10、Controller上的為20、Action上的為30.也就是說,Filter的執行順序為

全局 -> Controller -> Action, 實際的執行順序是這樣的:

全局 OnActionExecuting

     Controller OnActionExecuting

          Action OnActionExecuting

          Action OnActionExecuted

     Controller OnActionExecuted

全局 OnActionExecuted

也是嵌套的,和中間件的處理方式類似。

當然我們可以自定義Filter的Order使其不再采用默認值0,只需在其構造函數中設置即可

    public class Test1Filter : ActionFilterAttribute
    {
        public Test1Filter()
        {
            Order = 1;
        }

        //...........

    }

 

3.對於同樣作用域的同種Filter來說,它們的執行順序是按照注冊先后排列的。

例如:

        [Test2Filter]
        [Test1Filter]
        public JsonResult Index()

則先執行Test2Filter、后執行Test1Filter。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM