I'm attempting to validate that only one of three fields has a value using FluentValidation.
RuleFor(x => x.Date1)
.Must(x => !x.HasValue)
.When(x => x.Date2.HasValue || x.Date3.HasValue)
.WithMessage("Select only one of Date 1, Date 2 and Date 3");
This is repeated for the other 2 dates. As would be expected, this produces on message per rule that matches.
There are other rules involved, so is there a way to execute the other rules but fail on the first of these three? I've seen where I could set CascadeMode.StopOnFirstFailure globally but I want the other rules outside of these three to work as they currently do.
I decide to go down another route. It feels elegant but I'll know if it passes the code review.
I created a new property
public IEnumerable<DateTime?> MutuallyExclusiveDates
{
get
{
return new List<DateTime?>()
{
Date1,
Date2,
Date3
};
}
}
Then I added this rule
RuleFor(x => x.MutuallyExclusiveDates)
.Must(x => x.Count(d => d.HasValue) <= 1)
.WithMessage("Select only one of Date 1, Date 2 and Date 3");
Simple one rule for all 3 using xor. No extra properties needed. take out the unless if you want to force at least one to have a value.
RuleFor(x => x).Cascade(CascadeMode.StopOnFirstFailure)
.Must(x => (x.date1.HasValue ^ x.date2.HasValue) ^ x.date3.HasValue)
.Unless(x => !x.date1.HasValue && !x.date2.HasValue && !x.date3.HasValue)
.WithMessage("Select only one of Date 1, Date 2 and Date 3");
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With