FluentValidation规则链接不会在第一次失败时停止

时间:2017-02-07 21:23:33

标签: c# fluentvalidation

我有一个模特:

public class DTO
{
    public int[] StatementItems { get; set; }
}

我要验证它:

  1. StatementItems不为空
  2. StatementItems不为空
  3. StatementItems不包含任何重复的ID
  4. 我创建的验证规则链是:

    RuleFor(x => x.StatementItems).NotNull().NotEmpty().Must(x => x.Distinct().Count() == x.Count());
    

    我有一个测试:

    _validator.ShouldHaveValidationErrorFor(x => x.StatementItems, null as int[]);
    

    当我运行测试传递一个空值时,我希望它在链的第一个规则(NotNull())上失败并停在那里。但是,它抱怨Must()中使用的lamda值为null。

    如果Must()失败,我认为不应该运行NotNull()我错了吗?如果是这样,该规则应该如何编写?

    由于

3 个答案:

答案 0 :(得分:8)

尽管@ NPras的回答确实为我提供了一个解决方案,但我不喜欢我复制NotNull规则的事实。在对FluentValidation进行了一些研究后,我使用DependentRules实现了它:

RuleFor(x => x.StatementItems).NotNull().NotEmpty()
            .DependentRules(d =>
                d.RuleFor(x => x.StatementItems).Must(x => x.Distinct().Count() == x.Count())
            );

所以现在只有在前两个规则有效时才会触发Must条件。

答案 1 :(得分:1)

我在FluentValidation文档中没有看到它确实可以保证短路。

如果您查看其来源:

public virtual ValidationResult Validate(ValidationContext<T> context)
{
  ...
  var failures = nestedValidators.SelectMany(x => x.Validate(context));
  return new ValidationResult(failures);
}

它将运行* all *验证器(带有SelectMany())并返回错误列表。

您唯一的选择似乎是强制检查Must规则。

.Must(x => x!= null && x.Distinct().Count() == x.Count())
//or, fluently:
.Must(x => x.Distinct().Count() == x.Count()).When(x => x! = null)

编辑: 我打算建议,因为Validate()是虚拟的,你可以在验证器中覆盖它以使其短路。但后来我意识到nestedValidators列表是私有的。所以是的,没有..

答案 2 :(得分:0)

查看FluentValidation的cascade mode。您可以像这样在第一次失败时使其短路:

RuleFor(x => x.StatementItems)
   .Cascade(CascadeMode.Stop)
   .NotNull()
   .NotEmpty()
   .Must(x => x.Distinct().Count() == x.Count());