AOP系列之Filter管道模型

一、前言

Filter 是延續 Asp.Net Mvc 的產物,同樣保留了五種的Filter,分別是Authorization FilterResource FilterAction FilterException FilterResult Filter。通過不同的 Filter 可以有效處理一些共通的動作。

(一)Filter 介紹

  • Authorization Filter:優先級1;權限過濾器,通常在 Filter Pipleline 中首先執行,並用於決定當前客戶端 Request 請求權限的身份授權驗證
  • Resource Filter:優先級2;資源過濾器,通常在 Authorization 後面執行,同時在後面的其它過濾器完成後還會執行;作用於Api資源授權、緩存處理等一些可以性能原因的攔截,因爲運行在模型綁定前,所以這裏的操作都會影響模型綁定。
  • Action Filter:優先級3;方法過濾器,執行於 Action 方法前後,用於 Action 審計日誌、傳遞參數和方法返回值的處理。
  • Exception Filter:優先級4;異常過濾器,被應用全局策略處理未處理的異常被寫入響應體。
  • Result Filter:優先級5;返回值過濾器,可以執行於 Action 結果之前執行,且執行 Action 成功後執行,使用邏輯一般圍繞 Action 入參的驗證和格式化返回值。

(二)Filter 流程圖

image

二、Filter 實現&場景應用

在開始寫代碼前需引用nuget包或包含的集成包 Microsoft.AspNetCore.Mvc.Abstractions 均可;下面我用異步的方式,繼承相應過濾器實現對應功能,說這麼多,還是看代碼吧!

(一)Authorization Filter

權限過濾器,通過 Authorization Filter 可以實現複雜的 防篡改驗證XsrfToken防僞令牌 等操作。具體代碼如下:

    /// <summary>
    /// SB過濾器 - 權限
    /// </summary>
    public class SBAuthorizationFilterAttribute : Attribute, IAsyncAuthorizationFilter
    {
        public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
        {

            // 參數防篡改

            // 驗證XsrfToken防僞令牌

            // ..

        }
    }

(二)Resource Filter

資源過濾器,通過 Resource Filter 可以進行 Api資源授權緩存處理 等複雜操作。具體代碼如下:

    /// <summary>
    /// SB過濾器 - 資源
    /// </summary>
    public class SBResourceFilterAttribute : Attribute, IAsyncResourceFilter
    {
        public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next)
        {
            // 控制器實例化之前,執行的動作

            // 驗證是否跳過Api資源授權

            // 緩存處理

            await next();
            
            // Action的Result Filter(befor)執行後再執行

        }
    }

(三)Action Filter

方法過濾器,執行於控制器方法的前後置動作,前置動作可以應用於 參數傳遞 ,後置動作可以應用於 Action審計日誌 。具體代碼如下:

    /// <summary>
    /// SB過濾器 - 方法
    /// </summary>
    public class SBActionFilter : IAsyncActionFilter
    {
        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {

            // Action執行前,執行的動作

            // 參數傳遞
            
            var result = await next();

            // Action的執行後,執行的動作

            // Action審計日誌

        }
    }

(四)Exception Filter

異常過濾器,作用於全局的異常處理,當系統發生未捕獲異常時會觸發此過濾器進行處理,應用於 全局異常捕獲異常日誌處理 。具體代碼如下:

    /// <summary>
    /// SB過濾器 - 全局異常
    /// </summary>
    public class SBExceptionFilter : IExceptionFilter
    {
        public void OnException(ExceptionContext context)
        {

            if (context.ExceptionHandled)//異常是否已處理
                return;

            // 異常處理
            context.Result = new ObjectResult(
                        new { code = "412", msg = "異常信息" });

            // 處理完告訴系統此異常已處理
            context.ExceptionHandled = true;
        }
    }

(五)Result Filter

返回值過濾器,執行於結果執行之前/之後,前置動作可以應用於 Dto模型驗證 ,後置動作可以應用於 格式化返回值 。具體代碼如下:

    /// <summary>
    /// SB過濾器 - 返回值
    /// </summary>
    public class SBResultFilter : IAsyncResultFilter
    {
        public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
        {

            // 結果執行前,執行的動作

            // Dto模型驗證

            var result = await next();

            // 結果執行後,執行的動作

            // 格式化返回值

        }
    }

三、Asp.Net Core 過濾器的註冊方式

Asp.Net Core過濾器 分爲兩種註冊方式 全局局部 ,根據過濾器的使用場景及需要我們可以選擇不同的註冊方式。

(一)全局註冊

過濾器也區分作用於全局和局部之分,作用於全局就不需要局部(類、控制器等)每一個進行代碼註冊,相對方便非常多。具體代碼如下:

        public void ConfigureServices(IServiceCollection services)
        {
            //...

            services.AddMvc(options => {
                options.Filters.Add<SBAuthorizationFilterAttribute>();
                options.Filters.Add<SBResourceFilterAttribute>();
                options.Filters.Add<SBActionFilter>();
                options.Filters.Add<SBExceptionFilter>();
                options.Filters.Add<SBResultFilter>();
            });

            //...
        }

(二)局部註冊

場景假設幾大過濾器中有個過濾器只想作用於局部作用,過濾器可能就需要局部註冊 ServiceFilterTypeFilter
ps:幾大過濾器沒有繼承 Attribute 不能使用特性的註冊方式,想了解特性註冊方式可以百度,暫時還沒寫。

ServiceFilterTypeFilter 的區別:

  • ServiceFilterTypeFilter 都實現了 IFilterFactory
  • ServiceFilter 需要對自定義的 Filter 進行註冊,TypeFilter 不需要。
  • ServiceFilterFilter 生命週期源自於註冊方式,而 TypeFilter 每次都會創建一個新的實例。

1. ServiceFilter 使用方式

控制器中具體代碼如下:

    [ServiceFilter(typeof(SBAuthorizationFilterAttribute))]//過濾器註冊到控制器中
    [Route("api/[controller]")]
    [ApiController]
    public class DefaultController : ControllerBase
    {
        // GET: api/Default
        [HttpGet]
        [ServiceFilter(typeof(SBAuthorizationFilterAttribute))]//過濾器註冊到方法中
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }
    }

註冊服務中具體代碼如下:

        public void ConfigureServices(IServiceCollection services)
        {
            //...

            services.AddMvc();

            // 註冊過濾器服務,使用ServiceFilter 方式必須要註冊 否則會報沒有註冊該服務的相關異常
            services.AddSingleton<SBAuthorizationFilterAttribute>();

            //...
        }

2. TypeFilter 使用方式

TypeFilter 的用法就比較方便,只要控制器或者方法註冊即可。

    [TypeFilter(typeof(SBAuthorizationFilterAttribute))]//過濾器註冊到控制器中
    [Route("api/[controller]")]
    [ApiController]
    public class DefaultController : ControllerBase
    {
        // GET: api/Default
        [HttpGet]
        [TypeFilter(typeof(SBAuthorizationFilterAttribute))]//過濾器註冊到方法中
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }
    }

四、Asp.Net Core 過濾器調用順序

  • 全局->局部
  • Controller->Action
  • 先註冊先調用

image

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章