This example demonstrating how to conditionally validate nested objects using FluentValidation’s When method.
Scenario
Let’s say we have:
- A Personclass with anAddressproperty
- We only want to validate the AddresswhenHasAddressistrue
Model Classes
public class Person
{
    public string Name { get; set; }
    public bool HasAddress { get; set; }
    public Address Address { get; set; }
}
public class Address
{
    public string Street { get; set; }
    public string City { get; set; }
    public string ZipCode { get; set; }
}Validator Implementation
public class PersonValidator : AbstractValidator<Person>
{
    public PersonValidator()
    {
        // Always validate name
        RuleFor(x => x.Name).NotEmpty().MaximumLength(100);
        
        // Only validate address when HasAddress is true
        When(x => x.HasAddress, () => 
        {
            RuleFor(x => x.Address)
                .NotNull()
                .WithMessage("Address must be provided when HasAddress is true");
                
            RuleFor(x => x.Address.Street)
                .NotEmpty()
                .When(x => x.Address != null)
                .WithMessage("Street is required");
                
            RuleFor(x => x.Address.City)
                .NotEmpty()
                .When(x => x.Address != null)
                .MaximumLength(50);
                
            RuleFor(x => x.Address.ZipCode)
                .NotEmpty()
                .When(x => x.Address != null)
                .Matches(@"^\d{5}(-\d{4})?$");
        });
    }
}Alternative Approach (Using Child Validator)
public class PersonValidator : AbstractValidator<Person>
{
    public PersonValidator()
    {
        RuleFor(x => x.Name).NotEmpty().MaximumLength(100);
        
        When(x => x.HasAddress, () => 
        {
            RuleFor(x => x.Address)
                .NotNull()
                .SetValidator(new AddressValidator());
        });
    }
}
public class AddressValidator : AbstractValidator<Address>
{
    public AddressValidator()
    {
        RuleFor(x => x.Street).NotEmpty();
        RuleFor(x => x.City).NotEmpty().MaximumLength(50);
        RuleFor(x => x.ZipCode).NotEmpty().Matches(@"^\d{5}(-\d{4})?$");
    }
}Usage Example
var person = new Person 
{
    Name = "Khan",
    HasAddress = false,
    Address = null
};
var validator = new PersonValidator();
var result = validator.Validate(person); // Won't validate addressKey Points:
- The Whencondition determines whether the nested rules should execute
- The nested rules are only evaluated if HasAddressis true
- We still need null checks for the address object itself
- The second approach using a separate validator is cleaner for complex nested objects
This pattern is useful when you want to validate complex objects only in certain scenarios, reducing unnecessary validation overhead.