ASP.NET core 的Filter是系統中經常用到的,本文詳細分享一下各種Filter定義、執行的內部機制以及執行順序。 一、 概述 ASP.NET Core MVC 中有好幾種常用的篩選器,例如Authorization filters 、Resource filters、Action fi ...
ASP.NET core 的Filter是系統中經常用到的,本文詳細分享一下各種Filter定義、執行的內部機制以及執行順序。
一、 概述
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。