如何在FluentValidation中封装带依赖规则的自定义邮箱验证器?
封装带必填性检查的自定义邮箱验证器
要解决重复编写NotNull/NotEmpty规则+邮箱格式验证的问题,同时避免null时触发重复错误,你可以通过以下两种正确方式封装自定义验证器:
方案1:使用When条件控制验证触发时机
利用When方法限制后续格式验证仅在字段非空时执行,同时保留必填性规则:
public static IRuleBuilderOptions<T, string> EmailMustBeValid<T>(this IRuleBuilder<T, string> ruleBuilder) { return ruleBuilder .NotNull().WithMessage("邮箱不能为空") .NotEmpty().WithMessage("邮箱不能为空字符串") // 仅当字段不为null时,才执行后续的格式验证 .When(x => x != null, ApplyConditionTo.CurrentValidator) .Must(email => IsValidEmail(email)).WithMessage("邮箱格式无效或域名不符合规则"); }
调用时只需一行代码:
RuleFor(dto => dto.Upn).EmailMustBeValid();
方案2:正确使用DependentRules
之前的错误是在DependentRules中直接使用外部的ruleBuilder,导致依赖规则脱离了前置条件。正确的做法是使用委托参数提供的内部规则构建器:
public static IRuleBuilderOptions<T, string> EmailMustBeValid<T>(this IRuleBuilder<T, string> ruleBuilder) { return ruleBuilder .NotNull().WithMessage("邮箱不能为空") .NotEmpty().WithMessage("邮箱不能为空字符串") .DependentRules(innerRules => { // 内部规则会自动继承前置规则的通过条件 innerRules.Must(email => IsValidEmail(email)).WithMessage("邮箱格式无效或域名不符合规则"); }); }
为什么之前的代码无效?
你之前在DependentRules中调用ruleBuilder.Must(...),相当于直接给原始规则链追加了验证逻辑,并没有和前面的NotNull/NotEmpty规则建立依赖关系。而使用innerRules时,内部规则会绑定到前置规则的执行结果——只有当前置的NotNull/NotEmpty验证通过,才会触发内部的格式验证。
关于是否复制NotNull逻辑到IsValidEmail
不建议这么做。将必填性检查(NotNull/NotEmpty)和格式检查分离,更符合单一职责原则:IsValidEmail只负责验证邮箱格式和域名规则,必填性验证由FluentValidation的原生规则处理,逻辑更清晰,也便于后续单独调整必填性规则或格式规则。
内容的提问来源于stack exchange,提问作者Robin
相关产品推荐
相关产品推荐

