隨着技術的發展,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, IOrderedFilter 11 { 12 public RequireHttpsAttribute(); 13 14 // 15 // 摘要: 16 // Specifies whether a permanent redirect, 301 Moved Permanently, should be used 17 // 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.IAuthorizationFilter 22 // early. 23 public int Order { get; set; } 24 25 // 26 // 摘要: 27 // Called early in the filter pipeline to confirm request is authorized. Confirms 28 // requests are received over HTTPS. Takes no action for HTTPS requests. Otherwise 29 // if it was a GET request, sets Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext.Result 30 // to a result which will redirect the client to the HTTPS version of the request 31 // URI. Otherwise, sets Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext.Result 32 // 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.Result 38 // 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.Result 46 // to a result which will redirect the client to the HTTPS version of the request 47 // URI. Otherwise, default implementation sets Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext.Result 48 // 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 /// <summary> 6 /// 同步版本 7 /// </summary> 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 /// <summary> 24 /// 異步版本 25 /// </summary> 26 public class AsynLogResouceFilter : Attribute, IAsyncResourceFilter 27 { 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 : IAsyncActionFilter 20 { 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, IAsyncExceptionFilter 14 { 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, IAsyncResultFilter 19 { 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<LogResourceFilter>(); 4 option.Filters.Add<DoExceptionFilter>(); 5 option.Filters.Add<DoResultFilter>(); 6 option.Filters.Add<DoDoActionFilter>(); 7 });
全局測試如下所示:
以上就是ASP.NET Core MVC 從入門到精通之Filter的全部內容。
參考文檔
官方文檔:https://learn.microsoft.com/zh-cn/aspnet/core/mvc/controllers/filters?view=aspnetcore-6.0