在对API进行大量重构期间,似乎我改变了一些影响模型绑定/模型验证行为的东西。
我试图调查这些变化,但我不知道变化是由什么引起的。
我有一个MyApiController
继承自ControllerBase
。 MyApiController
的post方法接收一个请求模型(使用默认的API模板创建,而没有HTTPS为您提供典型的ValuesController)。
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Threading.Tasks;
namespace XperimentModelBinding.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class MyApiController : ControllerBase
{
public ILogger<MyApiController> Logger { get; }
public MyApiController(ILogger<MyApiController> logger)
{
Logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
[HttpPost()]
public async Task<IActionResult> PostModel([FromBody] MyCreateRequestModel request)
{
Logger.LogInformation("PostModel: " + JsonConvert.SerializeObject(request, Formatting.None));
if (!ModelState.IsValid) return BadRequest(ModelState);
return Ok();
}
}
}
我使用的模型是:
using System.ComponentModel.DataAnnotations;
namespace XperimentModelBinding
{
public class MyCreateRequestModel
{
[Required]
[StringLength(10)]
public string Name { get; set; }
[Required]
[Range(1, 5)]
public int Value { get; set; }
}
}
启动它并在记录器上设置一个断点。
与邮递员一起测试:
测试1:
{
"Name": "1234567890",
"Value": 1
}
击中断点,返回200 OK(按预期)。
测试2:
{
"Name": null,
"Value": 1
}
断点未命中,返回的模型为:
{
"errors": {
"Name": [
"The Name field is required."
]
},
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "80000006-0000-ff00-b63f-84710c7967bb"
}
预期结果是调用了该方法,命中了换行符,到目前为止,我已经有了响应模型(似乎只包含错误):
{
"Name": [
"The Name field is required."
]
}
改变的是:给定一个无效模型的请求,我的方法被调用,我用ModelState.IsValid
检查是否有错误。太好了,因为我以这种方式创建了自定义响应模型。
现在我的方法不再被调用,并且模型绑定直接返回其自己的模型。
什么改变了我的方法不再被调用?
答案 0 :(得分:4)
它已连接到link的[ApiController]属性
Web API控制器如果具有> [ApiController]属性,则不必检查ModelState.IsValid。在这种情况下,当模型状态无效时,将返回包含问题详细信息的自动HTTP 400响应。有关更多信息,请参阅HTTP 400自动响应。
答案 1 :(得分:1)
您可能想在ConfigureApiBehaviorOptions
中services.AddMvc()
内使用Startup.cs
来为无效的模型请求设置自定义错误消息。
services.AddMvc()
.ConfigureApiBehaviorOptions(options => {
options.InvalidModelStateResponseFactory = actionContext =>
{
var modelState = actionContext.ModelState.Values;
return new BadRequestObjectResult(new ErrorResult(modelState));
};
});
});
并根据需要定义ErrorResult
类,例如:
public class ErrorResult
{
public int code { get; set; }
public string message { get; set; }
public ErrorResult()
{
}
public ErrorResult(ModelStateDictionary.ValueEnumerable modelState)
{
// This will take the error message coming directly from modelState
foreach (var value in modelState)
{
if (value.Errors.Count > 0)
{
code = 900; // Or use a code handler or whatever
message = value.Errors.FirstOrDefault().ErrorMessage;
break;
}
}
}
}