.net 溫故知新【16】:Asp.Net Core WebAPI 篩選器

一、篩選器

通過使用篩選器可在請求處理管道中的特定階段之前或之後運行代碼。

這即是我們經常聽到的面向切面編程AOP(Aspect Oriented Programming)技術,AOP通過預編譯方式和運行期間動態代理實現程序功能的統一維護的一種技術。

篩選器在 ASP.NET Core 操作調用管道(有時稱爲篩選器管道)內運行。 篩選器管道在 ASP.NET Core 選擇了要執行的操作之後運行:
image

Asp.Net Core 關注的切面點 包括錯誤處理、緩存、配置、授權和日誌記錄篩選器,這個是說通過篩選器可以實現對以上關注點的一些操作。

在Asp.Net Core中有如下幾種類型的篩選器:

image

其中部分是內置篩選器,比如授權,響應緩存已經幫我們內置進了框架,我們只需要配置即可使用;其他篩選器是可以自定義處理邏輯的。

下圖展示了篩選器類型在篩選器管道中的交互方式和執行順序:

image

二、操作型篩選器

第一部分主要是對篩選器的一個梳理,有些重點的提煉,詳情查看文檔,因爲文檔部分理解起來比較晦澀,比如關注點是關注點,知識說篩選器可以對這些關注點啓到作用,篩選器是固定的幾種,不要被文檔中的這種描述搞暈了,一會兒有這幾種,怎麼到下面又是另外幾種,要注意區分重點。

操作篩選器可以實現接口IActionFilter,在接口中有兩個方法,OnActionExecuting 在調用操作方法之前執行。 OnActionExecuted 在操作方法返回之後執行。

  • 先建WebAPI項目 WebAPI_Filter
  • 建一個 FilterController,並創建Get請求Test
namespace WebAPI_Filter.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class FilterController : ControllerBase
    {
        [HttpGet]
        public string Test()
        {
            return "測試Filter!";
        }
    }
}
  • 創建ActionFilter 篩選器
namespace WebAPI_Filter.Filter
{
    public class MyActionFilter : IActionFilter
    {
        public void OnActionExecuted(ActionExecutedContext context)
        {
            Console.WriteLine(context.HttpContext.Request.GetDisplayUrl()+ "  執行之後!");
        }

        public void OnActionExecuting(ActionExecutingContext context)
        {
            Console.WriteLine(context.HttpContext.Request.GetDisplayUrl() + "  執行之前!");
        }
    }
}
  • 在Program.cs裏面添加篩選器
    image

執行測試接口
image

三、篩選器作用域和執行順序

上面直接在Program.cs裏面添加篩選器的方式稱爲全局篩選器,所有控制器、操作都會受全局篩選器影響。還有一種篩選器實現方式是屬性篩選器,通過繼承屬性類然後將屬性標籤放置在控制器或者操作上。

新建兩個屬性類MyAttributeFilter 用於Controller控制器類,MyOPAttributeFilter用於操作方法上。

    public class MyAttributeFilter: ActionFilterAttribute
    {
        public override void OnActionExecuted(ActionExecutedContext context)
        {
            Console.WriteLine(context.HttpContext.Request.GetDisplayUrl() + "  控制器之後-篩選器屬性!");
        }

        public override void OnActionExecuting(ActionExecutingContext context)
        {
            Console.WriteLine(context.HttpContext.Request.GetDisplayUrl() + "  控制器之前-篩選器屬性!");
        }
    }


    public class MyOPAttributeFilter : ActionFilterAttribute
    {
        public override void OnActionExecuted(ActionExecutedContext context)
        {
            Console.WriteLine(context.HttpContext.Request.GetDisplayUrl() + "  操作之後-篩選器屬性!");
        }

        public override void OnActionExecuting(ActionExecutingContext context)
        {
            Console.WriteLine(context.HttpContext.Request.GetDisplayUrl() + "  操作之前-篩選器屬性!");
        }
    }

image

加上之前的全局篩選器,我們一共有三個作用域的篩選器,現在我們測試看看篩選器的執行順序。
image

則可總結出不同作用域篩選器的執行順序:

全局篩選器的 before 代碼。
	控制器篩選器的 before 代碼。
		操作方法篩選器的 before 代碼。
		操作方法篩選器的 after 代碼。
	控制器篩選器的 after 代碼。
全局篩選器的 after 代碼。

當然可以通過 Order 屬性來確定執行順序,在全局或者屬性篩選器裏面設置 Order 值,值越小執行優先級越高。

image

四、篩選器依賴注入

可按類型或實例添加篩選器。 如果添加實例,該實例將用於每個請求。

其中builder.Services.AddControllers(options => options.Filters.Add<MyActionFilter>())即爲按實例添加,該MyActionFilter用於每個請求。

如果添加類型,則將激活該類型。 激活類型的篩選器意味着:第一種是爲每個請求創建一個實例,第二種依賴關係注入 (DI) 將填充所有構造函數依賴項。

上面位置我們是爲每個請求創建一個實例,這樣的話無法使用依賴注入體系爲我們自動注入,因爲因爲屬性在應用時必須提供自己的構造函數參數,該參數需要手動指定。

比如我們想在操作方法的MyOPAttributeFilter篩選屬性 注入IHostEnvironment:

    public class MyOPAttributeFilter : ActionFilterAttribute
    {
        IHostEnvironment hostEnvironment;

        public MyOPAttributeFilter(IHostEnvironment _hostEnvironment)
        {
            hostEnvironment = _hostEnvironment;
        }
        public override void OnActionExecuted(ActionExecutedContext context)
        {
            Console.WriteLine(context.HttpContext.Request.GetDisplayUrl() + "  操作之後-篩選器屬性!");
        }

        public override void OnActionExecuting(ActionExecutingContext context)
        {
            Console.WriteLine(context.HttpContext.Request.GetDisplayUrl() + "  操作之前-篩選器屬性!");
            //打印環境變量
            Console.WriteLine(hostEnvironment.EnvironmentName);
        }
    }

這個時候直接就報錯提示需要參數,而我們想的是通過依賴注入配置。

image

框架提供以下篩選器支持從 DI 提供的構造函數依賴項:

  • ServiceFilterAttribute
  • TypeFilterAttribute
  • 在屬性上實現 IFilterFactory。

TypeFilterAttribute:不會直接從 DI 容器解析其類型。Microsoft.Extensions.DependencyInjection.ObjectFactory 對類型進行實例化,所以不需要先將MyOPAttributeFilter加入容器,直接使用:

[TypeFilter(typeof(MyOPAttributeFilter))]

image

ServiceFilterAttribute 使用需要先將MyOPAttributeFilter注入到容器,然後再使用。

image

以上就是關於AOP切面編程和篩選器的梳理,其他類型的篩選器和細節可查詢官方文檔:ASP.NET Core 中的篩選器

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