为什么 ModelState returns 不同的结果以及如何解决?
Why ModelState returns different result and how to fix it?
Asp.net 核心 3.1 WebApi。
我有一个具有所需属性的模型。
1.If 模型无效,则响应包含数据
喜欢 :
{
"errors": {
"Name": [
"Update model can't have all properties as null."
],
"Color": [
"Update model can't have all properties as null."
]
},
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "|f032f1c9-4c36d1e62aa60ead."
}
这看起来很适合我。
但是如果我向 modelState.AddModelError("statusId", "Invalid order status id.") 添加一些自定义验证,那么它 returns 不同的结构:
[
{
"childNodes": null,
"children": null,
"key": "statusId",
"subKey": {
"buffer": "statusId",
"offset": 0,
"length": 8,
"value": "statusId",
"hasValue": true
},
"isContainerNode": false,
"rawValue": "11202",
"attemptedValue": "11202",
"errors": [
{
"exception": null,
"errorMessage": "Invalid order status id."
}
],
"validationState": 1
}
]
看起来 ModelState.IsValid 对于控制器来说也不再是实际的了,因为错误的请求甚至在以无效模式进入控制器之前就已返回。或者是否有一些通过 ModelSate 进行全局验证的标志?
为什么结构不同?
怎么让它一样呢?
如何强制进入 api 控制器内部的 ModelState.IsValid 方法,因为它在 MVC 中工作?
更新:
[Route("....")]
[Authorize]
[ApiController]
public class StatusesController : ApiControllerBase
{
[HttpPut, Route("{statusId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status409Conflict)]
[Produces("application/json")]
public async Task<ObjectResult> UpdateStatusAsync(int statusId, [FromBody] StatusUpdateDto orderStatusUpdateDto)
{
int companyId = User.Identity.GetClaimValue<int>(ClaimTypes.CompanyId);
const string errorNotFound = "There is not order status with this id for such company";
if (statusId <= 0)
{
Logger.LogError(errorNotFound);
ModelState.AddErrorModel(nameof(statusId), "Invalid order status id")
throw new NotFound(ModelState);
}
if (orderStatusUpdateDto == null)
{
const string error = "Invalid (null) order status can't be added";
Logger.LogError(error);
throw new ArgumentNullException(error);
}
if (ModelState.IsValid == false) // also this code is always true or returns 400 before this line
{
return BadRequest(ModelState);
}
....
return result;
}
}
ApiController
属性向控制器添加了一些特定的固执己见的行为。如果模型无效,其中之一是 return 400 错误。
可以禁用此行为,但仅限于全局级别。
services.AddControllers()
.ConfigureApiBehaviorOptions(options =>
{
options.SuppressModelStateInvalidFilter = true;
});
我认为你有以下选择:
- 禁用此行为并自行检查
ModelState.IsValid
。使用 ValidationProblem
方法产生相同的响应
- 将此检查添加到模型的验证器
- 保持原样。但是在控制器方法中使用
ValidationProblem
来 return 验证错误。
Asp.net 核心 3.1 WebApi。
我有一个具有所需属性的模型。
1.If 模型无效,则响应包含数据 喜欢 :
{
"errors": {
"Name": [
"Update model can't have all properties as null."
],
"Color": [
"Update model can't have all properties as null."
]
},
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "|f032f1c9-4c36d1e62aa60ead."
}
这看起来很适合我。
但是如果我向 modelState.AddModelError("statusId", "Invalid order status id.") 添加一些自定义验证,那么它 returns 不同的结构:
[
{
"childNodes": null,
"children": null,
"key": "statusId",
"subKey": {
"buffer": "statusId",
"offset": 0,
"length": 8,
"value": "statusId",
"hasValue": true
},
"isContainerNode": false,
"rawValue": "11202",
"attemptedValue": "11202",
"errors": [
{
"exception": null,
"errorMessage": "Invalid order status id."
}
],
"validationState": 1
}
]
看起来 ModelState.IsValid 对于控制器来说也不再是实际的了,因为错误的请求甚至在以无效模式进入控制器之前就已返回。或者是否有一些通过 ModelSate 进行全局验证的标志?
为什么结构不同? 怎么让它一样呢? 如何强制进入 api 控制器内部的 ModelState.IsValid 方法,因为它在 MVC 中工作?
更新:
[Route("....")]
[Authorize]
[ApiController]
public class StatusesController : ApiControllerBase
{
[HttpPut, Route("{statusId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status409Conflict)]
[Produces("application/json")]
public async Task<ObjectResult> UpdateStatusAsync(int statusId, [FromBody] StatusUpdateDto orderStatusUpdateDto)
{
int companyId = User.Identity.GetClaimValue<int>(ClaimTypes.CompanyId);
const string errorNotFound = "There is not order status with this id for such company";
if (statusId <= 0)
{
Logger.LogError(errorNotFound);
ModelState.AddErrorModel(nameof(statusId), "Invalid order status id")
throw new NotFound(ModelState);
}
if (orderStatusUpdateDto == null)
{
const string error = "Invalid (null) order status can't be added";
Logger.LogError(error);
throw new ArgumentNullException(error);
}
if (ModelState.IsValid == false) // also this code is always true or returns 400 before this line
{
return BadRequest(ModelState);
}
....
return result;
}
}
ApiController
属性向控制器添加了一些特定的固执己见的行为。如果模型无效,其中之一是 return 400 错误。
可以禁用此行为,但仅限于全局级别。
services.AddControllers()
.ConfigureApiBehaviorOptions(options =>
{
options.SuppressModelStateInvalidFilter = true;
});
我认为你有以下选择:
- 禁用此行为并自行检查
ModelState.IsValid
。使用ValidationProblem
方法产生相同的响应 - 将此检查添加到模型的验证器
- 保持原样。但是在控制器方法中使用
ValidationProblem
来 return 验证错误。