.NET 6 WebAPI:如何让Action过滤器在[ApiController]返回400前执行
确保自定义过滤器在[ApiController]之前执行的两种方案
在.NET 6中,[ApiController]属性会自动注入一个ModelStateInvalidFilter(负责验证失败时返回HTTP 400的过滤器),它的默认执行顺序(Order)为-2000,且属于ActionFilter类型。要让你的日志过滤器优先执行,有两种直接可行的方案:
方案一:利用ResourceFilter的天然优先级
过滤器的执行顺序规则是:ResourceFilter > ActionFilter > ExceptionFilter,而[ApiController]的验证逻辑是通过ActionFilter实现的。因此只需将日志过滤器改为实现IAsyncResourceFilter(异步)或IResourceFilter(同步),就能天然在ApiController的验证逻辑之前执行,无需调整Order数值。
代码示例
自定义日志过滤器:
public class ValidationLoggingFilter : IAsyncResourceFilter { private readonly ILogger<ValidationLoggingFilter> _logger; public ValidationLoggingFilter(ILogger<ValidationLoggingFilter> logger) { _logger = logger; } public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next) { // 提前检查模型验证状态并记录日志 if (!context.ModelState.IsValid) { var errorMessages = context.ModelState.Values .SelectMany(v => v.Errors) .Select(e => e.ErrorMessage); _logger.LogWarning("用户请求验证失败:{Errors}", string.Join("; ", errorMessages)); } // 继续执行后续流程(包括ApiController的验证逻辑) await next(); } }
在Program.cs中注册过滤器:
var builder = WebApplication.CreateBuilder(args); // 添加控制器并注册自定义过滤器 builder.Services.AddControllers(options => { options.Filters.Add<ValidationLoggingFilter>(); }); var app = builder.Build(); // 中间件配置... app.MapControllers(); app.Run();
方案二:调整ActionFilter的Order值
如果坚持使用ActionFilter类型的过滤器,可以通过实现IOrderedFilter接口,设置一个比-2000更小的Order值(比如-2001),让它的优先级高于ApiController的内置验证过滤器。
代码示例
自定义日志过滤器:
public class ValidationLoggingFilter : IAsyncActionFilter, IOrderedFilter { private readonly ILogger<ValidationLoggingFilter> _logger; public ValidationLoggingFilter(ILogger<ValidationLoggingFilter> logger) { _logger = logger; } // 设置Order为-2001,比ApiController内置过滤器的-2000更早执行 public int Order => -2001; public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { if (!context.ModelState.IsValid) { var errorMessages = context.ModelState.Values .SelectMany(v => v.Errors) .Select(e => e.ErrorMessage); _logger.LogWarning("用户请求验证失败:{Errors}", string.Join("; ", errorMessages)); } await next(); } }
注册方式与方案一一致,全局注册到控制器选项中即可。
额外说明
如果要在单个控制器或Action上添加过滤器,需使用[ServiceFilter(typeof(ValidationLoggingFilter))]代替直接标记[ValidationLoggingFilter]——因为过滤器依赖了ILogger,需要从DI容器中获取实例。
内容的提问来源于stack exchange,提问作者verbalxd
相关产品推荐
相关产品推荐

