2010-06-25 135 views
2

我有我创建的DataAnnotationValidator。我目前正在尝试使用必填字段属性进行测试,并且当我的属性为空时,我无法使IsValid属性失败。当我创建一个范围属性超出指定范围的数字时,它确实工作正常。DataAnnotations中的必需属性似乎不起作用

public class TestEntityWithDataAnnotations 
{ 
    public Guid Id { get; set; } 

    [Required(ErrorMessage = "Required")] 
    public string Name { get; set; } 
} 

[TestFixture] 
public class DataAnnotationValidatorTest 
{ 
    [Test] 
    public void Validate_ReturnsFailure_WhenPropertyValidationIsNotValid() 
    { 
     var validator = new DataAnnotationValidator(); 
     var invalidEntity = new TestEntityWithDataAnnotations 
     { 
      Id = Guid.NewGuid() 
     }; 
     var validationResult = validator.Validate(invalidEntity); 

     Assert.IsFalse(validationResult.IsValid); 
    } 
} 

public class DataAnnotationValidator 
{ 
    public ValidationResult Validate(object obj) 
    { 
     Type objType = obj.GetType();    
     var typeDescriptor = GetTypeDescriptor(obj, objType); 
     var validationResult = new ValidationResult(); 

     var classValidationResult = CheckClassIsValid(obj, typeDescriptor); 
     if (!classValidationResult.IsValid) 
     { 
      validationResult.AddErrors(classValidationResult.Errors); 
     } 
     foreach (PropertyDescriptor propertyDescriptor in typeDescriptor.GetProperties()) 
     { 
      // Loop over all of the properties on our object that have Validation Attributes 
      var propValidationResult = CheckPropertyIsValid(obj, propertyDescriptor); 
      if(!propValidationResult.IsValid) 
      { 
       validationResult.AddErrors(propValidationResult.Errors); 
      } 
     } 
     return validationResult; 
    } 

    /// <summary> 
    /// Checks to see if there are any class level validation attributes and runs them 
    /// </summary> 
    /// <returns></returns> 
    private static ValidationResult CheckClassIsValid(object obj, ICustomTypeDescriptor typeDescriptor) 
    { 
     var errors = typeDescriptor.GetAttributes().OfType<ValidationAttribute>() 
      .Where(x => !x.IsValid(obj)) 
      .Select(x => new ValidationError(typeDescriptor.GetClassName(), x.ErrorMessage)); 
     return new ValidationResult(errors.ToList()); 
    } 

    /// <summary> 
    /// Checks to see if a property has any DataAnnotations that it has violated 
    /// </summary> 
    private static ValidationResult CheckPropertyIsValid(object obj, PropertyDescriptor propertyDescriptor) 
    { 
     var errors = propertyDescriptor.Attributes.OfType<ValidationAttribute>() 
      .Where(x => !x.IsValid(obj)) 
      .Select(x => new ValidationError(propertyDescriptor.Name, x.ErrorMessage)); 
     return new ValidationResult(errors.ToList()); 
    } 

    /// <summary> 
    /// Gets the model's type descriptor. In order to support the buddy class metadata model 
    /// for LINQ to SQL and Entity Framework, it uses 
    /// <see cref="AssociatedMetadataTypeTypeDescriptionProvider"/>. 
    /// </summary> 
    /// <param name="obj">The model object</param> 
    /// <param name="objType">The type of the model object</param> 
    /// <returns>The model's type descriptor</returns> 
    private static ICustomTypeDescriptor GetTypeDescriptor(object obj, Type objType) 
    { 
     var provider = new AssociatedMetadataTypeTypeDescriptionProvider(objType); 
     return provider.GetTypeDescriptor(objType, obj); 
    } 
} 

回答

2

我有点愚蠢。我需要将属性的值传递给CheckPropertyIsValid中的IsValid而不是整个对象。

private static ValidationResult CheckPropertyIsValid(object obj, PropertyDescriptor propertyDescriptor) 
    { 
     var errors = propertyDescriptor.Attributes.OfType<ValidationAttribute>() 
      .Where(x => !x.IsValid(propertyDescriptor.GetValue(obj))) 
      .Select(x => new ValidationError(propertyDescriptor.Name, x.ErrorMessage)); 
     return new ValidationResult(errors.ToList()); 
    }