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.");
});