I thought that the new C# 8.0 feature – non-nullable reference types is just an IntelliSense feature powered by Roslyn that prevents null reference exceptions. I was wrong. It may affect how your application works in many ways. More specifically, everything that use reflection can start behaving differently. It includes also ASP.NET Core routing. Some bindings can stop working when no additional code changes are applied.
Let us see it on example. Differentiation between nullable and non-nullable reference types can be turned on in .csproj file:
<PropertyGroup>
<Nullable>enable</Nullable>
</PropertyGroup>
Do not think it does not apply either on the annotations value:
<PropertyGroup>
<Nullable>annotations</Nullable>
</PropertyGroup>
The route may look like this:
[HttpPost]
public async Task MyMethod([Required, FromBody] MyContract contract) {
...
}
public class MyContract {
public string MyValue { get; set; }
...
}
MyValue does not have Required attribute so even if the JSON request does not have myValue property, binding between HTTP request and MyMethod will work. That is true unless you enable nullable reference types. Once you do that, you must declare that MyValue can be null because it is the default value when the property is not included in the request. When the type is not nullable, the default value cannot be applied, and the property is required automatically by syntax. Required attribute in this case would be redundant. It became redundant also in contract parameter declaration.
public class MyContract {
public string? MyValue { get; set; }
...
}
MyContract above has MyValue type of string? which means that the property is optional. The contract will continue to work like before when nullable reference types were enabled.