能递归检查DataAnnotations的验证函数

有时在Command和DTO之间层次比较多,写了个验证Command的函数,能实现递归验证.

比如下面这些有层级关系的class定义,能通过一句代码来进行验证:

class A
    {
        [Required]
        public B B { get; set; }
    }

    class B
    {
        [Range(10, 20)]
        public int C { get; set; }

        [Range(typeof(Guid), "00000000-0000-0000-0000-000000000001", "00000000-0000-0000-0000-000000000010")]
        public Guid aa { get; set; }

        public CC ddd { get; set; }
    }
    class CC
    {
        [Range(10, 20)]
        public int DDDDD { get; set; }

        [Required(ErrorMessage = "必须填写用户名")]
        [Display(Name = "用户名")]
        public string UserName { get; set; }

        [Required(ErrorMessage = "必须填写密码")]
        [DataType(DataType.Password)]
        [Display(Name = "密码")]
        public string Password { get; set; }
    }

 

验证函数调用:

List<BrokenRule> errors = obj.IsValid();

 

 

代码如下:

public class BrokenRule
    {
        public string Key { get; set; }
        public string Message { get; set; }
    }

    public static class DataAnnotationHelper
    {
        public static List<BrokenRule> IsValid<T>(this T o, bool only1Level = false)
        {
            return IsValid(typeof(T), o, only1Level);
        }

        private static List<BrokenRule> IsValid(Type t, object o, bool only1Level)
        {
            List<BrokenRule> errors = new List<BrokenRule>();

            var descriptor = GetTypeDescriptor(t);

            foreach (PropertyDescriptor propertyDescriptor in descriptor.GetProperties())
            {
                foreach (var validationAttribute in propertyDescriptor.Attributes.OfType<ValidationAttribute>())
                {
                    if (!validationAttribute.IsValid(propertyDescriptor.GetValue(o)))
                    {
                        BrokenRule error = new BrokenRule();
                        error.Key = propertyDescriptor.Name;
                        error.Message = validationAttribute.FormatErrorMessage(propertyDescriptor.Name);
                        errors.Add(error);
                    }
                }
            }

            if (!only1Level)
            {
                if (o.GetType().IsClass&&!o.GetType().Equals(typeof(string)))
                {
                    foreach (var p in o.GetType().GetProperties())
                    {
                        object pValue = p.GetValue(o, null);
                        if (pValue != null)
                        {
                            List<BrokenRule> pErrors = IsValid(p.PropertyType, pValue, only1Level);
                            errors.AddRange(pErrors);
                        }
                    }
                }
            }

            return errors;
        }
        private static ICustomTypeDescriptor GetTypeDescriptor(Type type)
        {
            return new AssociatedMetadataTypeTypeDescriptionProvider(type).GetTypeDescriptor(type);
        }
    }

 

 效果图:

 

 完整demo代码下载

 

posted @ 2013-10-08 17:48  McKay  阅读(1343)  评论(0编辑  收藏  举报