如何在ASP.NET Core 2.0中移除ModelState错误消息的前缀?
解决ASP.NET Core 2.0 API ModelState验证错误带对象前缀的问题
我之前也碰到过这个头疼的问题!ASP.NET Core 2.0默认返回的ModelState验证错误会带上对象前缀(比如[objectPrefix].PropertyName),这完全不符合你API文档里只列PropertyName的约定,消费者反序列化肯定会出问题。下面是几个经过实践验证的解决办法,你可以按需选择:
方法1:自定义ValidationProblemDetails(推荐)
这种方法最规范,因为它基于ASP.NET Core的ValidationProblemDetails(符合RFC 7807问题详情规范),只需要修改错误键名去掉前缀即可:
首先创建一个自定义的ValidationProblemDetails类:
public class CustomValidationProblemDetails : ValidationProblemDetails { public CustomValidationProblemDetails(ActionContext context) : base(context.ModelState) { // 遍历所有错误键,提取最后一个点后的属性名 var cleanedErrors = new Dictionary<string, string[]>(Errors.Count); foreach (var keyValuePair in Errors) { var propertyName = keyValuePair.Key.Split('.').Last(); cleanedErrors.Add(propertyName, keyValuePair.Value); } // 替换原错误集合 Errors.Clear(); foreach (var error in cleanedErrors) { Errors.Add(error); } } }
然后在Startup.cs的ConfigureServices方法中,配置API行为使用这个自定义类:
services.AddMvc() .SetCompatibilityVersion(CompatibilityVersion.Version_2_0) .ConfigureApiBehaviorOptions(options => { options.InvalidModelStateResponseFactory = context => { var problemDetails = new CustomValidationProblemDetails(context); return new BadRequestObjectResult(problemDetails); }; });
这样返回的错误响应里,键就只剩PropertyName了,和你的API文档完全匹配。
方法2:使用Action过滤器全局修改ModelState
如果你更喜欢用过滤器的方式,可以创建一个全局过滤器,在Action执行前清理ModelState的键:
创建过滤器类:
public class RemoveModelStatePrefixFilter : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext context) { if (!context.ModelState.IsValid) { var cleanedModelState = new ModelStateDictionary(); foreach (var keyValuePair in context.ModelState) { var propertyName = keyValuePair.Key.Split('.').Last(); cleanedModelState.Add(propertyName, keyValuePair.Value); } // 替换原ModelState context.ModelState.Clear(); foreach (var item in cleanedModelState) { context.ModelState.Add(item); } } base.OnActionExecuting(context); } }
然后在Startup.cs里注册全局过滤器:
services.AddMvc(options => { options.Filters.Add(new RemoveModelStatePrefixFilter()); }) .SetCompatibilityVersion(CompatibilityVersion.Version_2_0);
或者你也可以只在特定的Controller/Action上添加[RemoveModelStatePrefixFilter]特性,实现局部生效。
方法3:手动处理错误(适合局部场景)
如果只是个别Action需要处理,也可以在Action里手动清理错误键:
[HttpPost] public IActionResult Create([FromBody] YourModel model) { if (!ModelState.IsValid) { var cleanedErrors = new Dictionary<string, string[]>(); foreach (var key in ModelState.Keys) { var propertyName = key.Split('.').Last(); cleanedErrors[propertyName] = ModelState[key].Errors.Select(e => e.ErrorMessage).ToArray(); } return BadRequest(new { Errors = cleanedErrors }); } // 业务逻辑... return Ok(); }
这种方式比较灵活,但缺点是需要每个Action重复写,适合不需要全局处理的场景。
内容的提问来源于stack exchange,提问作者whiskytangofoxtrot
相关产品推荐
相关产品推荐

