Search code examples
fluentvalidation

Validate multiple properties with one message


I'm trying to validate a class that has three required properties.
If one or more of them is null it should trigger a single validation message.
Is there a idiomatic way to describe this in fluent validator?

I'm looking at dependant rules but the bottom of the documentation's page advises against using them.
Furthermore I still want to validate all three properties. I just don't want duplicate messages.
I noticed RuleSets, but these seem to serve a different purpose.

Alternatively I could create a validator specifically for these three options but without message and then chain the new validator in the original one. Then I think I can give that one a single message.
But that's a lot of ceremony for a system that is built around being readable.

So looking for a readable way to express validation for three fields with a single message as result.


Solution

  • There are 3 main ways you can do this with FluentValidation: Conditions, dependent rules or a custom rule.

    Conditions

    You can use 3 separate rule declarations with When conditions to ensure that you only ever get a single validation message.

    RuleFor(x => x.Property1).NotNull()
      .WithMessage("At least one is required");
    
    RuleFor(x => x.Property2).NotNull()
      .When(x => x.Property1 != null)
      .WithMessage("At least one is required");
    
    RuleFor(x => x.Property3).NotNull()
      .When(x => x.Property1 != null && x.Property2 != null)
      .WithMessage("At least one is required");
    

    Dependent Rules

    RuleFor(x => x.Property1).NotNull()
      .WithMessage("At least one is required")
      .DependentRules(() => {
          RuleFor(x => x.Property2).NotNull()
           .WithMessage("At least one is required")
           .DependentRules(() => {
              RuleFor(x => x.Property3).NotNull().WithMessage("At least one is required");
           });
       });
    

    I don't particularly like this approach - I think it's hard to read (hence the warning in the documentation), but if you like this approach it'll work just fine.

    Custom logic

    RuleFor(x => x)
      .Must(x => x.Property1 != null && x.Property2 != null && x.Property3 != null)
      .WithMessage("At least one is required");
    

    This approach is slightly different as it creates a model-level rule, so the error message will be associated with the entire model, rather than with a specific property.