3

FluentValidation 中是否有可能为 RuleSet 提供特定的错误消息?

就像是:

RuleSet("LoginInformation", () =>
{
    RuleFor(m => m.Email).NotEmpty().EmailAddress();
    RuleFor(m => m.Password).NotEmpty();
}); // I thought I can add a WithMessage here...

如果任何规则失败,那应该会显示一条错误消息。

4

1 回答 1

1

简单的解决方案

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。

于 2015-04-24T12:44:16.097 回答