ASP.NET Core 過濾器
阿新 • • 發佈:2020-08-25
# 過濾器
過濾器與中介軟體很相似,能夠在某些功能前後執行,由此而形成一個管道
### ASP.NET Core MVC 提供了5種類型的過濾器
* `AuthorizationFilter`:最先執行,用於判斷使用者是否授權如果未授權直接結束當前請求
* `ResourceFilter`:在`Authorization`後執行,可以用來對請求判斷是否執行Action
* `ActionFilter`:在Action執行的前後執行,與`Resource`不同的是,它在模型繫結之後執行。
* `ExceptionFilter`:用於捕獲異常
* `ResultFilter`:在最後執行,可以控制Action執行的結果
以上五種型別過濾器的工作順序
```mermaid
graph TD
A[中介軟體] --> B[AuthorizationFilter]
B --> C[ResourceFilter]
C --> D[ExceptionFilter]
D --> F[模型繫結]
F --> G[ActionFilter]
G --> H[Action]
H --> I[ActionFilter]
I --> L[ResultAction]
```
### 快速入門
Action過濾器將在Controller的Action執行之前和執行相應的方法
首先我們新建一個類,繼承於`IActionFilter`,檢視`IActionFilter`裡面會發現有兩個介面
```C#
//
// 摘要:
// A filter that surrounds execution of the action.
public interface IActionFilter : IFilterMetadata
{
//
// 摘要:
// Called after the action executes, before the action result.
//
// 引數:
// context:
// The Microsoft.AspNetCore.Mvc.Filters.ActionExecutedContext.
void OnActionExecuted(ActionExecutedContext context);
//
// 摘要:
// Called before the action executes, after model binding is complete.
//
// 引數:
// context:
// The Microsoft.AspNetCore.Mvc.Filters.ActionExecutingContext.
void OnActionExecuting(ActionExecutingContext context);
}
```
根據描述我們可得知第一個是在執行方法之後執行,第二個在執行方法之前執行
然後就可以寫我們自己的過濾器啦
```C#
public class TestActionFilterAttribute : Attribute, IActionFilter
{
public void OnActionExecuted(ActionExecutedContext context)
{
Console.WriteLine("OnActionExecuted執行了");
}
public void OnActionExecuting(ActionExecutingContext context)
{
Console.WriteLine("OnActionExecuting執行了");
}
}
```
心細的小夥伴可能看到我這裡還繼承了`Attribute`,沒錯可以直接通過特性應用在方法或者類上表示對這個方法或者類進行過濾
```
[HttpGet]
[TestActionFilter]
public IActionResult Test()
{
Console.WriteLine("Action執行");
return Ok(new
{
msg = "OK"
});
}
```
```
[Route("api/[controller]")]
[ApiController]
[TestActionFilter]
public class TestController : ControllerBase
{
}
```
也可以在`startup`的`ConfigureServices()`裡面進行新增,表示全域性註冊
```
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(options =>
options.Filters.Add(new WebApplication2.Utility.Filter.TestActionFilterAttribute()));
}
```
執行結果
```
OnActionExecuting執行了
Action執行
OnActionExecuted執行了
```
多個過濾器執行時,會保持著**先進後出**的原則,例如
```C#
public class TestActionFilterAttribute : Attribute, IActionFilter
{
public void OnActionExecuted(ActionExecutedContext context)
{
Console.WriteLine("OnActionExecuted1執行了");
}
public void OnActionExecuting(ActionExecutingContext context)
{
Console.WriteLine("OnActionExecuting1執行了");
}
}
```
```C#
public class TestActionFilterAttribute2 : Attribute, IActionFilter
{
public void OnActionExecuted(ActionExecutedContext context)
{
Console.WriteLine("OnActionExecuted2執行了");
}
public void OnActionExecuting(ActionExecutingContext context)
{
Console.WriteLine("OnActionExecuting2執行了");
}
}
```
執行結果為
```
OnActionExecuting1執行了
OnActionExecuting2執行了
Action執行
OnActionExecuted2執行了
OnActionExecuted1執行了
```
除了直接實現Filter介面,.Net Core同時提供了一些基於特性的過濾器,我們可以繼承相應的特性來實現自定義的過濾器。這些特性包括`ActionFilterAttribute`、`ExceptionFilterAttribute`、`ResultFilterAttribute`、`FormatFilterAttribute`、`ServiceFilterAttribute`、`TypeFilterAttribute`
### Filter通過註解的話如何注入例項呢
如果特性類的建構函式有參的話特性也是需要帶入引數的並且只能是常量,那麼如何注入呢?
1. `ServiceFilter` 需要在容器中註冊過濾器
```C#
[ServiceFilter(typeof(TestActionFilterAttribute))]
```
2. `TypeFilter` 通過使用`Microsoft.Extensions.DependencyInjection.ObjectFactory`對指定的過濾器型別進行例項化因此不需要註冊容器
```C#
[TypeFilter(typeof(TestActionFilterAttribute))]
```
3. `IFilterFactory` 需要自己手動實現工廠類(其實就是第一種的實現方式,也需要在容器中註冊過濾器)
```C#
public class CustomFilterFactory : Attribute,IFilterFactory
{
private Type _filterType = null;
public CustomFilterFactory(Type type)
{
this._filterType = type;
}
public bool IsReusable => true;
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
{
return (IFilterMetadata)serviceProvider.GetService(this._filterType);
// throw new NotImplementedException();
}
}
```