简单的解决方案
RuleSet
在不更改 FluentValidation 源的情况下直接设置错误消息是不可能的,但是您可以在特殊列表中收集您的规则,并在循环中设置相同的错误消息:
RuleSet("LoginInformation", () =>
{
var loginRules = new List<IRuleBuilderOptions<CredentialsModel, object>>
{
RuleFor(m => m.Email).NotEmpty().EmailAddress(),
RuleFor(m => m.Password).NotEmpty()
};
foreach (var rule in rules)
{
// this overload chosen just to show, that all possibilities to set error message still available
rule.WithMessage("An error occured. Additional information: {0}, {1}", (model, value) => value, (model, value) => model.Email);
}
});
只有 2 个级联模式选项,您不能告诉验证器在第一次失败时停止所有规则,因此您只需从验证结果中提取第一个错误并删除其他相同的错误。为此,您可以覆盖AbstractValidator
:
public class SingleErrorValidator<T> : AbstractValidator<T>
{
public override ValidationResult Validate(ValidationContext<T> context)
{
var result = base.Validate(context);
if (result.IsValid)
return result;
var singleErrorList = new List<ValidationFailure> { result.Errors.First() };
var singleErrorResult = new ValidationResult(singleErrorList);
return singleErrorResult;
}
}
高级解决方案:
如果您 fork FluentValidation 并且可以修改解决方案中的源代码,那么您可以为常见错误消息制定可重用的方法并RuleSet
在类中添加下一个方法重载AbstractValidator
(您不能使用扩展方法或继承,因为重要字段具有 private 修饰符):
public void RuleSet(string ruleSetName, Func<List<IRuleBuilderOptions<T, object>>> function, Action<IRuleBuilderOptions<T, object>> writeRuleMessage)
{
ruleSetName.Guard("A name must be specified when calling RuleSet.");
function.Guard("A ruleset definition must be specified when calling RuleSet.");
using (nestedValidators.OnItemAdded(r => r.RuleSet = ruleSetName))
{
var list = function();
foreach (var rule in list)
{
writeRuleMessage(rule);
}
}
}
然后你可以使用RuleSet
下一种方式:
RuleSet("LoginInformation", () =>
{
var rules = new List<IRuleBuilderOptions<B, object>>()
{
RuleFor(x => x.Name).NotEmpty().EmailAddress(),
RuleFor(x => x.Email).NotEmpty()
};
return rules;
}, (rule) =>
{
rule.WithMessage("An error occured");
}); // still can use another overloads, that allow access to model and validated properties
结论
两种解决方案都可以工作,但由于 KISS 原则,我建议使用 1-st。