I'm using ASP.NET Core 2.0, and I have a request object annotated like this:
public class MyRequest
{
[Required]
public Guid Id { get; set; }
[Required]
public DateTime EndDateTimeUtc { get; set; }
[Required]
public DateTime StartDateTimeUtc { get; set; }
}
And in my controller:
public async Task<IActionResult> HandleRequest([FromBody] MyRequest request)
{ /* ... */ }
I noticed an issue with model binding: When I send a request containing the header Content-Type
set to application/json
and a an empty body, as I expect, the request
in my controller is null
and ModelState.IsValid
is false
.
But when I have a body like this:
{
"hello": "a-string-value!"
}
my request
is NOT null
, it has default values for everything, and ModelState.IsValid
is true
This is happening of course while I'm missing all the Required
properties, and the only existing one's name doesn't match a property there (even the type for this single parameter is string
, which doesn't match any type on my model).
So in a way, those Required
attributes seem to be working if there's nothing in my request, but they don't do anything if my request is not empty!
As I was preparing this question, I noticed that there's also a JsonRequired
attribute, and it seems to take care of the properties being present.
So, what's the difference between Required
and JsonRequired
?
System. Text. Json focuses primarily on performance, security, and standards compliance. It has some key differences in default behavior and doesn't aim to have feature parity with Newtonsoft.
JsonPropertyAttribute indicates that a property should be serialized when member serialization is set to opt-in. It includes non-public properties in serialization and deserialization. It can be used to customize type name, reference, null, and default value handling for the property value.
[FromBody] attributeThe ASP.NET Core runtime delegates the responsibility of reading the body to an input formatter. Input formatters are explained later in this article. When [FromBody] is applied to a complex type parameter, any binding source attributes applied to its properties are ignored.
Yet Newtonsoft. Json was basically scrapped by Microsoft with the coming of . NET Core 3.0 in favor of its newer offering designed for better performance, System. Text.
For correct work of Required
attribute, you should make the properties nullable:
public class MyRequest
{
[Required]
public Guid? Id { get; set; }
[Required]
public DateTime? EndDateTimeUtc { get; set; }
[Required]
public DateTime? StartDateTimeUtc { get; set; }
}
Now if you send request with missing Id
, EndDateTimeUtc
or StartDateTimeUtc
, corresponding field will be set to null
, ModelState.IsValid
will be set to false
and ModelState
will contain error(s) description, e.g. The EndDateTimeUtc field is required.
JsonRequired
attribute is specific to JSON.Net. It plays during deserialization, while Required
attribute (as other attributes from System.ComponentModel.DataAnnotations
namespace) plays after model is deserialized, during model validation. If JsonRequired
attribute is violated, the model will not be deserialized at all and corresponding action parameter will be set to null
.
The main reason why you should prefer Required
attribute over JsonRequired
is that JsonRequired
will not work for other content types (like XML). Required
in its turn is universal since it's applied after the model is deserialized.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With