13
votes

From the FluentValidation documentation I learned that I can abort validation by setting the cascade mode.

RuleFor(x => x.Surname)
.Cascade(CascadeMode.StopOnFirstFailure)
.NotNull()
.NotEqual("foo");

That way if the property Surname is null, the equality check won't be executed and a null pointer exception prevented. Further down in the documentation it is implied that this would also work not only within a rule but on a validator level as well.

public class PersonValidator : AbstractValidator<Person> {
  public PersonValidator() {

    // First set the cascade mode
    CascadeMode = CascadeMode.StopOnFirstFailure;

    // Rule definitions follow
    RuleFor(...) 
    RuleFor(...)
  }
}

I set the CascadeMode not inside the rule definition but for an instance of a validator. The expected behaviour would be that if the first RuleFor fails, the second RuleFor won't be evaluated but that's not the case. Regardless of previous validation errors, all rules are being evaluated.

Am I using it wrong or did I misinterpret the documentation?

3
Agree, this behavior is really not expected or ideal as each chain can be verifying a different aspect of the same field, with a different error message and state injection, meaning you need to often have multiple rules for a single field. it becomes especially annoying when you dont want the last rule to fire because it is an expensive call that checks the db, which is pointless when the previous rule determined the field was blank! - AaronHS

3 Answers

13
votes

According to the JeremyS' answer, I have misunderstood the purpose of the CascadeMode. It is in fact not intended to have effect on a validator level but only within a rule.

10
votes

You can set CascadeMode at the global level by setting

ValidatorOptions.CascadeMode = CascadeMode.StopOnFirstFailure;

or at property level by

RuleFor(x => x.PropertyName)
    .Cascade(CascadeMode.StopOnFirstFailure)
0
votes

If you are using .NET Core you can set the cascade mode at a global level like below

.AddFluentValidation(fv =>
            {
                fv.RunDefaultMvcValidationAfterFluentValidationExecutes = true;
                fv.ValidatorOptions.CascadeMode = CascadeMode.Stop;

                fv.RegisterValidatorsFromAssemblyContaining<Startup>();
            });