Fluent Validation 链式规则不适用于多个 When 条件

ren*_*gbp 3 c# xunit fluentvalidation

我有一个非常有趣的行为。我有以下两个测试用例:

[Fact]
public void Ctor_WhenNeverIsTrueAndAfterOcurrenceIsNotNull_HasError()
{
    // arrange
    var reccurenceEnd = new RecurrenceEnd()
    {
         IsNever = true,
         AfterOccurence = 1
     };

     // act
     var validator = GetValidator();

     // assert
     validator.ShouldHaveValidationErrorFor(p => p.AfterOccurence, reccurenceEnd);
}

[Fact]
public void Ctor_WhenNeverIsFalseAndAfterOccurenceIsNullAndByDateIsNull_HasError()
{
    // arrange
    var reccurenceEnd = new RecurrenceEnd()
    {
        IsNever = false,
        AfterOccurence = null,
        ByDate = null
    };

    // act
    var validator = GetValidator();

    // assert
    validator.ShouldHaveValidationErrorFor(p => p.AfterOccurence, reccurenceEnd);
}
Run Code Online (Sandbox Code Playgroud)

在我的验证器上,如果我有以下内容,第一个测试失败,第二个通过。如果我改变规则的顺序,第一个测试通过,第二个失败。

RuleFor(dto => dto.AfterOccurence)
    .Cascade(CascadeMode.StopOnFirstFailure)
    .Null()
        .When(p => p.IsNever == true)
    .NotEmpty()
        .When(p => p.IsNever == false && p.ByDate == null);
Run Code Online (Sandbox Code Playgroud)

如果我将验证器更改为以下内容,则两个测试都会通过。

RuleFor(dto => dto.AfterOccurence)
    .Null()
        .When(p => p.IsNever);
RuleFor(dto => dto.AfterOccurence)
    .NotEmpty()
        .When(p => p.IsNever == false && p.ByDate == null);
Run Code Online (Sandbox Code Playgroud)

我设置错了吗?

ren*_*gbp 8

好的,从 FluentValidation 的github-issues得到了答案:

您好,这与您使用 When 条件有关。默认情况下,When 条件适用于同一个 RuleFor 调用中的所有先前验证器,因此当您使用对 RuleFor 的单个调用时,实际上是在条件上加倍。您应该使用单独的 RuleFor 调用(如您在第二个示例中所做的那样),或者使用 When 的其他重载允许您指定 ApplyConditionTo.CurrentValidator

第二种解决方案是:

RuleFor(dto => dto.AfterOccurence)
    .Cascade(CascadeMode.StopOnFirstFailure)
    .Null()
        .When(p => p.IsNever == true)
    .NotEmpty()
        .When(p => p.IsNever == false && p.ByDate == null, ApplyConditionTo.CurrentValidator);
Run Code Online (Sandbox Code Playgroud)