.NET 6 Web API配置验证错误返回application/problem+json
解决方案
问题原因
返回Content-Type不符合预期、丢失错误详情的核心原因:
- 直接将
ModelState对象传入UnprocessableEntity/UnprocessableEntityObjectResult时,框架会把ModelState的键值对序列化为普通JSON,不会包装为RFC 7807标准的ProblemDetails结构,默认返回application/json类型 - 无参
UnprocessableEntity()不会自动携带模型校验错误信息,必然丢失校验详情 - 自定义的
ValidationFilterAttribute和控制器内手动判断ModelState的逻辑,覆盖了.NET 6 Web API自带的标准校验响应处理逻辑
实现步骤
方法一:使用框架自带的ApiBehavior配置(推荐)
- 首先删除控制器中手动判断
ModelState.IsValid返回的代码,以及你自定义的ValidationFilterAttribute,避免重复逻辑覆盖默认配置 - 在
Program.cs中配置控制器服务,自定义模型校验失败的响应工厂,强制返回application/problem+json格式的标准校验响应,同时保留所有错误详情,状态码设为需要的422:
var builder = WebApplication.CreateBuilder(args); // 其他服务注入逻辑... builder.Services.AddControllers() .ConfigureApiBehaviorOptions(options => { // 自定义模型校验失败的响应逻辑 options.InvalidModelStateResponseFactory = context => { // 将模型校验错误包装为标准ValidationProblemDetails var problemDetails = new ValidationProblemDetails(context.ModelState) { Status = StatusCodes.Status422UnprocessableEntity, Title = "参数校验失败", Instance = context.HttpContext.Request.Path }; return new UnprocessableEntityObjectResult(problemDetails) { // 强制指定响应Content-Type为application/problem+json ContentTypes = { "application/problem+json" } }; }; }); // 可选:全局添加ProblemDetails服务,让其他异常场景也返回标准problem+json格式 builder.Services.AddProblemDetails(); var app = builder.Build(); // 其他中间件配置逻辑... app.Run();
配置完成后,所有标记[ApiController]的接口,在参数校验失败时都会自动返回带完整错误详情的application/problem+json响应,不需要在控制器里写重复判断逻辑。
方法二:保留自定义ValidationFilterAttribute的改法
如果一定要保留自定义过滤器,不要直接将ModelState传入返回结果,而是先包装为ValidationProblemDetails对象,再指定Content-Type:
public class ValidationFilterAttribute : IActionFilter { public void OnActionExecuting(ActionExecutingContext context) { if (!context.ModelState.IsValid) { var problemDetails = new ValidationProblemDetails(context.ModelState) { Status = StatusCodes.Status422UnprocessableEntity, Title = "参数校验失败" }; context.Result = new UnprocessableEntityObjectResult(problemDetails) { ContentTypes = { "application/problem+json" } }; } } public void OnActionExecuted(ActionExecutedContext context) { } }
如果需要在控制器内手动返回校验错误,也按照同样的写法,不要直接传ModelState:
if (!ModelState.IsValid) { var problem = new ValidationProblemDetails(ModelState) { Status = StatusCodes.Status422UnprocessableEntity, Title = "参数校验失败" }; return new UnprocessableEntityObjectResult(problem) { ContentTypes = { "application/problem+json" } }; }
效果说明
返回的响应结构为标准RFC 7807格式,errors字段下包含所有字段的校验错误详情,响应头Content-Type为application/problem+json,完全符合需求。
内容的提问来源于stack exchange,提问作者Steve
相关产品推荐
相关产品推荐

