如何从RuleBuilderOptions获取PropertyValidatorContext实现自定义When扩展
解决FluentValidation自定义When扩展获取上下文的问题
嘿,我懂你想实现的功能——给FluentValidation加个自定义的WhenHasChanged扩展,只在实体属性确实发生变更时才执行后续验证规则对吧?你现在的问题在于,试图在规则构建阶段从IRuleBuilderOptions里拿PropertyValidatorContext,但这个上下文只有在实际验证执行阶段才会存在,所以直接从rule对象里是拿不到的。
正确的实现思路
FluentValidation的When方法本身就支持接收一个包含PropertyValidatorContext的委托,这个委托会在验证执行时被调用,这时候你就能拿到当前的实例和属性名了。我们可以基于这个重载来封装你的逻辑:
public static IRuleBuilderOptions<T, TProperty> WhenHasChanged<T, TProperty>(this IRuleBuilderOptions<T, TProperty> rule) { return rule.When(context => { // 将实例转换为你的变更跟踪接口 var changeTrackingInstance = context.Instance as IChangeTrackingObject; if (changeTrackingInstance == null) { // 如果实例不支持变更跟踪,默认跳过验证(可根据需求调整) return false; } // 检查当前属性是否在变更列表中 if (!changeTrackingInstance.GetChangedProperties().TryGetValue(context.PropertyName, out var propertyChange)) { // 属性未发生变更,跳过后续验证 return false; } // 比较新旧值,只有当值确实变化时才执行验证 var oldValue = propertyChange.OldValue; var newValue = context.PropertyValue; return oldValue == null ? newValue != null : !oldValue.Equals(newValue); }); }
关键说明
- 规则构建 vs 验证执行:
IRuleBuilderOptions是用来配置验证规则的对象,在你写RuleFor(x => x.Name).WhenHasChanged()的时候就存在了,但这时候还没有要验证的实例和上下文。只有当调用Validate方法验证实体时,才会创建PropertyValidatorContext并传入When的委托。 - When的逻辑:
When的委托返回true时,后续的验证规则才会执行;返回false时,规则会被跳过。上面的代码逻辑是:只有当属性确实被修改(新旧值不同)时,才触发验证。 - 异常处理:代码里考虑了
IChangeTrackingObject转换失败的情况,你可以根据自己的业务需求调整这部分逻辑(比如抛出异常或者默认执行验证)。
使用示例
之后你就可以像这样使用这个扩展:
RuleFor(x => x.Email) .WhenHasChanged() .NotEmpty() .EmailAddress();
这段代码会只在Email属性发生变更时,才检查它是否为空和是否符合邮箱格式。
内容的提问来源于stack exchange,提问作者johnny 5
相关产品推荐
相关产品推荐

