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的級別和執行順序如下: