ASP.NET Core 2 學習筆記(十四)Filters

来源:https://www.cnblogs.com/snaildev/archive/2018/06/08/9154669.html
-Advertisement-
Play Games

Filter是延續ASP.NET MVC的產物,同樣保留了五種的Filter,分別是Authorization Filter、Resource Filter、Action Filter、Exception Filter及Result Filter。通過不同的Filter可以有效處理封包進出的加工,本 ...


Filter是延續ASP.NET MVC的產物,同樣保留了五種的Filter,分別是Authorization FilterResource FilterAction FilterException FilterResult Filter
通過不同的Filter可以有效處理封包進出的加工,本篇將介紹ASP.NET Core的五種Filter運作方式。

Filter 介紹

Filter的作用是在Action 執行前或執行後做一些加工處理。
某種程度來看,會跟Middleware很像,但執行的順序略有不同,用對Filter不僅可以減少代碼,還可以提高執行效率。

ASP.NET Core 有以下五種Filter 可以使用:

  • Authorization Filter
    Authorization是五種Filter中優先順序最高的,通常用於驗證Request合不合法,不合法後面就直接跳過。
  • Resource Filter
    Resource是第二優先,會在Authorization之後,Model Binding之前執行。通常會是需要對Model加工處理才用。
  • Action Filter
    最常使用的Filter,封包進出都會經過它,使用上沒什麼需要特別註意的。跟Resource Filter很類似,但並不會經過Model Binding。
  • Exception Filter
    異常處理的Filter。
  • Result Filter
    當Action完成後,最終會經過的Filter。

Filter 運作方式

ASP.NET Core的每個Request都會先經過已註冊的Middleware接著才會執行Filter,除了會依照上述的順序外,同類型的Filter預設都會以先進後出的方式處里封包。
Response在某些Filter並不會做處理,會直接被pass。Request及Response的運作流程如下圖:

  • 黃色箭頭是正常情況流程
  • 灰色箭頭是異常處理流程

建立Filter

ASP.NET Core的Filter基本上跟ASP.NET MVC的差不多。
上述的五種Filter範例分別如下:

Authorization Filter

AuthorizationFilter.cs

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Filters;

namespace MyWebsite.Filters
{
    public class AuthorizationFilter : IAuthorizationFilter
    {
        public void OnAuthorization(AuthorizationFilterContext context)
        {
            context.HttpContext.Response.WriteAsync($"{GetType().Name} in. \r\n");
        }
    }
}

非同步的方式:

// ...
public class AuthorizationFilter : IAsyncAuthorizationFilter
{
    public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
    {
        await context.HttpContext.Response.WriteAsync($"{GetType().Name} in. \r\n");
    }
}

Resource Filter

ResourceFilter.cs

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Filters;

namespace MyWebsite.Filters
{
    public class ResourceFilter : IResourceFilter
    {
        public void OnResourceExecuting(ResourceExecutingContext context)
        {
            context.HttpContext.Response.WriteAsync($"{GetType().Name} in. \r\n");
        }

        public void OnResourceExecuted(ResourceExecutedContext context)
        {
            context.HttpContext.Response.WriteAsync($"{GetType().Name} out. \r\n");
        }
    }
}

非同步的方式:

// ...
public class ResourceFilter : IAsyncResourceFilter
{
    public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next)
    {
        await context.HttpContext.Response.WriteAsync($"{GetType().Name} in. \r\n");

        await next();

        await context.HttpContext.Response.WriteAsync($"{GetType().Name} out. \r\n");
    }
}

Action Filter

ActionFilter.cs

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Filters;

namespace MyWebsite.Filters
{
    public class ActionFilter : IActionFilter
    {
        public void OnActionExecuting(ActionExecutingContext context)
        {
            context.HttpContext.Response.WriteAsync($"{GetType().Name} in. \r\n");
        }

        public void OnActionExecuted(ActionExecutedContext context)
        {
            context.HttpContext.Response.WriteAsync($"{GetType().Name} out. \r\n");
        }
    }
}

非同步的方式:

// ...
public class ActionFilter : IAsyncActionFilter
{
    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        await context.HttpContext.Response.WriteAsync($"{GetType().Name} in. \r\n");

        await next();

        await context.HttpContext.Response.WriteAsync($"{GetType().Name} out. \r\n");
    }
}

Result Filter

ResultFilter.cs

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Filters;

namespace MyWebsite.Filters
{
    public class ResultFilter : IResultFilter
    {
        public void OnResultExecuting(ResultExecutingContext context)
        {
            context.HttpContext.Response.WriteAsync($"{GetType().Name} in. \r\n");
        }

        public void OnResultExecuted(ResultExecutedContext context)
        {
            context.HttpContext.Response.WriteAsync($"{GetType().Name} out. \r\n");
        }
    }
}

非同步的方式:

// ...
public class ResultFilter : IAsyncResultFilter
{
    public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
    {
        await context.HttpContext.Response.WriteAsync($"{GetType().Name} in. \r\n");

        await next();

        await context.HttpContext.Response.WriteAsync($"{GetType().Name} out. \r\n");
    }
}

Exception Filter

ExceptionFilter.cs

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Filters;

namespace MyWebsite.Filters
{
    public class ExceptionFilter : IExceptionFilter
    {
        public void OnException(ExceptionContext context)
        {
            context.ExceptionHandled = true; // 表明異常已處理,客戶端可得到正常返回
            context.HttpContext.Response.WriteAsync($"{GetType().Name} in. \r\n");
        }
    }
}

非同步的方式:

// ...
public class ExceptionFilter : IAsyncExceptionFilter
{
        public Task OnExceptionAsync(ExceptionContext context)
        {
            context.ExceptionHandled = true;// 表明異常已處理,客戶端可得到正常返回
            context.HttpContext.Response.WriteAsync($"{GetType().Name} in. \r\n");
            return Task.CompletedTask;
        }
}

註冊Filter

Filter有兩種註冊方式,一種是全局註冊,另一種是用[Attribute]局部註冊的方式,只套用在特定的Controller或Action。

全局註冊

Startup.ConfigureServices的MVC服務中註冊Filter,這樣就可以套用到所有的Request。如下:

// ...
public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc(config =>
        {
            config.Filters.Add(new ResultFilter());
            config.Filters.Add(new ExceptionFilter());
            config.Filters.Add(new ResourceFilter());
        });
    }
}

局部註冊

ASP.NET Core在局部註冊Filter的方式跟ASP.NET MVC有一點不一樣,要通過[TypeFilter(type)]
在Controller或Action上面加上[TypeFilter(type)]就可以局部註冊Filter。如下:

// ...
namespace MyWebsite.Controllers
{
    [TypeFilter(typeof(AuthorizationFilter))]
    public class HomeController : Controller
    {
        [TypeFilter(typeof(ActionFilter))]
        public void Index()
        {
            Response.WriteAsync("Hello World! \r\n");
        }
        
        [TypeFilter(typeof(ActionFilter))]
        public void Error()
        {
            throw new System.Exception("Error");
        }
    }
}

[TypeFilter(type)]用起來有點冗長,想要像過去ASP.NET MVC用[Attribute]註冊Filter的話,只要將Filter繼承Attribute即可。如下:

public class AuthorizationFilter : Attribute, IAuthorizationFilter
{
    // ...
}
public class ActionFilter : Attribute, IActionFilter
{
    // ...
}

[Attribute] 註冊就可以改成如下方式:

// ...
namespace MyWebsite.Controllers
{
    [AuthorizationFilter]
    public class HomeController : Controller
    {
        [ActionFilter]
        public void Index()
        {
            Response.WriteAsync("Hello World! \r\n");
        }
        
        [ActionFilter]
        public void Error()
        {
            throw new System.Exception("Error");
        }
    }
}

執行結果

http://localhost:5000/Home/Index 輸出結果如下:

AuthorizationFilter in.
ResourceFilter in.
ActionFilter in.
Hello World!
ActionFilter out.
ResultFilter in.
ResultFilter out.
ResourceFilter out.

http://localhost:5000/Home/Error 輸出結果如下:

AuthorizationFilter in.
ResourceFilter in.
ActionFilter in.
ActionFilter out.
ExceptionFilter in.
ResourceFilter out.

執行順序

預設註冊同類型的Filter 是以先進後出的方式處里封包,註冊層級也會影響執行順序。

但也可以通過實現 IOrderedFilter 更改執行順序。例如:

public class ActionFilter : Attribute, IActionFilter, IOrderedFilter
{
    public string Name { get; set; }

    public int Order { get; set; } = 0;

    public void OnActionExecuting(ActionExecutingContext context)
    {
        context.HttpContext.Response.WriteAsync($"{GetType().Name}({Name}) in. \r\n");
    }
    public void OnActionExecuted(ActionExecutedContext context)
    {
        context.HttpContext.Response.WriteAsync($"{GetType().Name}({Name}) out. \r\n");
    }
}

在註冊Filter 時帶上Order,數值越小優先權越高。

// ...
public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc(config =>
        {
            config.Filters.Add(new ActionFilter() { Name = "Global", Order = 3 });
        });
    }
}
// ...
namespace MyWebsite.Controllers
{
    [ActionFilter(Name = "Controller", Order = 2)]
    public class HomeController : Controller
    {
        [ActionFilter(Name = "Action", Order = 1)]
        public void Index()
        {
            Response.WriteAsync("Hello World! \r\n");
        }
    }
}

變更執行順序後的輸出內容:

ActionFilter(Action) in. 
ActionFilter(Controller) in. 
ActionFilter(Global) in. 
Hello World! 
ActionFilter(Global) out. 
ActionFilter(Controller) out. 
ActionFilter(Action) out.

參考

ASP.NET Core Filters

 

老司機發車啦:https://github.com/SnailDev/SnailDev.NETCore2Learning  


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一款用C#開發的APP開源項目。這款開源項目名為SmoSec,目前包含資產管理、耗材管理兩大類。並且,未來會不斷迭代,持續增加盤點、標簽列印和倉庫管理等功能。 ...
  • 公司用了一臺發卡機,usb介面,半雙工,給了個dll,不支持線程操作,使得UI線程老卡。 懊惱了,想自己直接通過usb讀寫,各種百度,然後是無數的坑,最終搞定。 現將各種坑和我自己的某些猜想記錄一下,也供各位參考。 一、常量定義 主要用於CreateFile時用。 二、結構、枚舉、類定義 都是從各種 ...
  • 使用.Net Core 2.1開發Captcha驗證碼服務 開發工具:Visual Studio 2017 15.7.3 開發平臺:64位 Windows 10 目標框架:.NET Core 2.1 完成度:已實現 Github地址: "https://github.com/PuzzledAlien ...
  • 哪些因素可能會導致損壞? 損壞的原因也各不相同,包括但不限於 無法讀取/寫入存儲介質 程式發生崩潰(特別是在數據寫入 RVT 模型時) 附加模塊以通過正常 UI 無法或意外的方式修改圖元 未經測試的多項操作或一系列操作(例如,取消同步或在同步後使用“撤消”命令) 解決方案: 要最大程度地減少數據損壞 ...
  • 新手上路,老司機請多多包含!Ocelot 在博園裡文章特別多,但是按照其中一篇文章教程,如果經驗很少或者小白,是沒法將程式跑向博主的結果. 因此總結下 參考多篇文章,終於達到預期效果。 Ocelot 目標是使用.NET運行微服務/面向服務架構,我們需要一個統一的入口進入我們的服務,提供監控、鑒權、負 ...
  • Python3 與 C# 基礎語法對比(基礎知識場):https://www.cnblogs.com/dunitian/p/9103673.html Python3 與 C# 基礎語法對比(String專欄):https://www.cnblogs.com/dunitian/p/9119986.ht ...
  • 需求:當選擇工序時,帶出對應的作業內容 步驟一:使用SqlDataSource設定從資料庫撈取要填入下拉式選單的值 步驟二:設定下拉式選單的項目 步驟三:再拉一個SqlDatasource 步驟四:設定第二個SqlDataSource變數 步驟五:再拉一個下拉式選單設定數據源 , 但不打勾AutoP ...
  • 問題描述: “System.InvalidOperationException”類型的異常在 System.Data.OracleClient.dll 中發生,但未在用戶代碼中進行處理 其他信息: 嘗試載入 Oracle 客戶端庫時引發 BadImageFormatException。如果在安裝 3 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...