FluentValidation rules chaining not stopping at first failure

蹲街弑〆低调 提交于 2019-12-12 10:46:58

问题


I have a model:

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

Which I want to validate that:

  1. StatementItems is not null
  2. StatementItems is not empty
  3. StatementItems does not contain any duplicate IDs

The validation rule chain I created is:

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

And I have a test as:

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

When I run the test passing in a null value, I would expect it to fail on the first rule of the chain (NotNull()) and stop there. However, it complains that the lamda value used in the Must() is null.

Am I wrong in thinking that the Must() shouldn't be run if the NotNull() fails? If so, how should this rule be written?

Thanks


回答1:


Although @NPras's answer did supply my with a solution, I didn't like the fact that I'm duplicating the NotNull rule. After a bit more research on FluentValidation I have implemented it using DependentRules:

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

So now the Must condition is only fired when the previous two rules are valid.




回答2:


I don't see in the FluentValidation documentation that it actually guarantees short-circuiting.

If you look in its source:

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

It will run through *all* the validators (with the SelectMany()) and returns a list of errors.

Your only option seems to be to force a check on your Must rule.

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

EDIT: I was going to suggest that since Validate() is virtual, you could just override it in your validator to make it short-circuit. But then I realised that the nestedValidators list is private. So yeah, no..



来源:https://stackoverflow.com/questions/42100254/fluentvalidation-rules-chaining-not-stopping-at-first-failure

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!