ASP.NET Core Filter

发布时间 2023-11-02 14:05:25作者: 云霄宇霁

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)之前运行。