ASP.NET Core Filter
Filter在ASP.NET Core中允许code在指定的请求阶段前或者后执行。
Filter在ASP.NET Core方法请求管道中运行,有时被称作filter pipeline,filter pipeline在ASP.NET Core选择Action执行。
Filter 分类
每个filter type在filter pipeline的不同阶段执行。
AuthorizationFilter:
- 第一个执行
- 判断请求user是否被授权
- 如果user没被授权则短路
ResourceFilter
- 在Authorization Filter之后执行
- OnResourceExecuting在模型绑定之前执行
- OnResourceExcuted在其余管道运行之后执行
ActionFilter
- 在Action执行前后立即执行
- 可以改变传入action的参数
- 可以改变action返回的结果
Endpoint Filter
- 同ActionFilter
- 可以在Action和路由处理Endpoint调用
ExceptionFilter
- 应用全局policy处理在响应前不可预知的异常。
ResultFilter
- 仅在Action成功执行后执行
- 对于和view或者formatter紧密结合的逻辑很有用
Dependency injection
Filter可以以type或者instance的方式加入。如果是以instance的方式加入的,那么这个instance被用于每次reqquest;如果是以type的方式加入它是type-activated
什么是type-activated?
- 每次request创建一个新的instance
- 任何构造函数依赖都由DI populated。
下面Filters支持从DI的构造函数依赖
- ServiceFilterAttribute
Service filter需要在DI Container中注入,并从DI Container中检索instance。
[ServiceFilter(typeof(Demo01Attribute))] public async Task<IActionResult> AttributeTest() { await Task.CompletedTask; return Ok("Invoke Completely!"); }
ServiceFilterAttribute及所依赖的service需要注入到DI Container中
builder.Services.AddTransient<Service01>();
builder.Services.AddTransient<Demo01Attribute>();
ServiceFilterAttribute的实现类
public class Demo01Attribute : IAsyncActionFilter { private readonly Service01 _service01; public Demo01Attribute(Service01 service01) { _service01 = service01; } public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { Console.WriteLine($"Run before Demo01 OnActionExecutionAsync, parameters: date:{_date}, class: {_className}."); _service01.Run(); await next(); Console.WriteLine("Run after Demo01 OnActionExecutionAsync"); } }
Notes: ServiceFilterAttribute实现IFilterFactory, IFilterFactory暴露CreateInstance方法创建IFilterMetadata instance. CreateInstance从DI中检索指定的type.
- TypeFilterAttribute
TypeFitlerAttribute和ServiceFilterAttribute很像,但是instance不是直接从DI Container中创建的,它的instance是通过Microsoft.Extensions.DependencyInjection.ObjectFactory创建的。
因为TypeFitlerAttribute不是从DI Container中创建instance所以:
1、TypeFilterAttribute filter不用注入到DI Container中,只需注入TypeFilterAttribute所需的service
2、TypeFitlerAttribute可以选择性接收一些参数
[TypeFilter(typeof(Demo01Attribute), Arguments = new object[] {"20231102",nameof(Demo01Attribute) }, IsReusable = false)] public async Task<IActionResult> AttributeTest() { await Task.CompletedTask; return Ok("Invoke Completely!"); }
TypeFitlerAttribute所需的Service注入到DI Container中
builder.Services.AddTransient<Service01>();
TypeFilterAttribute接收参数
public class Demo01Attribute : IAsyncActionFilter { private readonly Service01 _service01; private readonly string _date; private readonly string _className; public Demo01Attribute(string date, string className, Service01 service01) { _date = date; _className = className; _service01 = service01; } public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { Console.WriteLine($"Run before Demo01 OnActionExecutionAsync, parameters: date:{_date}, class: {_className}."); _service01.Run(); await next(); Console.WriteLine("Run after Demo01 OnActionExecutionAsync"); } }
- IFilterFactory
IFilterFactory 实现IFilterMetadata, 因此IFilterFactory instance可以在管道中替换任何IFitlerMetadata instance。
IFilterFactory可以作为自定义的attribute创建filter
public class ResponseHeaderFilterFactory : Attribute, IFilterFactory { public bool IsReusable => false; public IFilterMetadata CreateInstance(IServiceProvider serviceProvider) => new InternalResponseHeaderFilter(); private class InternalResponseHeaderFilter : IActionFilter { public void OnActionExecuting(ActionExecutingContext context) => context.HttpContext.Response.Headers.Add( nameof(OnActionExecuting), nameof(InternalResponseHeaderFilter)); public void OnActionExecuted(ActionExecutedContext context) { } }
在Filter pipeline中使用中间件
用中间件作为filter,创建一个类包含Configure方法指定中间件注入到filter pipeline
public class FilterMiddlewarePipeline { public void Configure(IApplicationBuilder app) { app.Use(async (context, next) => { context.Response.Headers.Add("Pipeline", "Middleware"); await next(); }); } }
用MiddlewareFilterAttribute 运行middleware
[MiddlewareFilter(typeof(FilterMiddlewarePipeline))] public async Task<IActionResult> AttributeTest() { await Task.CompletedTask; return Ok("Invoke Completely!"); }
中间件filter和ResourceFilter运行在同一个阶段在模型绑定(model binding)之前运行。