過濾器
過濾器與中間件很相似,能夠在某些功能前后執行,由此而形成一個管道
ASP.NET Core MVC 提供了5種類型的過濾器
AuthorizationFilter
:最先執行,用於判斷用戶是否授權如果未授權直接結束當前請求ResourceFilter
:在Authorization
后執行,可以用來對請求判斷是否執行ActionActionFilter
:在Action執行的前后執行,與Resource
不同的是,它在模型綁定之后執行。ExceptionFilter
:用於捕獲異常ResultFilter
:在最后執行,可以控制Action執行的結果
以上五種類型過濾器的工作順序
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
里面會發現有兩個接口
//
// 摘要:
// 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);
}
根據描述我們可得知第一個是在執行方法之后執行,第二個在執行方法之前執行
然后就可以寫我們自己的過濾器啦
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執行了
多個過濾器執行時,會保持着先進后出的原則,例如
public class TestActionFilterAttribute : Attribute, IActionFilter
{
public void OnActionExecuted(ActionExecutedContext context)
{
Console.WriteLine("OnActionExecuted1執行了");
}
public void OnActionExecuting(ActionExecutingContext context)
{
Console.WriteLine("OnActionExecuting1執行了");
}
}
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通過注解的話如何注入實例呢
如果特性類的構造函數有參的話特性也是需要帶入參數的並且只能是常量,那么如何注入呢?
ServiceFilter
需要在容器中注冊過濾器
[ServiceFilter(typeof(TestActionFilterAttribute))]
TypeFilter
通過使用Microsoft.Extensions.DependencyInjection.ObjectFactory
對指定的過濾器類型進行實例化因此不需要注冊容器
[TypeFilter(typeof(TestActionFilterAttribute))]
IFilterFactory
需要自己手動實現工廠類(其實就是第一種的實現方式,也需要在容器中注冊過濾器)
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();
}
}