c# – 如果我在属性中有验证属性,为什么Validator.TryValidateObject不验证类?

前端之家收集整理的这篇文章主要介绍了c# – 如果我在属性中有验证属性,为什么Validator.TryValidateObject不验证类?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我创建了一个针对类的自定义ValidationAttribute.每当我尝试调用Validator.TryValidateObject时,这都会正确验证.但是当我在我的类中的属性中有其他ValidationAttribute时,验证结果不包含类级别验证的结果.

这是一个示例代码

  1. [AttributeUsage(AttributeTargets.Class,AllowMultiple = false,Inherited = true)]
  2. public class IsHelloWorldAttribute : ValidationAttribute
  3. {
  4. public object _typeId = new object();
  5. public string FirstProperty { get; set; }
  6. public string SecondProperty { get; set; }
  7.  
  8. public IsHelloWorldAttribute(string firstProperty,string secondProperty)
  9. {
  10. this.FirstProperty = firstProperty;
  11. this.SecondProperty = secondProperty;
  12. }
  13.  
  14. public override bool IsValid(object value)
  15. {
  16. PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(value);
  17. string str1 = properties.Find(FirstProperty,true).GetValue(value) as string;
  18. string str2 = properties.Find(SecondProperty,true).GetValue(value) as string;
  19.  
  20. if (string.Format("{0}{1}",str1,str2) == "HelloWorld")
  21. return true;
  22. return false;
  23. }
  24.  
  25. public override object TypeId
  26. {
  27. get
  28. {
  29. return _typeId;
  30. }
  31. }
  32. }

这是我需要验证的类的代码

  1. [IsHelloWorld("Name","Code",ErrorMessage="Is not Hello World")]
  2. public class Myviewmodel : Baseviewmodel
  3. {
  4. string name;
  5. string code;
  6.  
  7. [required]
  8. public string Name
  9. {
  10. get { return model.Name; }
  11. set
  12. {
  13. if (model.Name != value)
  14. {
  15. model.Name = value;
  16. base.RaisePropertyChanged(() => this.Name);
  17. }
  18. }
  19. }
  20.  
  21. public string Code
  22. {
  23. get { return code; }
  24. set
  25. {
  26. if (code != value)
  27. {
  28. code = value;
  29. base.RaisePropertyChanged(() => this.Code);
  30. }
  31. }
  32. }
  33. }

以下是我调用TryValidateObject方法方法

  1. var validationContext = new ValidationContext(this,null,null);
  2. var validationResults = new List<ValidationResult>();
  3. Validator.TryValidateObject(this,validationContext,validationResults,true);

现在,如果我在Name属性中有[required]属性并且我尝试调用Validator.TryValidateObject,则验证结果只有一个,这是required验证的结果.但是当我从Name中删除[required]属性并离开IsHellowWorld属性然后调用TryValidateObject时,它会给我一个结果,那就是HellowWorldValidation的结果.

我需要做的是在类级别和属性级别上获得所有验证.我可以在不实现自己的TryValidateObject方法的情况下实现这一目标吗?

解决方法

这是因为如果检测到属性错误,则检查被短路.这是有道理的,因为类级别验证可能更昂贵,可能涉及回调,其他数据源调用等.

如果检测到属性错误,那么原来的逻辑就会停止.

在System.ComponentModel.DataAnnotations.Validator中:

  1. public static bool TryValidateObject(object instance,ValidationContext validationContext,ICollection<ValidationResult> validationResults,bool validateAllProperties)
  2. {
  3. if (instance == null)
  4. throw new ArgumentNullException("instance");
  5. if (validationContext != null && instance != validationContext.ObjectInstance)
  6. throw new ArgumentException(DataAnnotationsResources.Validator_InstanceMustMatchValidationContextInstance,"instance");
  7. bool flag = true;
  8. bool breakOnFirstError = validationResults == null;
  9. foreach (Validator.ValidationError validationError in Validator.GetObjectValidationErrors(instance,validateAllProperties,breakOnFirstError))
  10. {
  11. flag = false;
  12. if (validationResults != null)
  13. validationResults.Add(validationError.ValidationResult);
  14. }
  15. return flag;
  16. }

请注意对Validator.GetObjectValidationErrors的调用,而Validator.GetObjectValidationErrors又被定义为:

  1. private static IEnumerable<Validator.ValidationError> GetObjectValidationErrors(object instance,bool validateAllProperties,bool breakOnFirstError)
  2. {
  3. if (instance == null)
  4. throw new ArgumentNullException("instance");
  5. if (validationContext == null)
  6. throw new ArgumentNullException("validationContext");
  7. List<Validator.ValidationError> list = new List<Validator.ValidationError>();
  8.  
  9. //Check for property errors here
  10. list.AddRange(Validator.GetObjectPropertyValidationErrors(instance,breakOnFirstError));
  11.  
  12. // Short circuits here if any found
  13. if (Enumerable.Any<Validator.ValidationError>((IEnumerable<Validator.ValidationError>) list))
  14. return (IEnumerable<Validator.ValidationError>) list;
  15.  
  16. // Class level validation occurs below this point
  17. IEnumerable<ValidationAttribute> validationAttributes = Validator._store.GetTypeValidationAttributes(validationContext);
  18. list.AddRange(Validator.GetValidationErrors(instance,validationAttributes,breakOnFirstError));
  19. if (Enumerable.Any<Validator.ValidationError>((IEnumerable<Validator.ValidationError>) list))
  20. return (IEnumerable<Validator.ValidationError>) list;
  21. IValidatableObject validatableObject = instance as IValidatableObject;
  22. if (validatableObject != null)
  23. {
  24. foreach (ValidationResult validationResult in Enumerable.Where<ValidationResult>(validatableObject.Validate(validationContext),(Func<ValidationResult,bool>) (r => r != ValidationResult.Success)))
  25. list.Add(new Validator.ValidationError((ValidationAttribute) null,instance,validationResult));
  26. }
  27. return (IEnumerable<Validator.ValidationError>) list;
  28. }

猜你在找的C#相关文章