'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 1:[1]

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.Property2 != 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.

Solution 2:[2]

Stop the validator when the first rule fails by setting the CascadeMode property:

public class MyClassValidator : AbstractValidator<MyClass>
{
    public DestinationDeviceValidator()
    {
        this.CascadeMode = CascadeMode.Stop;

        this.RuleFor(x => x.Property1)
            .NotNull();

        this.RuleFor(x => x.Property2)
            .NotNull();

        this.RuleFor(x => x.Property3)
            .NotNull();
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Dharman
Solution 2 Lukas