ASP.NET Core MVC 過濾器(Filter)
目錄
- 一.過濾器如何工作
- 1.選擇過濾器
- 2.實現過濾器
- 3.過濾器作用域
- 4.取消和短路
- 二.配置過濾器
- 1.依賴注入
- 2.排序
- 3.對比中介軟體
一.過濾器如何工作
不同的過濾器型別在管道中的不同階段執行,因此具有各自的與其場景。根據需要執行的任務以及需要執行的請求管道中的位置,選擇要建立的過濾器型別。過濾器在 MVC 操作呼叫管道中執行,有時也稱為過濾管道,在 MVC 中選擇要執行的操作後,執行操作上的過濾器,如圖:
不同的過濾器在管道內的不同位置執行。像授權過濾器這樣的過濾器只在管道中靠前的位置執行。其他過濾器,如操作(Action)過濾器,可以在管道執行的其他部分之前和之後執行,如圖:
1.選擇過濾器
授權過濾器用於確定當前請求使用者是否被授權。
資源過濾器是在授權之後第一個處理請求的過濾器,也是最後一個在請求離開過濾管道時接觸請求的過濾器。在效能方面,對實現快取或者對過濾管道進行短路 特別有用。
操作過濾器包裝對單個操作方法的呼叫,並且可以處理傳遞到操作的引數以及從操作返回的操作結果。
異常過濾器用於對 MVC 應用程式中未處理的異常應用全域性策略。
結果過濾器包裝單個操作結果的執行,並且盡在操作執行成功時執行。它們必須是圍繞檢視執行或格式化程式執行的邏輯的理想選擇。
2.實現過濾器
所有過濾器均可通過不同的介面定義支援同步和非同步的實現。根據需要執行的任務型別,選擇同步或非同步實現。從框架的角度看,它們是可以互換的。
同步過濾器定義了 OnStageExecuting
和 OnStageExecuted
方法(也有例外)。OnStageExecuting
方法在事件管道階段之前通過階段名稱來呼叫,而 OnStageExecuted
方法將在階段名稱命名的管道階段之後呼叫。
public class SampleActionFilter:IActionFilter { public void OnActionExecuting(ActionExecutingContext context) { //操作執行前做的事情 } public void OnActionExecuted(ActionExecutedContext context) { //操作執行後做的事情 } }
非同步過濾器定義了一個單一的 OnActionExecutionAsync
方法,可以在具體管道階段的前後執行。 OnActionExecutionAsync
方法提供了一個 ActionExecutionDelegate
委託,呼叫時該委託會執行具體管道階段的工作,然後等待完成。
public class SampleAsyncActionFilter: IAsyncActionFilter { public async Task OnActionExecutionAsync(ActionExecutingContext context,ActionExecutionDelegate next) { //操作執行前做的事情 await next(); //操作執行後做的事情 } }
3.過濾器作用域
過濾器有三種不同級別的作用域。你可以在特定的操作上用特性(Attribute
)的方式使用特定的過濾器。也可以在控制器上用特性的方式使用過濾器,這樣就可以將效果作用在控制器內的所有操作上。或者註冊一個全域性過濾器,它將作用於整個 MVC 應用程式的每一個操作。
如果想要使用全域性過濾器,可以在配置 MVC 時,在 Startup
的 ConfigureServices
方法中新增:
services.AddMvc(options => { options.Filters.Add(typeof(SampleActionFilter));//通過型別 options.Filters.Add(new SampleActionFilter());//註冊例項 }).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
過濾器既可以通過型別新增,也可以通過例項新增。如果通過例項新增,則該例項會被使用於每一個請求。如果通過型別新增,則在每次請求後都會建立一個例項,其所有建構函式依賴項都將通過 DI 來填充。
把過濾器介面的實現當作特性使用也非常方便。過濾器特性可應用於控制器和操作方法。框架包含了內建的基於特性的過濾器,可以繼承他們或者另外定製。例如,下面的過濾器繼承了 ResultFilterAttribute
,並重寫 OnResultExecuting
方法(在響應中增加一個資訊頭):
public class AddHeaderAttribute: ResultFilterAttribute { private readonly string _name; private readonly string _value; public AddHeaderAttribute(string name,string value) { _name = name; _value = value; } public override void OnResultExecuting(ResultExecutingContext context) { context.HttpContext.Response.Headers.Add( _name,new string[] { _value }); base.OnResultExecuting(context); } }
特性允許過濾器接受引數,如下,可將此特性新增到控制器或操作中,併為其指定所需 HTTP 頭的名稱和值:
[AddHeader("Author","Ruby Lu")] public class HomeController : Controller { }
以下幾種過濾器介面可以自定義為相應特性的實現:
ActionFilterAttribute
ExceptionFilterAttribute
ResultFilterAttribute
FormatFilterAttribute
ServiceFilterAttribute
TypeFilterAttribute
4.取消和短路
通過設定傳入過濾器方法的上下文引數中的 Result 屬性,可以在過濾器管道的任意一點短路管道。比如,下面的 ShortCircuitingResourceFilter
將阻止它之後管道內的所有過濾器,包括所有操作過濾器:
public class ShortCircuitingResourceFilter:Attribute,IResourceFilter { public void OnResourceExecuting(ResourceExecutingContext context) { context.Result = new ContentResult() { Content = "短路" }; } public void OnResourceExecuted(ResourceExecutedContext context) { } }
二.配置過濾器
全域性過濾器在 Startup
中配置。基於特性的過濾器如果不需要任何依賴,可以簡單地繼承一個已存在地過濾器相對應地特性類型。如果要建立一個非全域性作用域,但需要從依賴注入中獲得依賴項的過濾器,那麼在它們上面加上 ServiceFilterAttrveFfIXwibute
或 TypeFilterAttribute
特性,這樣就可用於控制器或操作了。
1.依賴注入
以特性形式實現的,直接新增到控制器或操作的過濾器,其建構函式不得由依賴注入提供依賴項。其原因在於,特性所需的建構函式引數必須由使用處直接提供。這是特性原型機理的限制。
如果過濾器需要從 DI 中獲得依賴項,那麼可以用以下幾種方法在類或操作方法使用:
ServiceFilterAttribute
TypeFilterAttribute
IFilterFactory
實現特性
TypeFilter
將為其依賴項從 DI 中使用服務來例項化一個例項。 ServiceFilter 則從 DI 中獲取一個過濾器例項。下面演示 ServiceFilter
:
先在 ConfigureServices
中註冊 AddHeaderFilterWithDI
型別:services.AddScoped<AddHeaderFilterWithDI>();
然後使用:
[ServiceFilter(typeof(AddHeaderFilterWithDI))] public IActionResult Index() { }
ServiceFilterAttribute
實現了IFilterFactory
介面,它公開了一個建立 IFilter 例項的方法。在 ServiceFilterAttribute
中,IFilterFactory
介面的 CreateInstance
方法被實現為從服務容器載入指定的型別。
TypeFilterAttribute
非常類似 ServiceFilterAttribute
(也實現 IFilterFactory 介面),但它的型別不是直接從 DI 容器中解析,相反,它使用 Microsoft.Extensions.DependencyInjection.ObjectFactory
例項化型別。
由於這種差異,使用 TypeFilterAttribute
引用的型別不需要在使用前向容器註冊,但它們仍由容器來填充其依賴項。此外,TypeFilterAttribute 可以可選的接受該型別的建構函式引數。下面是 TypeFilterAttribute
演示:
[TypeFilter(typeof(AddHeaderAttribute),Arguments =new object[] { "Author","Ruby" })] public IActionResult Index() { return View(); }
如果有一個簡單的過濾器,不需要任何引數,但有建構函式需要通過 DI 填充依賴項,那麼可以繼承 TypeFilterAttribute,
允許使用自己命名的特性類和方法(而不是 [TypeFilterAttribute(typeof(FilterType
))])。下面的過濾器顯示瞭如何實現此功能:
public class SampleActionFilterAttribute:TypeFilterAttribute http://www.cppcns.com { public SampleActionFilterAttribute() : base(typeof(SampleActionFilterImpl)) { } private class SampleActionFilterImpl:IActionFilter { public void OnActionExecuting(ActionExecutingContext context) { //操作執行前做的事情 } public void OnActionExecuted(ActionExecutedContext context) { //操作執行後做的事情 } } }
該過濾器可通過使用 [SampleActionFilter
] 這樣的語法應用於類或方法,而不必使用 [TypeFilter
] 或 [ServiceFilter
] 。
IFilterFactory
實現 IFilter
,因此在過濾器管道中,任何位置的 IFilterFactory
例項都可當作 Filter 例項來使用。當框架準備呼叫過濾器時,將嘗試將其轉換為 IFilterFactory
。如果轉換成功, 則呼叫 CreateInstance
方法來建立將被呼叫的 IFilter 例項。這是一種非常靈活的設計,因為當應用程式啟動時,不需要明確地設定精確地過濾器。
你可以在自己地特性中實現 IFilterFactory
幾口,作為另一種建立過濾器的方法:
public class AddHeadWithFactoryAttribute:Attribute,IFilterFactory { public bool IsReusable { get; } //實現IFilterFactory public IFilterMetadata CreateInstance(IServiceProvider serviceProvider) { return new InternalAddHeaderFilter(); } } public class InternalAddHeaderFilter : IResultFilter { public void OnResultExecuting(ResultExecutingContext context) { context.HttpContext.Response.Headers.Add( "Internal",new string[] { "Header Add" }); } public void OnResultExecuted(ResultExecutedContext context) { } }
2.排序
veFfIXw過濾器可以應用於操作方法或控制器(通過特性)或新增到全域性過濾器集合中。作用域通常也決定了排序,最接近操作的過濾器首先執行。
除了作用域,過濾器還可以通過實現 IOrderedFilter
來重寫它們的執行順序。此介面簡單的暴露了一個 int Order 屬性,並且過濾器基於該屬性以數字升序執行。所有內建的過濾器,包括 TypeFilterAttribute
和 ServiceFilterAttribute
,都實現 IOrderedFilter
介面。,因此當將過濾器特性應用於類或方法時,可以指定過濾器執行順序。預設情況下,所有內建過濾器的 Order 屬性都為0,因此範圍用作分隔符,並且是決定性因素(除非 Order 設定為 0)。
每個從 Controller
基類繼承的控制器都包含 OnActionExecuting
和 OnActionExecuted
方法。這些方法為給定操作包裝了過濾器,它們分別最先執行和最後執行。假設沒有為任何過濾器設定 Order 舒總,那麼單純基於範圍的順序為:
- 控制器的
OnActionExecuting
- 全域性過濾器的
OnActionExecuting
- 類過濾器的
OnActionExecuting
- 方法過濾器的
OnActionExecuting
- 方法過濾器的
OnActionExecuted
- 類過濾器的
OnActionExecuted
- 全域性過濾器的
OnActionExecuted
- 控制器過濾器的
OnActionExecuted
要修改預設的基於範圍的順序,則應顯示設定類級別或者方法級別過濾器的 Order
屬性。例如,將 Order = -1
新增到方法級屬性:
[MyFilter (Name = "...",Order = -1)]
在這種情況下,小於零的值將確保此過濾器在全域性和類級過濾器之前執行:
- 控制器的
OnActionExecuting
- 方法過濾器的
OnActionExecuting
- 全域性過濾器的
OnActionExecuting
- 類過濾器的
OnActionExecuting
- 類過濾器的
OnActionExecuted
- 全域性過濾器的
OnActionExecuted
- 控制器過濾器的
OnActionExecuted
- 方法過濾器的
OnActionExecuted
Controller
類的方法總是在所有過濾器之前和之後執行。這些方法不作為IFilter
例項實現。也不參與IFilter排序演算法。
3.對比中介軟體
一般來說,過濾器用於處理業務與應用程式的橫切關注點,用法和功能很像中介軟體,但過濾器允許你將作用範圍縮小,並將其插入到應用程式中有意義的位置,例如檢視之前或模型繫結之後。過濾器是 MVC 的一部分,可以訪問其上下文和建構函式。例如,中介軟體很難檢測到請求的模型驗證是否產生錯誤,並且做出相應的響應。
到此這篇關於ASP.NET Core MVC
過濾器(Filter)的文章就介紹到這了,更多相關ASP.NET Core
MVC 過濾器內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!