Boris Callens
Boris Callens

Reputation: 93407

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.

Upvotes: 3

Views: 9551

Answers (2)

Jeremy Skinner
Jeremy Skinner

Reputation: 1461

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.

Upvotes: 6

Rami A.
Rami A.

Reputation: 10602

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();
    }
}

Upvotes: 2

Related Questions