派生自抽象类的类中自定义属性验证器验证容器类时不执行的解决方法
问题分析与解决方案
问题根源
验证SomeClass实例时,默认的Validator.TryValidateObject存在两个关键限制:
- 不会自动递归验证集合内的元素,仅检查集合本身是否满足必填等基础属性要求;
- 由于
elements声明为IList<AbstractClass>,验证上下文会以抽象类类型执行验证,无法识别实际的派生类DerivedClass,因此派生类属性上的CustomValidation不会被触发。
解决方案一:手动递归验证集合元素
在验证SomeClass后,遍历集合中的每个元素,使用元素的实际类型创建验证上下文,手动执行派生类的属性验证:
var someClassInstance = new SomeClass { elements = new List<AbstractClass> { new DerivedClass { value = "无效值" } } }; var validationResults = new List<ValidationResult>(); bool isValid = Validator.TryValidateObject(someClassInstance, new ValidationContext(someClassInstance), validationResults, true); // 遍历集合,逐个验证派生类实例 foreach (var element in someClassInstance.elements) { if (element == null) continue; // 基于元素实际类型创建验证上下文,确保触发派生类的验证器 var elementContext = new ValidationContext(element) { Items = { ["Validator:ValidateAllProperties"] = true } }; isValid &= Validator.TryValidateObject(element, elementContext, validationResults, true); } // 此时isValid会正确反映派生类属性的验证结果
解决方案二:自定义集合验证属性
创建一个自定义验证属性,自动处理集合内元素的递归验证,包括多态类型的验证逻辑:
自定义验证属性代码
public class ValidateCollectionElementsAttribute : ValidationAttribute { protected override ValidationResult IsValid(object value, ValidationContext validationContext) { var collection = value as IEnumerable; if (collection == null) { return ValidationResult.Success; } var validationResults = new List<ValidationResult>(); bool isValid = true; foreach (var item in collection) { if (item == null) continue; // 使用元素实际类型创建验证上下文 var itemContext = new ValidationContext(item, validationContext.ServiceContainer, null); isValid &= Validator.TryValidateObject(item, itemContext, validationResults, true); } if (!isValid) { var combinedErrors = string.Join("; ", validationResults.Where(r => !string.IsNullOrEmpty(r.ErrorMessage)).Select(r => r.ErrorMessage)); return new ValidationResult($"集合元素验证失败:{combinedErrors}"); } return ValidationResult.Success; } }
修改SomeClass的属性标记
将自定义属性添加到elements属性上:
public class SomeClass { [DataMember] [JsonProperty(Required = Required.Always)] [ValidateCollectionElements] // 新增自定义验证属性 public IList<AbstractClass> elements { get; init; } }
使用方式
此时直接调用原有验证代码即可,自定义属性会自动处理集合内派生类的验证:
var someClassInstance = new SomeClass { elements = new List<AbstractClass> { new DerivedClass { value = "无效值" } } }; var validationResults = new List<ValidationResult>(); bool isValid = Validator.TryValidateObject(someClassInstance, new ValidationContext(someClassInstance), validationResults, true); // isValid 会正确返回false,validationResults包含派生类属性的验证错误
内容的提问来源于stack exchange,提问作者user16940228
相关产品推荐
相关产品推荐

