英文:
ASP.NET Core 6 WebAPI, invalid model does not reach the action method, instead instantly returns with HTTP 400
问题
我在VS 2022中创建了一个WebAPI项目,使用.NET 6。
我已经在模型的Customer类的CustomerId
属性上添加了[MaxLength(5)]
和[MinLength(5)]
属性。
如果我使用无效数据调用API,比如4或6个字符的CustomerId,那么Insert
方法永远不会被调用。某个地方,管道会立即发送带有正确验证错误消息的HTTP 400响应。
问题
不清楚 ModelState.IsValid
何时为假。我能否配置管道以允许调用该方法?
英文:
I've created a WebAPI project in VS 2022, using .NET 6
I've annotated my model's Customer class CustomerId
property with [MaxLength(5)]
and [MinLength(5)]
attributes.
[Route("api/[controller]")]
[ApiController]
public class CustomerController : ControllerBase
{
private readonly NorthwindContext _ctx;
// ...
[HttpPost]
public Customer Insert(Customer customer)
{
// Method never called. Somewhere the pipeline instantly
// sends the HTTP 400 response with the correct error message.
if (!ModelState.IsValid)
{
}
If I call the API with invalid data, say 4 or 6 lenght CustomerId, then the Insert
method never called. Somewhere the pipeline instantly sends the HTTP 400 response with the correct validation error message
Question
It is not clear, then when will be the ModelState.IsValid false? Can I configure the pipeline to allow the method to be called?
答案1
得分: 2
> 它不清楚,那么 ModelState.IsValid
何时会变为假?
在 MVC 控制器中,简言之,如果您没有在属性上设置任何注释,默认情况下它是必需的,意味着不能为空。所以如果您不传递值,您的 ModelState.IsValid
将始终为假。通常,模型状态代表来自两个子系统的错误。
例如,模型绑定 和 模型验证,这意味着请求首先经过模型验证器,一旦满足条件,它就会路由到特定控制器,否则控制器不会被调用。
因此,在您设置为必需的任何属性且在提交请求时没有传递其值的情况下,您的 ModelState.IsValid
总是为 false
。所以,是的,任何没有可空 ?
的属性都需要在提交请求时传递,否则您的 ModelState.IsValid
将始终为 false
。
让我们考虑一下,您的 Customer 类,您已在 CustomerId 上设置了一些验证约束,如果它不是空的;它首先会到达模型绑定,如果不符合您的条件,它将从那里抛出验证消息,并且不会调用控制器。
因此,如果对非可空属性不传递值或您的属性违反任何条件,它将阻止您提交请求。
> 那么为什么你的 ModelState.IsValid
没有到达?
因为您正在使用 Web API 控制器,在 Web API 控制器中,如果它们有 ApiController 属性,它们不必检查 ModelState.IsValid
。在这种情况下,当模型状态无效时,会自动返回包含错误详细信息的 HTTP 400 响应。
> 我可以配置管道以允许调用该方法吗?
当然可以。在这种情况下,您需要 禁用自动 400 行为。您可能知道在 builder.Services.AddControllers
中有 ConfigureApiBehaviorOptions,您将会得到一个名为 SuppressModelStateInvalidFilter 的属性,我们需要将此属性设置为 true
。请查看以下代码片段:
builder.Services.AddControllers()
.ConfigureApiBehaviorOptions(options =>
{
options.SuppressModelStateInvalidFilter = true;
});
输出:
注意:
如果您想了解更多关于 模型状态验证 和 自动 400 响应 的详细信息,您可以在此处查看我们的官方文档。
英文:
> It is not clear, then when will be the ModelState.IsValid false?
Well, in a nutshell, in MVC controller; if you haven't set any annotation on property by default its required means not null. So if you don't pass the value your ModelState.IsValid will always be false. Usually Model state represents errors that come from two subsystems.
For instances, model binding and model validation which means request firstly goes to the model validator once it meet the condition then it route to the specific controller other than, controller doesn't get hitted.
Thus, your ModelState.IsValid
would always be false when any property you would set required and that's value wouldn't be passed while you submitting request for your scenario Insert
. So, yes any property without nullable ?
would require to pass during request submission, other than your ModelState.IsValid
would always be false
.
Let's consider, your Customer Class you have set few validation constrains on CustomerId if this is not null; it will firstly reach to model binding and if it doesn't meet your condition it will throw validation message from there and it wouldn't hit controller.
So if you don't pass the value for non nullable property or your property violate any condition it will restrict you from submitting request.
> Why then your ModelState.IsValid doesn't reach?
As you are using Web API controller and in Web API controllers don't have to check ModelState.IsValid if they have the ApiController attribute. In that case, an automatic HTTP 400 response containing error details is returned when model state is invalid.
> Can I configure the pipeline to allow the method to be called?
Of course you can. In that scenario, you have to disable the automatic 400 behavior. You might know ConfigureApiBehaviorOptions within builder.Services.AddControllers and you will get a property called SuppressModelStateInvalidFilter we have to set this property to true. Please have a look on following code snippet:
builder.Services.AddControllers()
.ConfigureApiBehaviorOptions(options =>
{
options.SuppressModelStateInvalidFilter = true;
});
Output:
Note:
If you would like to know more details on Model state Validation and automatic 400 response you could check our official document here.
答案2
得分: 0
使用.NET 6/.NET 7中的可空性,发送到 Web API 的数据必须与模型匹配,否则会发生以下情况。
public class MyModel
{
public int SomeId { get; set; }
public int? ForeignId { get; set; }
public string? SomeName { get; set; }
public string RequiredName { get; set; }
}
MyModel myData = new()
{
SomeId = 5,
ForeignId = 9,
SomeName = "Test",
RequiredName = null
}
var myResult = MyWebAPICall(myData);
由于RequiredName被定义为不可为空,Web API 将拒绝它并返回400错误。
您需要检查模型/DTO,并确保您定义的内容与数据源(数据库等)匹配,以便正确保存并专注于需要允许空值的字段。可空性确实迫使您仔细检查所有内容。
英文:
With the nullability in .Net 6/.Net 7, the data you send to the Web API has to match the model or this will happen.
public class MyModel
{
public int SomeId { get; set; }
public int? ForeignId { get; set; }
public string? SomeName { get; set; }
public string RequiredName{ get; set; }
}
MyModel myData = new()
{
SomeId = 5,
ForeignId = 9,
SomeName = "Test",
RequiredName = null
}
var myResult = MyWebAPICall(myData);
Since the RequiredName is defined as not nullable, the Web API will reject it and send back the 400.
You have to go through the models / DTO's and make sure what you defined matches your data source (database, etc.) so it will save properly and focus on what fields need to allow nulls. The nullability really forces you to go through everything.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论