1. 程式人生 > 實用技巧 >ASP.Net Core -- 過濾器

ASP.Net Core -- 過濾器

Filter

過濾器用於MVC,可以在MVC請求管道里新增邏輯,之前或之後,可以避免程式碼重複,比如授權,日誌,對HTTP有要求等等。

比如:

[Authorize]
public IActionResult Create()
{
      return View();
}

再比如,需要HTTPS請求:

[RequireHttps]
public IActionResult Create()
{
    return View();
}

程式碼也很簡潔,直接中括號,寫上類名就行

看一下MVC和過濾器的關係:

當請求來到路由器後,可以有一個過濾器,模型驗證完後還可以有過濾器,也就是進入controller之前,之後還可以有一個過濾器,ViewResult執行後也可以有一個過濾器

Filter種類

1:授權:

授權過濾器在過濾器管道中第一個執行,通常用於驗證當前請求的合法性,不合法後面的管道會直接跳過。它們只有一個Before方法,不像其它大多數過濾器支援前置階段方法和後置階段方法。注意,您不要在授權過濾器中丟擲異常,因為沒有任何程式碼來處理異常(異常過濾器不處理它們)。

2:資源

資源過濾器是第二個執行,在 Authorization Filter 之後,Model Binding 之前執行。在效能方面,資源過濾器在實現快取或截斷過濾器管道尤為重要。

3:Action

使用率最高的過濾器,在呼叫 Acioin 方法之前和之後執行程式碼。跟 Resource Filter 很類似,但 Model Binding 在之後執行。 • 異常

4:異常

用於為應用程式執行異常處理策略。

5:Result

當 Action 執行完成後,最後會執行過濾器。用於處理ActionResult結果輸出策略。

實現Filter

要是有自己定義的Filter,要實現IFilterMetadata這個介面,其實這個接口裡邊啥也沒有,因為它不知道我們需要實現什麼功能的Filter,針對以上五種型別,IFilterMetadata一下有五個子介面,分別是:

1:IAuthorizationFilter,IAsyncAuthorizationFilter 注:一個同步版本的還有一個非同步版本的

2:IResourceFilter

3:IActionFilter

4:IExceptionFilter

5:IResultFilter

程式碼示例

新建一個LogResourceFilter.cs檔案,如下:

public class LogResourceFilter: Attribute, IResourceFilter
    {
        public void OnResourceExecuting(ResourceExecutingContext context)
        {
            Console.WriteLine("Executing Resource Filter!");
        }

        public void OnResourceExecuted(ResourceExecutedContext context)
        {
            Console.Write("Executed Resource Filter...");
        }
    }

裡邊兩個方法,每個方法裡都有一個引數,代表上下文,看名字就知道,一個是進行時,一個是過去時或者叫完成時也行。就是一個是在動作發生之前執行,一個是在動作完成後執行

1:ResourceExecutingContext

這個裡邊包含了HttpContext還有路由的一些東西,以及當前Action的一些資訊

2:ResourceExecutedContext

這個和上邊的不一樣,包含了一些其它方面的東西,比如返回的IActionResult,具體內容可以對其進行反編譯檢視原始碼

這個類實現IResourceFilter這個介面,我們可以對這個介面進行反編譯,如下:

可以看到,它就實現了IFilterMetadata這個介面。為什麼實現Attribute這個介面?因為要在動作前邊使用過濾器

這是同步的,我們再新建一個非同步版本的,取名為LogAsyncResourceFilter.cs,如下:

public class LogAsyncResourceFilter : Attribute, IAsyncResourceFilter
    {
        public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next)
        {
            Console.WriteLine("Executing async Resource Filter!");

            var executedContext = await next();

            Console.WriteLine("Executed async Resource Filter...");

        }
    }

這裡邊只有一個方法,因為是非同步的嘛,有一個委託next,next裡就包含了整個剩餘的MVC管道里邊的東西,在日常開發中,還是使用同步的版本比較好。

應用Filter

一共應用到三個地方

1:Action

2:Controller

3:全域性

在Index上邊使用LogResourceFilter這個過濾器,程式碼示例如下:

[LogResourceFilter] 
        public IActionResult Index() 
        {
            var studentList = _repository.GetAll();

            var newStudentList = studentList.Select(x => new StudentViewModel
            {
                Name = $"{x.FirstName}+{x.LastName}",
                Age = DateTime.Now.Subtract(x.BirthDate).Days / 365,
                Id = x.Id
            });

            var list = new HomeIndexViewModel
            {
                studentList = newStudentList
            };

            return View(list);
        }

然後啟動專案,開啟控制檯,如下:

一個index動作發生之前,一個在index動作發生之後。

如果放在Controller之前,那麼無論進到那個動作,都會呼叫這兩個方法,這裡就不測試了。

全域性應用Filter

既然是全域性,那麼肯定實在startup裡添加了,需要在ConfigureServices方法裡使用services.AddMvc()來新增

一共有三種方式,如下:

services.AddMvc(options=> 
{
    options.Filters.Add(new LogResourceFilter());

    options.Filters.Add(typeof(LogResourceFilter));

    options.Filters.Add<LogResourceFilter>();
});

這樣,不論在那個控制器裡,那個動作發生,都會呼叫過濾器裡邊那兩個方法,一個動作發生之前,一個動作發生之後!

這幾種Filter的級別和執行順序如下: