FluentValidation中CascadeMode.Stop未终止验证的原因咨询
CascadeMode.Stop未生效的原因分析
当Label为空或null时,SharedFolderValidator中设置了CascadeMode.Stop的验证链仍会执行到.Must(l => l.StartsWith(labelPrefix, StringComparison.Ordinal))并抛出空引用异常,但按预期应该在MustHaveValidLabel()验证失败后终止后续验证。以下是相关代码实现:
LabelValidator 实现
internal sealed class LabelValidator : AbstractValidator<string> { public LabelValidator() { RuleFor(label => label) .NotNull() .NotEmpty() .MaximumLength(120); } }
ValidatorExtensions 扩展类
internal static class ValidatorExtensions { public static IRuleBuilderOptions<T, string> MustHaveValidLabel<T>(this IRuleBuilder<T, string> ruleBuilder) { return ruleBuilder.SetValidator(new LabelValidator()); } }
SharedFolderValidator 实现
internal sealed class SharedFolderValidator : ResourceValidator<SharedFolderDto> { public SharedFolderValidator(string labelPrefix, string groupPrefixFullControl, string groupPrefixReadOnly) { RuleFor(resource => resource.Label) .Cascade(CascadeMode.Stop) .MustHaveValidLabel() .Must(l => l.StartsWith(labelPrefix, StringComparison.Ordinal)) } protected override bool PreValidate(ValidationContext<SharedFolderDto> context, ValidationResult result) { base.PreValidate(context, result); [Some other tests] return !result.Errors.Any(); } }
ValidatorBehavior 管道行为
public sealed class ValidatorBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : notnull { private async Task<TResponse> Validate(TRequest request, RequestHandlerDelegate<TResponse> next) { List<ValidationFailure> failures = _validators .Select(v => v.Validate(request)) .SelectMany(result => result.Errors) .Where(error => error != null) .ToList(); if (failures.Any()) { _logger.LogValidationResult(typeName, JsonSerializer.Serialize(request), failures); throw new ResourceDomainException(); } return await next(); } }
核心原因
CascadeMode.Stop的作用范围仅限于当前规则链内的同级验证规则,无法穿透到通过SetValidator()引入的子验证器:
- 父规则链(针对
resource.Label的规则)的CascadeMode.Stop只会控制父链中直接定义的规则,比如如果父链是.NotNull().NotEmpty().Must(...),前面规则失败后会停止后续父链规则。 MustHaveValidLabel()通过SetValidator()调用了独立的LabelValidator,子验证器内部的规则失败只会生成验证错误并添加到结果中,不会触发父规则链的终止逻辑。父链会继续执行下一个规则.Must(l => l.StartsWith(...)),此时Label为null/空,导致lambda表达式执行时抛出异常。
另外需要明确:CascadeMode的终止逻辑是基于验证规则返回失败结果,而不是直接中断代码执行。子验证器的错误属于子上下文的结果,不会主动中断父链的规则执行流程。
内容的提问来源于stack exchange,提问作者Vincent
相关产品推荐
相关产品推荐

