Почему валидатор.TryValidateObject не проверяет класс, если у меня есть атрибут проверки в свойстве?

Я создал пользовательский ValidationAttribute, который нацелен на класс. Это проверяет правильно всякий раз, когда я пытаюсь вызвать валидатор.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);
            }
        }
    }
}

вот как я называю Метод TryValidateObject:

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

Теперь, если у меня есть атрибут [Required] в свойстве Name, и я попытался вызвать валидатор.TryValidateObject, результат проверки только один, это результат для требуемой проверки. Но когда я удалил атрибут [Required] из имени и оставил атрибут IsHellowWorld, который затем называется TryValidateObject, он даст мне один результат, и это результат HellowWorldValidation.

что мне нужно сделать, это получите всю проверку на уровне класса и на уровне свойств. Могу ли я достичь этого без реализации собственного метода TryValidateObject?

1 ответов


это потому, что проверка закорочена, если обнаружены ошибки свойств. Это имеет смысл, поскольку проверка уровня класса может быть более дорогостоящей, потенциально включая обратные вызовы, другие вызовы источников данных и т. д.

Если ошибка свойства была обнаружена, то логика, как она стоит просто стоит.

В Рамках Системы.ComponentModel.DataAnnotations.Валидатор:

 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, validationContext, validateAllProperties, breakOnFirstError))
      {
        flag = false;
        if (validationResults != null)
          validationResults.Add(validationError.ValidationResult);
      }
      return flag;
    }

обратите внимание на вызов Validator.GetObjectValidationErrors, который, в свою очередь, определяется as:

     private static IEnumerable<Validator.ValidationError> GetObjectValidationErrors(object instance, ValidationContext validationContext, 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, validationContext, validateAllProperties, 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, validationContext, 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;
        }