问题
I am trying to validate that if a property / field is completely left off on a request that the ModelState is invalid and a BadRequest is sent back to the client, however I am struggling with handling of non-nullable types in request bodies.
Works for nullable types
[Required] public string NullableString { get; set; }
Works for non-nullable and nullable parameters
public IActionResult RequiredNonNullableIntQueryString([Required]int nonNullableInt)
public IActionResult RequiredNullableStringQueryString([Required]string nullableString)
However, it does NOT work for non-nullable types in request bodies
public IActionResult RequiredNonNullableIntBody([FromBody]NonNullablesRequest request)
public class NonNullablesRequest
{
[Required] // I have also tried [BindRequired] with the same result.
public int NonNullableInt { get; set; }
}
I have read:
- Microsoft documentation - Model Validation # [Required] validation on the server
- Good article on [Required] and [BindRequired] in ASP.NET Core MVC
The Microsoft documentation states:
The validation system in .NET Core 3.0 and later treats non-nullable parameters or bound properties as if they had a [Required] attribute. Value types such as decimal and int are non-nullable.
That's cool... However later says
On the server, a required value is considered missing if the property is null. A non-nullable field is always valid, and the [Required] attribute's error message is never displayed.
Why? This really doesn't seem to make sense. Why make sure all non-nullables are required but then ignore errors if they were not supplied?
I know many suggestions indicating that one can do the hacky workaround of the following, whereby one sets the required parameter as nullable. To me this does not seem like a reasonable solution.
public class NonNullablesRequest
{
[Required]
public int? NonNullableInt { get; set; }
}
This just feels wrong.
- The datatype is not accurately representing the expectations of the request arriving
- One has to use
.HasValue
and.Value
every time one is accessing the property to avoid "Possible Null" warnings. - Seems like an anti-pattern to C# 8.0's Nullable reference types (C# reference)
Is there a way to configure the ModelBinding to invalidate the ModelState if non-nullable types are not supplied?
Edit 1:
It seems there is quite some debate: ASP.NET Core [Require] non-nullable types I am not sure I agree with Chris Pratt. It is not that we expect the value to not be supplied. In fact the opposite, I want ensure the caller gives me the value. But one has to be defensive against a consumer not supplying the adequate data and therefore the system should reject the requests with a 400 BadRequest.
From this then the expected result is an int
not an int?
. If no data was supplied the ModelBinder should indicate that the ModelState is invalid.
I can, however, see the challenge where there are two parts 1) Deserialization and then 2) ModelBinding.
回答1:
You could use two different classes for this.
One that represents what your web-application sends to the backend and another that represents your domain model (e.g. entity model).
Http Transport Object
public class YourWebAppDto
{
[Required]
public int? NonNullableInt { get; set; }
}
Domain Model Object
public class YourDomainModelObject
{
public int NonNullableInt { get; set; }
}
By separating those two concerns, you can keep your domain model clean while addressing the potential invalid input of your web application.
Of course, you need a mapping between the two. We use automapper for this.
I know, this does not directly answer your question but it might help as an other way of looking at things.
Cheers, Mike
来源:https://stackoverflow.com/questions/62279845/validating-non-nullable-property-in-body-as-required-aspnetcore-3-1