Inheritance Validation

As of FluentValidation 9.2, if your object contains a property which is a base class or interface, you can set up specific child validators for individual subclasses/implementors.

For example, imagine the following example:

// We have an interface that represents a 'contact',
// for example in a CRM system. All contacts must have a name and email.
public interface IContact 
{
  string Name { get; set; }
  string Email { get; set; }
}

// A Person is a type of contact, with a name and a DOB.
public class Person : IContact 
{
  public string Name { get; set; }
  public string Email { get; set; }

  public DateTime DateOfBirth { get; set; }
}

// An organisation is another type of contact,
// with a name and the address of their HQ.
public class Organisation : IContact 
{
  public string Name { get; set; }
  public string Email { get; set; }

  public Address Headquarters { get; set; }
}

// Our model class that we'll be validating.
// This might be a request to send a message to a contact.
public class ContactRequest 
{
  public IContact Contact { get; set; }

  public string MessageToSend { get; set; }
}

Next we create validators for Person and Organisation:

public class PersonValidator : AbstractValidator<Person> 
{
  public PersonValidator() 
  {
    RuleFor(x => x.Name).NotNull();
    RuleFor(x => x.Email).NotNull();
    RuleFor(x => x.DateOfBirth).GreaterThan(DateTime.MinValue);
  }
}

public class OrganisationValidator : AbstractValidator<Organisation> 
{
  public OrganisationValidator() 
  {
    RuleFor(x => x.Name).NotNull();
    RuleFor(x => x.Email).NotNull();
    RuleFor(x => x.HeadQuarters).SetValidator(new AddressValidator());
  }
}

Now we create a validator for our ContactRequest. We can define specific validators for the Contact property, depending on its runtime type. This is done by calling SetInheritanceValidator, passing in a function that can be used to define specific child validators:

public class ContactRequestValidator : AbstractValidator<ContactRequest>
{
  public ContactRequestValidator()
  {

    RuleFor(x => x.Contact).SetInheritanceValidator(v => 
    {
      v.Add<Organisation>(new OrganisationValidator());
      v.Add<Person>(new PersonValidator());
    });

  }
}

There are also overloads of Add available that take a callback, which allows for lazy construction of the child validators.

This method also works with collections, where each element of the collection may be a different subclass. For example, taking the above example if instead of a single Contact property, the ContactRequest instead had a collection of contacts:

public class ContactRequest 
{
  public List<IContact> Contacts { get; } = new();
}

…then you could define inheritance validation for each item in the collection:

public class ContactRequestValidator : AbstractValidator<ContactRequest>
{
  public ContactRequestValidator()
  {

    RuleForEach(x => x.Contacts).SetInheritanceValidator(v => 
    {
      v.Add<Organisation>(new OrganisationValidator());
      v.Add<Person>(new PersonValidator());
    });
  }
}