What Does It Mean for a Property to Be [Required] and Nullable

What does it mean for a property to be [Required] and nullable?

The reason for making a property nullable and marked with the [Required] attribute is to protect against under-posting attacks. It also allows you to display an initial empty value in the view rather than the default value for the property. This is typically done with value type properties in view models.

An under-posting attack is where a malicious user modifies the request to omit a value for the property in the request. If the property was DateTime (not nullable), then the DefaultModelBinder will initialize the value its default (01/01/0001) and no ModelState error would be generated. As a result, that value may then be saved even though its not what you may be expecting.

If the property is DateTime? (nullable) and [Required], then if a malicious user did omit the property in the request, then a ModelState error will be generated because a value is expected in the request, and the view would be returned, therefore the invalid data will not be saved.

Refer also Brad Wilson's article Input Validation vs. Model Validation in ASP.NET MVC and the section titled The "Under-Posting" Problem.

Non-nullable property must contain a non-null value when exiting constructor. Consider declaring the property as nullable

The compiler is warning you that the default assignment of your string property (which is null) doesn't match its stated type (which is non-null string).

This is emitted when nullable reference types are switched on, which changes all reference types to be non-null, unless stated otherwise with a ?.

For example, your code could be changed to

public class Greeting
{
public string? From { get; set; }
public string? To { get; set; }
public string? Message { get; set; }
}

to declare the properties as nullable strings, or you could give the properties defaults in-line or in the constructor:

public class Greeting
{
public string From { get; set; } = string.Empty;
public string To { get; set; } = string.Empty;
public string Message { get; set; } = string.Empty;
}

if you wish to retain the properties' types as non-null.

ASP.NET Core [Require] non-nullable types

Solution working with json requests

You cannot validate an already created model instance, because a non-nullable property has always a value (no matter whether it was assigned from json or is a default value). The solution is to report the missing value already during deserialization.

Create a contract resolver

public class RequiredPropertiesContractResolver : DefaultContractResolver
{
protected override JsonObjectContract CreateObjectContract(Type objectType)
{
var contract = base.CreateObjectContract(objectType);

foreach (var contractProperty in contract.Properties)
{
if (contractProperty.PropertyType.IsValueType
&& contractProperty.AttributeProvider.GetAttributes(typeof(RequiredAttribute), inherit: true).Any())
{
contractProperty.Required = Required.Always;
}
}

return contract;
}
}

and then assign it to SerializerSettings:

services.AddMvc()
.AddJsonOptions(jsonOptions =>
{
jsonOptions.SerializerSettings.ContractResolver = new RequiredPropertiesContractResolver();
});

The ModelState is then invalid for non-nullable properties with the [Required] attribute if the value is missing from json.


Example

Json body

var jsonBody = @"{ Data2=123 }"

is invalid for model

class Model
{
[Required]
public int Data { get; set; }

public int Data2 { get; set; }
}

How do I specify a property as required (NOT NULLABLE)?

Simply use nullable types, for example in the class,

public class Foo
{
public int Bar { get; set; }
public int? baz { get; set; }
}

Bar will not be nullable, while Baz will be nullable in the db when use mapping by code.



Related Topics



Leave a reply



Submit