与 ModelState 验证不一致的行为 asp.net 核心 api
Inconsistent behaviour with ModelState validation asp.net core api
当 asp.net 核心 api 验证对象时以及当我手动添加模型错误并调用 BadRequest(ModelState)
时,我得到了不一致的行为
例如,我的控制器中有这两个端点
[HttpPost]
public IActionResult Post(MyModel model)
{
return Ok();
}
[HttpPost]
[Route("test")]
public IActionResult OtherPost()
{
ModelState.AddModelError("field", "error");
return BadRequest(ModelState);
}
MyModel 是:
public class MyModel
{
[Required]
[MinLength(10)]
public string MyProperty { get; set; }
}
当我调用带有空主体的第一个端点时,我不需要验证 ModelState,因为框架会自动执行并给出此响应:
{
"errors":{"MyProperty":["The MyProperty field is required."]},
"title":"One or more validation errors occurred.",
"status":400,
"traceId":"80000005-0000-ff00-b63f-84710c7967bb"
}
使用第二个控制器我得到这个:
{"field":["error"]}
我是不是使用了错误的方法来向 ModelState 添加错误,或者这是一个已知问题?
ApiController 执行自动模型状态验证和 returns 出现错误时的响应。
如果您想要类似的行为,您可以禁用自动验证和响应:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<ApiBehaviorOptions>(options =>
{
options.SuppressModelStateInvalidFilter = true;
});
}
See here 了解更多信息。希望对您有所帮助!
- 如果您更喜欢自己验证模型状态并期望得到与
ApiController
绑定失败消息完全相同的结果,您可以如下所示:
public IActionResult Other2Post()
{
ModelState.AddModelError("field", "error");
var problemDetails = new ValidationProblemDetails(ModelState)
{
Status = StatusCodes.Status400BadRequest,
};
var traceId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
problemDetails.Extensions["traceId"] = traceId;
var result = new BadRequestObjectResult(problemDetails);
result.ContentTypes.Add("application/problem+json");
result.ContentTypes.Add("application/problem+xml");
return result;
}
- 或者如果您不需要
traceId
,您可以简单地 return BadRequest
of ValidationProblemDetails
:
ModelState.AddModelError("field", "error");
var problemDetails = new ValidationProblemDetails(ModelState)
{
Status = StatusCodes.Status400BadRequest,
};
return BadRequest(problemDetails);
演示:
有关详细信息,请参阅 the related source code here and here。
你可以使用
public IActionResult Post(SomeModel model)
{
ModelState.AddModelError("key", "message");
return ValidationProblem(ModelState);
}
此代码产生类似的响应,只是没有 traceId。
UPD1: 对于asp.net core 3.1 it returns traceId
当 asp.net 核心 api 验证对象时以及当我手动添加模型错误并调用 BadRequest(ModelState)
时,我得到了不一致的行为例如,我的控制器中有这两个端点
[HttpPost]
public IActionResult Post(MyModel model)
{
return Ok();
}
[HttpPost]
[Route("test")]
public IActionResult OtherPost()
{
ModelState.AddModelError("field", "error");
return BadRequest(ModelState);
}
MyModel 是:
public class MyModel
{
[Required]
[MinLength(10)]
public string MyProperty { get; set; }
}
当我调用带有空主体的第一个端点时,我不需要验证 ModelState,因为框架会自动执行并给出此响应:
{
"errors":{"MyProperty":["The MyProperty field is required."]},
"title":"One or more validation errors occurred.",
"status":400,
"traceId":"80000005-0000-ff00-b63f-84710c7967bb"
}
使用第二个控制器我得到这个:
{"field":["error"]}
我是不是使用了错误的方法来向 ModelState 添加错误,或者这是一个已知问题?
ApiController 执行自动模型状态验证和 returns 出现错误时的响应。
如果您想要类似的行为,您可以禁用自动验证和响应:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<ApiBehaviorOptions>(options =>
{
options.SuppressModelStateInvalidFilter = true;
});
}
See here 了解更多信息。希望对您有所帮助!
- 如果您更喜欢自己验证模型状态并期望得到与
ApiController
绑定失败消息完全相同的结果,您可以如下所示:
public IActionResult Other2Post()
{
ModelState.AddModelError("field", "error");
var problemDetails = new ValidationProblemDetails(ModelState)
{
Status = StatusCodes.Status400BadRequest,
};
var traceId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
problemDetails.Extensions["traceId"] = traceId;
var result = new BadRequestObjectResult(problemDetails);
result.ContentTypes.Add("application/problem+json");
result.ContentTypes.Add("application/problem+xml");
return result;
}
- 或者如果您不需要
traceId
,您可以简单地 returnBadRequest
ofValidationProblemDetails
:
ModelState.AddModelError("field", "error");
var problemDetails = new ValidationProblemDetails(ModelState)
{
Status = StatusCodes.Status400BadRequest,
};
return BadRequest(problemDetails);
演示:
有关详细信息,请参阅 the related source code here and here。
你可以使用
public IActionResult Post(SomeModel model)
{
ModelState.AddModelError("key", "message");
return ValidationProblem(ModelState);
}
此代码产生类似的响应,只是没有 traceId。
UPD1: 对于asp.net core 3.1 it returns traceId