隨著技術的發展,ASP.NET Core MVC也推出了好長時間,經過不斷的版本更新迭代,已經越來越完善,本系列文章主要講解ASP.NET Core MVC開發B/S系統過程中所涉及到的相關內容,適用于初學者,在校畢業生,或其他想從事ASP.NET Core MVC 系統開發的人員。
經過前幾篇文章的講解,初步了解ASP.NET Core MVC項目創建,啟動運行,以及命名約定,創建控制器,視圖,模型,接收參數,傳遞數據ViewData,ViewBag,路由,頁面布局,wwwroot和客戶端庫,Razor語法,EnityFrameworkCore與數據庫,HttpContext,Request,Response,Session,序列化,文件上傳,自動映射,Html輔助標簽,模型校驗,鑒權、授權基礎,Identity入門,日志管理等內容,今天繼續講解ASP.NET Core MVC 中Filter(篩選器)等相關內容,僅供學習分享使用。
(資料圖)
什么是Filter?
Filter又稱為篩選器,過濾器。在ASP.NET Core MVC項目中,通過使用Filter,可以在請求處理管道的特定位置之前或之后運行代碼。可以創建自定義Filter,用于處理橫切關注點,類似于AOP面向切面編程。對于創建Filter,可以減少代碼的復制,例如,錯誤處理異常篩選器可以合并錯誤處理。
Filter工作原理
從請求開始,到請求結束,經過一系列的節點,組成了調用管道。Filter在ASP.NET Core MVC的調用管道內運行,過濾器相當于在管道中設置的幾個鉤子,用于執行特定的代碼。
Filter類型
根據不同的處理功能,篩選器主要分為以下幾類:
授權篩選器AuthorizationFilter:
- 首先運行。
- 確定用戶是否獲得請求授權。
- 如果請求未獲授權,可以讓管道短路。
資源篩選器Resource Filter:
- 授權后運行。
- OnResourceExecuting在篩選器管道的其余階段之前運行代碼。 例如,
OnResourceExecuting
在模型綁定之前運行代碼。 - OnResourceExecuted在管道的其余階段完成之后運行代碼。
操作篩選器Action Filter:
- 在調用操作方法之前和之后立即運行。
- 可以更改傳遞到操作中的參數。
- 可以更改從操作返回的結果。
- 不可在 Razor Pages 中使用。
異常篩選器Exception Filter:在向響應正文寫入任何內容之前,對未經處理的異常應用全局策略。
結果篩選器Result Filter:
- 在執行操作結果之前和之后立即運行。
- 僅當操作方法成功執行時才會運行。
- 對于必須圍繞視圖或格式化程序的執行的邏輯,會很有用。
下圖展示了Filter篩選器類型在篩選器管道中的交互方式:
Filter實現
所有的Filter都實現接口IFilterMetadata,根據不同的業務類型,派生出了五個接口,分別對應五大類Filter,如下所示:
注意:上述五個接口還有對應異步接口(Async)。
Filter作用域
Filter可以作用在Controller,Action,全局。下面的示例闡釋了為同步操作篩選器運行篩選器方法的順序:
授權Filter
授權篩選器:
- 是篩選器管道中運行的第一個篩選器。
- 控制對操作方法的訪問。
- 具有在它之前的執行的方法,但沒有之后執行的方法。
如常用的RequireHttps就是授權篩選器,它實現了IAuthorizationFilter接口,并繼承了Attirbute,所以可以作用于Controller或Action中。以限制請求的方式。
1 using Microsoft.AspNetCore.Mvc.Filters; 2 using System; 3 4 namespace Microsoft.AspNetCore.Mvc 5 { 6 // 7 // 摘要: 8 // An authorization filter that confirms requests are received over HTTPS. 9 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]10 public class RequireHttpsAttribute : Attribute, IAuthorizationFilter, IFilterMetadata, IOrderedFilter11 {12 public RequireHttpsAttribute();13 14 //15 // 摘要:16 // Specifies whether a permanent redirect, 301 Moved Permanently, should be used17 // instead of a temporary redirect, 302 Found.18 public bool Permanent { get; set; }19 //20 // 值:21 // Default is int.MinValue + 50 to run this Microsoft.AspNetCore.Mvc.Filters.IAuthorizationFilter22 // early.23 public int Order { get; set; }24 25 //26 // 摘要:27 // Called early in the filter pipeline to confirm request is authorized. Confirms28 // requests are received over HTTPS. Takes no action for HTTPS requests. Otherwise29 // if it was a GET request, sets Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext.Result30 // to a result which will redirect the client to the HTTPS version of the request31 // URI. Otherwise, sets Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext.Result32 // to a result which will set the status code to 403 (Forbidden).33 public virtual void OnAuthorization(AuthorizationFilterContext filterContext);34 //35 // 摘要:36 // Called from Microsoft.AspNetCore.Mvc.RequireHttpsAttribute.OnAuthorization(Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext)37 // if the request is not received over HTTPS. Expectation is Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext.Result38 // will not be null after this method returns.39 //40 // 參數:41 // filterContext:42 // The Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext to update.43 //44 // 言論:45 // If it was a GET request, default implementation sets Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext.Result46 // to a result which will redirect the client to the HTTPS version of the request47 // URI. Otherwise, default implementation sets Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext.Result48 // to a result which will set the status code to 403 (Forbidden).49 protected virtual void HandleNonHttpsRequest(AuthorizationFilterContext filterContext);50 }51 }
資源Filter
資源Filter在授權Filter之后執行,需要實現IResourceFilter接口。如下所示:
1 using Microsoft.AspNetCore.Mvc.Filters; 2 3 namespace DemoCoreMVC.Filter 4 { 5 ///6 /// 同步版本 7 /// 8 public class LogResourceFilter :Attribute, IResourceFilter 9 {10 public void OnResourceExecuted(ResourceExecutedContext context)11 {12 //Action執行完成后執行13 Console.WriteLine("********************On Resource Filter Executed********************");14 }15 16 public void OnResourceExecuting(ResourceExecutingContext context)17 {18 //授權Filter執行后執行。19 Console.WriteLine("********************On Resource Filter Executing********************");20 }21 }22 23 ///24 /// 異步版本25 /// 26 public class AsynLogResouceFilter : Attribute, IAsyncResourceFilter27 {28 public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next)29 {30 Console.WriteLine("********************On Aysnc Resource Filter Executing********************");31 var exceutedContext = await next();32 Console.WriteLine("********************On Async Resource Filter Executed********************");33 }34 }35 }
如果要使大部分管道短路,資源篩選器會很有用。 例如,如果緩存命中,則緩存篩選器可以繞開管道的其余階段。
操作Filter
操作篩選器不應用于 Razor Pages。 Razor Pages 支持IPageFilter和IAsyncPageFilter。
操作篩選器:
- 實現IActionFilter或IAsyncActionFilter接口。
- 它們的執行圍繞著操作方法的執行。
以下代碼顯示示例操作篩選器:
1 using Microsoft.AspNetCore.Mvc.Filters; 2 3 namespace DemoCoreMVC.Filter 4 { 5 public class DoDoActionFilter : Attribute, IActionFilter 6 { 7 public void OnActionExecuted(ActionExecutedContext context) 8 { 9 10 Console.WriteLine("********************On Action Executed********************");11 }12 13 public void OnActionExecuting(ActionExecutingContext context)14 {15 Console.WriteLine("********************On Action Executing********************");16 }17 }18 19 public class AsyncDoDoActionFilter : IAsyncActionFilter20 {21 public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)22 {23 24 Console.WriteLine("********************On Async Action Executing********************");25 await next();26 Console.WriteLine("********************On Async Action Executed********************");27 }28 }29 }
ActionExecutingContext提供以下屬性:
- ActionArguments- 用于讀取操作方法的輸入。
- Controller- 用于處理控制器實例。
- Result- 設置
Result
會使操作方法和后續操作篩選器的執行短路。
ActionExecutedContext提供Controller
和Result
以及以下屬性:
- Canceled- 如果操作執行已被另一個篩選器設置短路,則為 true。
- Exception- 如果操作或之前運行的操作篩選器引發了異常,則為非 NULL 值。 將此屬性設置為 null:
- 有效地處理異常。
- 執行
Result
,從操作方法中將它返回。
對于IAsyncActionFilter
,一個向ActionExecutionDelegate的調用可以達到以下目的:
- 執行所有后續操作篩選器和操作方法。
- 返回
ActionExecutedContext
。
異常Filter
異常篩選器:
- 實現IExceptionFilter或IAsyncExceptionFilter。
- 可用于實現常見的錯誤處理策略。
下面的異常篩選器示例顯示在開發應用時發生的異常的相關詳細信息:
1 using Microsoft.AspNetCore.Mvc.Filters; 2 3 namespace DemoCoreMVC.Filter 4 { 5 public class DoExceptionFilter :Attribute, IExceptionFilter 6 { 7 public void OnException(ExceptionContext context) 8 { 9 Console.WriteLine("********************On Exception********************");10 }11 }12 13 public class DoAsyncExceptionFilter : Attribute, IAsyncExceptionFilter14 {15 public async Task OnExceptionAsync(ExceptionContext context)16 {17 await Task.Run(() =>18 {19 Console.WriteLine("********************On Exception Async********************");20 });21 22 }23 }24 }
異常篩選器:
- 沒有之前和之后的事件。
- 實現OnException或OnExceptionAsync。
- 處理 Razor 頁面或控制器創建、模型綁定、操作篩選器或操作方法中發生的未經處理的異常。
- 請不要捕獲資源篩選器、結果篩選器或 MVC 結果執行中發生的異常。
若要處理異常,請將ExceptionHandled屬性設置為true
或分配Result屬性。 這將停止傳播異常。 異常篩選器無法將異常轉變為“成功”。 只有操作篩選器才能執行該轉變。
異常篩選器:
- 非常適合捕獲發生在操作中的異常。
- 并不像錯誤處理中間件那么靈活。
建議使用中間件處理異常。 基于所調用的操作方法,僅當錯誤處理不同時,才使用異常篩選器。 例如,應用可能具有用于 API 終結點和視圖/HTML 的操作方法。 API 終結點可以將錯誤信息返回為 JSON,而基于視圖的操作可能會以 HTML 形式返回錯誤頁。
結果Filter
結果篩選器:
- 實現接口:
- IResultFilter或IAsyncResultFilter
- IAlwaysRunResultFilter或IAsyncAlwaysRunResultFilter
- 它們的執行圍繞著操作結果的執行。
1 using Microsoft.AspNetCore.Mvc.Filters; 2 3 namespace DemoCoreMVC.Filter 4 { 5 public class DoResultFilter :Attribute, IResultFilter 6 { 7 public void OnResultExecuted(ResultExecutedContext context) 8 { 9 Console.WriteLine("********************On Result Executed********************");10 }11 12 public void OnResultExecuting(ResultExecutingContext context)13 {14 Console.WriteLine("********************On Result Executing********************");15 }16 }17 18 public class DoAysncResultFilter :Attribute, IAsyncResultFilter19 {20 public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)21 {22 Console.WriteLine("********************On Result Execution Async Executing********************");23 await next();24 Console.WriteLine("********************On Result Execution Async Executed********************");25 }26 }27 28 }
Filter測試
將寫好的過濾器,放在Home/Index上,如下所示:
1 [DoExceptionFilter]2 [LogResourceFilter]3 [DoResultFilter]4 [DoDoActionFilter]5 public IActionResult Index()6 {7 _logger.LogInformation("Hello, 這是首頁!");8 return View();9 }
測試如下所示:
說明:異常過濾器沒有輸出內容,是因為沒有異常產生。授權過濾器沒有添加,在所有過濾器之前開始,所有過濾器之后結束。
Filter全局應用
Filter可以應用在單個Controller或Action上,也可以進行全局應用,代碼如下所示:
1 builder.Services.AddControllersWithViews(option =>2 {3 option.Filters.Add();4 option.Filters.Add ();5 option.Filters.Add ();6 option.Filters.Add ();7 });
全局測試如下所示:
以上就是ASP.NET Core MVC 從入門到精通之Filter的全部內容。
參考文檔
官方文檔:https://learn.microsoft.com/zh-cn/aspnet/core/mvc/controllers/filters?view=aspnetcore-6.0