Why is this an issue?
When a request omits a non-nullable value-type property, it can receive its default value, such as 0 for an int. The
handler then cannot distinguish missing input from an explicit zero. Make the property nullable when absence is allowed, or require its presence with
validation supported by your input format and serializer.
For example, {} and {"quantity": 0} both produce Quantity == 0 with the model below. This is called
under-posting.
How to fix it
For a required value, one option is a nullable property with [Required]. Missing input remains null, which fails model
validation. The example assumes an ASP.NET Core controller receiving the model with [FromBody] and running model validation. With
[ApiController], an invalid model normally produces an automatic HTTP 400 response; otherwise, check ModelState.IsValid
before using the input.
Code examples
Noncompliant code example
public class OrderRequest
{
public int Quantity { get; set; } // Noncompliant: omitted input becomes zero
}
Compliant solution
using System.ComponentModel.DataAnnotations;
public class OrderRequest
{
[Required]
public int? Quantity { get; set; }
}
This correction rejects both omission and explicit null, while accepting zero. Add value validation if zero is not a valid
quantity.
Choose the input contract
- Missing input is allowed: use a nullable value type such as
int?and handlenullexplicitly. This alone does not reject missing input or distinguish omission from an explicitnull. - A non-null value is required: use a nullable value type with
[Required]and enforce model validation.[Required]on a non-nullableintalone does not detect omission, because zero is a value. - A JSON property must be present: with System.Text.Json in .NET 7 or later, use
[System.Text.Json.Serialization.JsonRequired]or a C# 11requiredproperty, with a compatible serializer configuration. Missing required properties cause deserialization to fail. Check support for the serialization mode you use. - A supplied value must be in a domain range: add value validation, such as
[Range(1, 100)]. Choose presence and null-handling rules separately: a range that accepts the default value cannot distinguish omission from that value.
required also affects C# object initialization; it is not a general HTTP validation mechanism. JSON attributes apply to the
corresponding serializer, not to form or query model binding. When using Newtonsoft.Json, use its own required-property settings and distinguish
required presence from whether null is allowed.
If an omitted property intentionally means its default value, document that API contract. A detection exception is not evidence that incoming data has been validated.
Non-reporting cases
This rule does not raise an issue when properties are decorated with the following attributes:
- ValidateNever
- JsonProperty(Required = Required.Always)
- JsonProperty(Required = Required.AllowNull)
- Newtonsoft.Json.JsonIgnore
- Newtonsoft.Json.JsonRequired
- System.Text.Json.Serialization.JsonRequired
- System.Text.Json.Serialization.JsonIgnore
- Range
- BindNever
Additionally, this rule does not raise for properties in model classes that are not in the same project as the Controller class that references them. This is due to a limitation of Roslyn (see here).
Some attributes above skip validation or binding rather than require input. In particular, do not add [ValidateNever],
[BindNever], or an ignore attribute merely to silence the issue. Test omitted input, explicit null, the default value, and
valid values against the endpoint’s actual input format.
Resources
Documentation
- Microsoft Learn - Model Binding in ASP.NET Core
- Microsoft Learn - RequiredAttribute Class
- Microsoft Learn - Required properties in System.Text.Json
- Microsoft Learn - Nullable Value Types in .NET