问题
I'm having an issue with FluentValidation where I want to display one message regardless of the validation error in a given chain. For example, I've defined a validation chain for one property below. I would expect that the chain would be evaluated and any failures would result in the message defined in the WithMessage()
call below. However, it seems that it's short-circuiting and only displaying the FluentValidation default error message for the first error encountered. See code below:
RuleFor(s => s.ProposalDetail.AgeMin).NotNull()
.GreaterThanOrEqualTo(1)
.LessThanOrEqualTo(99)
.WithMessage("Minimum Age entry is required and must range from 1 to 99 years.");
What's happening is that the AgeMin property is null, so the first NotNull()
check is failing and the validation message reads "'Proposal Detail. Age Min' must not be empty." Proposal Detail is the name of the encapsulating view model.
I've tried setting the CascadeMode for the entire validator to CascadeMode.Continue, but it has no effect.
How can I accomplish one message for one property validation chain?
回答1:
Update 2
As it turns out,you can accomplish what you want with a simple extension method
using FluentValidation;
using FluentValidation.Internal;
using FluentValidation.Resources;
using FluentValidation.Results;
using System;
using System.Linq;
namespace ConsoleApplication9
{
class Program
{
static void Main(string[] args)
{
Customer customer = new Customer() { };
CustomerValidator validator = new CustomerValidator();
ValidationResult results = validator.Validate(customer);
Console.WriteLine(results.Errors.First().ErrorMessage);
Console.ReadLine();
}
}
public class CustomerValidator : AbstractValidator<Customer>
{
public CustomerValidator()
{
RuleFor(s => s.Id).NotNull()
.GreaterThanOrEqualTo(1)
.LessThanOrEqualTo(99)
.WithGlobalMessage("Minimum Age entry is required and must range from 1 to 99 years.");
}
}
public class Customer { public int? Id { get; set; } }
public static class MyExtentions
{
public static IRuleBuilderOptions<T, TProperty> WithGlobalMessage<T, TProperty>(this IRuleBuilderOptions<T, TProperty> rule, string errorMessage)
{
foreach (var item in (rule as RuleBuilder<T, TProperty>).Rule.Validators)
item.Options.ErrorMessageSource=new StaticStringSource(errorMessage);
return rule;
}
}
}
Update 3: (Apr 04/07/2019)
In FluentValidation v8.2.2, The IRuleBuilderOptions
interface do not have direct access to IRuleBuilderOptions.ErrorMessageSource
property anymore, instead we should use: IRuleBuilderOptions.Options.ErrorMessageSource
.
回答2:
The most straightforward solution would be to just set the message to a variable, and apply the same message after each rule:
var message = "Minimum Age entry is required and must range from 1 to 99 years.";
RuleFor(s => s.ProposalDetail.AgeMin)
.NotNull()
.WithMessage(message)
.GreaterThanOrEqualTo(1)
.WithMessage(message)
.LessThanOrEqualTo(99)
.WithMessage(message);
来源:https://stackoverflow.com/questions/35513141/one-message-for-rule-chain