代码之家  ›  专栏  ›  技术社区  ›  Keith Rousseau

DataAnnotations中必需的属性似乎不起作用

  •  2
  • Keith Rousseau  · 技术社区  · 14 年前

    我创建了一个DataAnnotationValidator。我正在尝试用一个必需的字段属性测试它,当我的属性为null时,我不能让IsValid属性失败。当我使用指定范围之外的Range属性创建一个数字时,它确实可以正常工作。

    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);
        }
    }
    
    1 回复  |  直到 14 年前
        1
  •  2
  •   Keith Rousseau    14 年前

    我有点愚蠢。我需要将属性的值传递到CheckPropertyIsValid的内部,而不是整个对象。

    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());
        }