我创建了一个针对类的自定义ValidationAttribute.每当我尝试调用Validator.TryValidateObject时,这都会正确验证.但是当我在我的类中的属性中有其他ValidationAttribute时,验证结果不包含类级别验证的结果.
这是一个示例代码:
[AttributeUsage(AttributeTargets.Class,AllowMultiple = false,Inherited = true)] public class IsHelloWorldAttribute : ValidationAttribute { public object _typeId = new object(); public string FirstProperty { get; set; } public string SecondProperty { get; set; } public IsHelloWorldAttribute(string firstProperty,string secondProperty) { this.FirstProperty = firstProperty; this.SecondProperty = secondProperty; } public override bool IsValid(object value) { PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(value); string str1 = properties.Find(FirstProperty,true).GetValue(value) as string; string str2 = properties.Find(SecondProperty,true).GetValue(value) as string; if (string.Format("{0}{1}",str1,str2) == "HelloWorld") return true; return false; } public override object TypeId { get { return _typeId; } } }
这是我需要验证的类的代码
[IsHelloWorld("Name","Code",ErrorMessage="Is not Hello World")] public class Myviewmodel : Baseviewmodel { string name; string code; [required] public string Name { get { return model.Name; } set { if (model.Name != value) { model.Name = value; base.RaisePropertyChanged(() => this.Name); } } } public string Code { get { return code; } set { if (code != value) { code = value; base.RaisePropertyChanged(() => this.Code); } } } }
var validationContext = new ValidationContext(this,null,null); var validationResults = new List<ValidationResult>(); Validator.TryValidateObject(this,validationContext,validationResults,true);
现在,如果我在Name属性中有[required]属性并且我尝试调用Validator.TryValidateObject,则验证结果只有一个,这是required验证的结果.但是当我从Name中删除[required]属性并离开IsHellowWorld属性然后调用TryValidateObject时,它会给我一个结果,那就是HellowWorldValidation的结果.
我需要做的是在类级别和属性级别上获得所有验证.我可以在不实现自己的TryValidateObject方法的情况下实现这一目标吗?
解决方法
这是因为如果检测到属性错误,则检查被短路.这是有道理的,因为类级别验证可能更昂贵,可能涉及回调,其他数据源调用等.
在System.ComponentModel.DataAnnotations.Validator中:
public static bool TryValidateObject(object instance,ValidationContext validationContext,ICollection<ValidationResult> validationResults,bool validateAllProperties) { if (instance == null) throw new ArgumentNullException("instance"); if (validationContext != null && instance != validationContext.ObjectInstance) throw new ArgumentException(DataAnnotationsResources.Validator_InstanceMustMatchValidationContextInstance,"instance"); bool flag = true; bool breakOnFirstError = validationResults == null; foreach (Validator.ValidationError validationError in Validator.GetObjectValidationErrors(instance,validateAllProperties,breakOnFirstError)) { flag = false; if (validationResults != null) validationResults.Add(validationError.ValidationResult); } return flag; }
请注意对Validator.GetObjectValidationErrors的调用,而Validator.GetObjectValidationErrors又被定义为:
private static IEnumerable<Validator.ValidationError> GetObjectValidationErrors(object instance,bool validateAllProperties,bool breakOnFirstError) { if (instance == null) throw new ArgumentNullException("instance"); if (validationContext == null) throw new ArgumentNullException("validationContext"); List<Validator.ValidationError> list = new List<Validator.ValidationError>(); //Check for property errors here list.AddRange(Validator.GetObjectPropertyValidationErrors(instance,breakOnFirstError)); // Short circuits here if any found if (Enumerable.Any<Validator.ValidationError>((IEnumerable<Validator.ValidationError>) list)) return (IEnumerable<Validator.ValidationError>) list; // Class level validation occurs below this point IEnumerable<ValidationAttribute> validationAttributes = Validator._store.GetTypeValidationAttributes(validationContext); list.AddRange(Validator.GetValidationErrors(instance,validationAttributes,breakOnFirstError)); if (Enumerable.Any<Validator.ValidationError>((IEnumerable<Validator.ValidationError>) list)) return (IEnumerable<Validator.ValidationError>) list; IValidatableObject validatableObject = instance as IValidatableObject; if (validatableObject != null) { foreach (ValidationResult validationResult in Enumerable.Where<ValidationResult>(validatableObject.Validate(validationContext),(Func<ValidationResult,bool>) (r => r != ValidationResult.Success))) list.Add(new Validator.ValidationError((ValidationAttribute) null,instance,validationResult)); } return (IEnumerable<Validator.ValidationError>) list; }