When using DataAnnotations to validate models for incoming controller requests, non-nullable reference types are implicitly treated as required unless you declare them as nullable (i.e. string? instead of string).
public class MyExampleModel
{
// Cannot be null! Equivalent to having [Required(AllowEmptyStrings = true)] on it
public string PropertyName { get; set; }
// Allowed to be null! No validation errors occur.
public string? OtherProp { get; set; }
}
This behavior results in an expected validation error of The PropertyName field is required when hitting the endpoint via Postman / etc.
However, when using the Validator class in a unit testing scenario, this implicit check is not correctly reported when passing null for the string PropertyName property.
using System.ComponentModel.DataAnnotations;
using FluentAssertions;
using Xunit;
namespace MyNamespace.Tests;
public class TestingValidationOfMyExampleModel
{
[Fact]
public void ShouldHaveErrorWhenPropertyNameIsNull()
{
var model = new MyExampleModel(); // model.PropertyName is null.
var validationResults = new List<ValidationResult>();
var validationContext = new ValidationContext(model, null, null);
// No errors returned! validationResults remains empty.
Validator.TryValidateObject(model, validationContext, validationResults, true);
validationResults.Should().HaveCount(1); // Fails!
}
}
Is there some way to configure the static System.ComponentModel.DataAnnotations.Validator class so that it also makes this implicit check?
The
DataAnnotations.Validatorwill validate exclusively based on the applied data annotation attributes. It's has been around for a very long time, and it's heavily used by various frameworks/tools (e.f. EF, Winforms, MVC). Modifying the behavior would break everything.On the other hand, the ASP.NET Core team decided to add support for NRT in the MVC's model binding and validation middleware. They did it by just adding the
Requiredattributes to the non-nullable reference types. You can find the implementation here DataAnnotationsMetadataProvider. Here is the sectionYou can opt-out of this behavior while registering the controllers
The ability to opt out makes it OK to have such inferring in MVC.