.NET Core 6 Minimal API基于OpenApi的请求验证问题咨询
问题解答
1. 此场景下处理验证的最佳实践
在.NET 6 Minimal API中,默认不会自动触发System.ComponentModel.DataAnnotations的验证逻辑,这就是案例1中超范围w值能返回200的核心原因。推荐两种在请求进入路由处理前完成校验的方案:
方案一:添加端点过滤器(官方推荐轻量方式)
直接在目标端点上绑定验证逻辑,代码侵入性低:
app.MapPut("/resolutions", (Resolution res) => { return Results.Ok(new { Message = "Resource updated successfully" }); }) .AddEndpointFilter(async (context, next) => { var resolution = context.Arguments.OfType<Resolution>().FirstOrDefault(); var validationContext = new ValidationContext(resolution); var validationResults = new List<ValidationResult>(); if (!Validator.TryValidateObject(resolution, validationContext, validationResults, validateAllProperties: true)) { var errorDict = validationResults .GroupBy(r => r.MemberNames.FirstOrDefault() ?? "Unknown") .ToDictionary(g => g.Key, g => g.Select(r => r.ErrorMessage).ToArray()); return Results.ValidationProblem(errorDict); } return await next(context); }) .Produces(200) .Produces(400) // 补充声明400状态码 .Produces(404) .WithName("PutResolution");
配置后,案例1的超范围请求会返回400状态码,同时携带具体的字段错误信息。
方案二:注册全局验证过滤器
如果多个端点都需要验证逻辑,可全局注册过滤器避免重复代码:
builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); // 注册全局验证过滤器 builder.Services.AddScoped<EndpointFilterDelegate>(sp => { return async (context, next) => { foreach (var arg in context.Arguments) { if (arg == null) continue; var validationContext = new ValidationContext(arg); var validationResults = new List<ValidationResult>(); if (!Validator.TryValidateObject(arg, validationContext, validationResults, validateAllProperties: true)) { var errorDict = validationResults .GroupBy(r => r.MemberNames.FirstOrDefault() ?? "Unknown") .ToDictionary(g => g.Key, g => g.Select(r => r.ErrorMessage).ToArray()); return Results.ValidationProblem(errorDict); } } return await next(context); }; }); // 后续端点无需单独配置验证 app.MapPut("/resolutions", (Resolution res) => { return Results.Ok(new { Message = "Resource updated successfully" }); }) .Produces(200) .Produces(400) .Produces(404) .WithName("PutResolution");
2. 是否可以基于动态生成的OpenApi契约验证请求?
可以实现,但无需额外复杂配置——默认Swashbuckle会根据DataAnnotations自动生成包含范围、类型、必填约束的OpenApi Schema,通过上面的端点过滤器就能间接实现“基于契约验证”的效果(因为过滤器的规则和OpenApi Schema的约束同源)。
如果要直接基于OpenApi Schema做校验,可借助Json Schema验证库(如Newtonsoft.Json.Schema)配合中间件实现:
- 从Swagger文档中匹配当前请求对应的OpenApi Schema;
- 对请求Body执行Schema校验;
- 校验失败时返回400状态码和具体错误信息。
不过这种方式复杂度较高,大部分场景下,基于DataAnnotations的端点过滤器已经能满足需求。
另外,针对案例2的数据类型错误,可通过全局异常处理统一返回友好提示:
app.UseExceptionHandler(exceptionHandlerApp => { exceptionHandlerApp.Run(async context => { var exception = context.Features.Get<IExceptionHandlerFeature>()?.Error; if (exception is JsonException) { context.Response.StatusCode = StatusCodes.Status400BadRequest; context.Response.ContentType = "application/json"; await context.Response.WriteAsJsonAsync(new { Message = "请求数据类型错误,请检查参数格式" }); } }); });
内容的提问来源于stack exchange,提问作者Fuczak
相关产品推荐
相关产品推荐

