Search code examples
c#fluentvalidation

FluentValidation, 2 of 3 are required


I'm trying to make a validator which handles any combination of 2 props out of a total of 3. So if I have A, B, C then the validation should succeed if any A-B, B-C, C-A or A-B-C is valid.

I've written it so far something like

RuleFor(x=>x.A)
 .Must(val=>!string.IsNullOrEmpty(val)
 .When(x=> !(string.IsNullOrEmpty(x.B) && string.IsNullOrEmpty(x.C)));

RuleFor(x=>x.C)
 .Must(val=>!string.IsNullOrEmpty(val)
 .When(x=> !(string.IsNullOrEmpty(x.B) && string.IsNullOrEmpty(x.A)));

RuleFor(x=>x.B)
 .Must(val=>!string.IsNullOrEmpty(val)
 .When(x=> !(string.IsNullOrEmpty(x.A) && string.IsNullOrEmpty(x.C)));

When(x=> string.IsNullOrEmpty(x.A), ()=>{
   ///   validate A according to business
})
When(x=> string.IsNullOrEmpty(x.B), ()=>{
   ///   validate B according to business
})
When(x=> string.IsNullOrEmpty(x.C), ()=>{
   ///   validate C according to business
})

But this does not work and I cannot find a way to make the validator work


Solution

  • You can use the Must method to create a custom validation rule that checks your custom rule inside:

    RuleFor(x => x)
        .Must(x => !string.IsNullOrEmpty(x.A) && !string.IsNullOrEmpty(x.B)
                   || !string.IsNullOrEmpty(x.B) && !string.IsNullOrEmpty(x.C)
                   || !string.IsNullOrEmpty(x.C) && !string.IsNullOrEmpty(x.A)
                   || !string.IsNullOrEmpty(x.A) && !string.IsNullOrEmpty(x.B) && !string.IsNullOrEmpty(x.C))
        .WithMessage("At least two of A, B, and C must be non-empty.");
    

    Then you can add additional rules to validate each individual property:

    When(x => string.IsNullOrEmpty(x.A), () => {
        RuleFor(x => x.B)
            .NotEmpty()
            .WithMessage("B is required when A is empty.");
    
        RuleFor(x => x.C)
            .NotEmpty()
            .WithMessage("C is required when A is empty.");
    });
    
    When(x => string.IsNullOrEmpty(x.B), () => {
        RuleFor(x => x.A)
            .NotEmpty()
            .WithMessage("A is required when B is empty.");
    
        RuleFor(x => x.C)
            .NotEmpty()
            .WithMessage("C is required when B is empty.");
    });
    
    When(x => string.IsNullOrEmpty(x.C), () => {
        RuleFor(x => x.A)
            .NotEmpty()
            .WithMessage("A is required when C is empty.");
    
        RuleFor(x => x.B)
            .NotEmpty()
            .WithMessage("B is required when C is empty.");
    });