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
Error Accessing Com Components
C# Conditional and (&&) or (||) Precedence
X509Certificate Constructor Exception
What's the How to Minimize to Tray a C# Winforms App
How to Delete a Directory with Read-Only Files in C#
How to Hide a Column (Gridview) But Still Access Its Value
Where's the Datetime 'Z' Format Specifier
Recursive Hierarchy - Recursive Query Using Linq
How to Run Unit Tests (Mstest) in Parallel
Generics - Where T Is a Number
Finding Quoted Strings with Escaped Quotes in C# Using a Regular Expression
How to Find Default Web Browser Using C#
Get Property Name and Type Using Lambda Expression
Problem Parsing Currency Text to Decimal Type
How to Set the Default Xml Namespace for an Xdocument
How to Modify or Delete Items from an Enumerable Collection While Iterating Through It in C#