Search code examples
c#validationservicestackfluentfluentvalidation

Skip Executing other Validation Rules in the Fluent validation Ruleset, if one of them fails


Is there any way to skips executing the validation rules in the Ruleset if one of them fails.

I have this following rules for my API endpoint

param1, param2, param3

RuleSet  => 
     RuleFor(req => req.param1).NotEmpty().WithMessage("param1 is missing.");
     RuleFor(req => req.param2).NotEmpty().WithMessage("param2 is missing.");
     RuleFor(req => req.param3).NotEmpty().WithMessage("param3 is missing.");
     RuleFor(req => req.param1).Must((req, param1) => IsValidRequest(req)).WithMessage("Invalid request.");

In my IsValidRequest(req) I again have to verify for param1, param2, param3 exist before doing my custom validation as even if the above rules fails all other validations will still continue to try.


Solution

  • By default, FluentValidation uses Continue cascade mode for invoking validators in rule definition (i.e. it invokes all validators). You should use StopOnFirstFailure mode to stop execution after first validator fails:

    ValidatorOptions.CascadeMode = CascadeMode.StopOnFirstFailure;
    

    Note that this will set StopOnFirstFailure mode globally. If you want to specify this mode for particular validators, you can use property of validator class:

    public class RequestValidator : AbstractValidator<Request>
    {
       public RequestValidator()
       {
           CascadeMode = CascadeMode.StopOnFirstFailure;
    
           RuleFor(req => req.param1)
              .NotEmpty().WithMessage("param1 is missing.")
              .Must((req, param1) => IsValidRequest(req)).WithMessage("Invalid request.");
           RuleFor(req => req.param2).NotEmpty().WithMessage("param2 is missing.");
           RuleFor(req => req.param3).NotEmpty().WithMessage("param3 is missing.");
       }
    }
    

    In the example above Must validator will not be executed if NotEmpty validator fails.


    If you want to execute Must validator only when all three parameters are not empty, then When is the best option:

    When(req => !String.IsNullOrEmpty(req.param1) 
             && !String.IsNullOrEmpty(req.param2)
             && !String.IsNullOrEmpty(req.param3), () => {
         RuleFor(req => req.param1)
            .Must((req, param1) => IsValidRequest(req)).WithMessage("Invalid request.");
    });
    

    You can move precondition check to separate method:

     private bool AllParametersSpecified(Request req)
     {
         return !String.IsNullOrEmpty(req.param1) 
             && !String.IsNullOrEmpty(req.param2)
             && !String.IsNullOrEmpty(req.param3);
     }
    

    And condition will be much more readable:

    When(AllParametersSpecified, () => {
         RuleFor(req => req.param1)
            .Must((req, param1) => IsValidRequest(req)).WithMessage("Invalid request.");
    });