Minimal API - Filter 筛选器

93 阅读1分钟

执行逻辑

sequenceDiagram
request->>endpoint: http请求
endpoint->>filter: 执行筛选器逻辑
filter-->>request: 跳过endpoint逻辑,返回response
filter->>endpoint: 执行endpoint逻辑
endpoint->>request: 返回response

官方描述

开发人员可以实现支持以下操作的业务逻辑:

  • endpoint处理程序 前、后 运行代码
  • 检查和修改endpoint程序调用期间提供的参数
  • 截获endpoint处理程序的相应行为

在以下场景中,筛选器很有用:

  • 验证已发送到终结点的请求参数和正文
  • 记录有关请求和响应的信息
  • 验证请求是否面向受支持的 API 版本

如何使用

个人推荐使用继承IEndpointFilter接口,这样可以逻辑复用。

日志打印

namespace Filters.EndpointFilters;

// 日志输出
// Before next
// Endpoint
// After next

app.MapGet("/", () => 
    { 
        app.Logger.LogInformation("Endpoint"); 
        return "Test of multiple filters"; 
    }) 
    .AddEndpointFilter<LoggerEndpointFilter>();

public class LoggerEndpointFilter : IEndpointFilter
{
    protected readonly ILogger Logger;
    
    // 依赖注入 ILoggerFactory
    protected ABCEndpointFilters(ILoggerFactory loggerFactory)
    {
        Logger = loggerFactory.CreateLogger<ABCEndpointFilters>();
    }

    public virtual async ValueTask<object?> InvokeAsync(EndpointFilterInvocationContext context,
        EndpointFilterDelegate next)
    {
        // 之前执行
        Logger.LogInformation("Before next");
        
        // 执行endpoint逻辑
        var result = await next(context);
        
        // 之后执行
        Logger.LogInformation("After next");
        return result;
    }
}

模型验证

public class TodoIsValidFilter : IEndpointFilter
{
    private ILogger _logger;

    // 依赖注入
    public TodoIsValidFilter(ILoggerFactory loggerFactory)
    {
        _logger = loggerFactory.CreateLogger<TodoIsValidFilter>();
    }

    public async ValueTask<object?> InvokeAsync(EndpointFilterInvocationContext efiContext, 
        EndpointFilterDelegate next)
    {
        // 获取参数
        var todo = efiContext.GetArgument<Todo>(0);
    
        // 验证
        var validationError = Utilities.IsValid(todo!);
    
        // 模型不符合
        if (!string.IsNullOrEmpty(validationError))
        {
            // 记录日志
            _logger.LogWarning(validationError);
            
            // 跳过endpoint逻辑,返回http请求结果
            return Results.Problem(validationError);
        }
        
        // 模型符合,执行endpoint逻辑
        return await next(efiContext);
    }
}

总结

实现起来很简单,但是考验你的创造能力。