.NET Core 7 Minimal API:通用过滤器中如何区分服务与POST请求体
问题描述
我正在使用.NET Core 7 Minimal API,需要记录POST请求的请求体。当前代码通过给请求体DTO添加自定义RequestBodyAttribute来识别请求体,但这种方式容易因遗漏标记出错;通过参数位置判断也有风险;想通过检查[FromBody]特性来识别,但不知道在过滤器中如何获取该信息。现有代码如下:
端点配置
var endpoints = app.MapGroup("api/v1") .AddEndpointFilter<RequestResponseLogFilter>(); endpoints.MapPost("/endpoint", async ([FromServices] ServiceA serviceA, [FromServices] ServiceB serviceB, [FromBody] MyRequest request) => await MyEndpoint.DoSomething(serviceA, serviceB, request));
自定义特性与DTO
public class RequestBodyAttribute : Attribute { } [RequestBody] public class MyRequest { }
现有日志过滤器
public class RequestResponseLogFilter : IEndpointFilter { public async ValueTask<object?> InvokeAsync(EndpointFilterInvocationContext context, EndpointFilterDelegate next) { var httpContext = context.HttpContext; var logger = httpContext.RequestServices.GetService<ILogger>()!; object? requestBody = context.Arguments.FirstOrDefault(a => a?.GetType().GetCustomAttribute<RequestBodyAttribute>() != null); logger.Information("{@Request}", LogHelper.PrepareRequest(httpContext, requestBody)); var stopwatch = Stopwatch.StartNew(); var result = await next(context); stopwatch.Stop(); logger.Information("{@Response}", LogHelper.PrepareResponse(httpContext, result, stopwatch.Elapsed)); return result; } }
解决方案
可以通过EndpointFilterInvocationContext的MethodInfo获取端点方法的参数元数据,结合[FromBody]特性精准定位请求体参数,无需额外标记或依赖参数位置。修改后的过滤器代码如下:
using Microsoft.AspNetCore.Mvc; using System.Reflection; public class RequestResponseLogFilter : IEndpointFilter { public async ValueTask<object?> InvokeAsync(EndpointFilterInvocationContext context, EndpointFilterDelegate next) { var httpContext = context.HttpContext; var logger = httpContext.RequestServices.GetService<ILogger>()!; // 获取方法参数信息,匹配带[FromBody]特性的参数 var methodParams = context.MethodInfo.GetParameters(); object? requestBody = null; for (int i = 0; i < methodParams.Length; i++) { if (methodParams[i].GetCustomAttribute<FromBodyAttribute>() != null) { requestBody = context.Arguments[i]; break; // 通常POST请求只有一个FromBody参数,找到后直接跳出 } } logger.Information("{@Request}", LogHelper.PrepareRequest(httpContext, requestBody)); var stopwatch = Stopwatch.StartNew(); var result = await next(context); stopwatch.Stop(); logger.Information("{@Response}", LogHelper.PrepareResponse(httpContext, result, stopwatch.Elapsed)); return result; } }
说明
- 利用
context.MethodInfo.GetParameters()获取端点方法的所有参数元数据,遍历每个参数检查是否带有[FromBody]特性 - 通过参数索引对应到
context.Arguments中的实参,精准获取请求体对象 - 无需给DTO添加任何自定义特性,也不依赖参数位置,完全基于ASP.NET Core原生的参数绑定特性判断,避免遗漏或位置错误的问题
内容的提问来源于stack exchange,提问作者Pavel
相关产品推荐
相关产品推荐

