我创建了一个针对类的自定义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;
- }