代码之家  ›  专栏  ›  技术社区  ›  David Neale

MVC2模型验证互斥的必需注释

  •  1
  • David Neale  · 技术社区  · 14 年前

    有人知道一个好的算法,可以用 ModelValidator ?

    类似:

        [EitherPropertyRequired("BuildingNumber","BuildingName"]
        public class Address{
           public int BuildingNumber { get; set; }
           public string BuildingName { get; set; }
       }
    
    2 回复  |  直到 14 年前
        1
  •  2
  •   David Neale    14 年前

    我最终创建了一个属性并用一个自定义的 ModelValidator . 使用 AssociatedValidatorProvider 注册地: Application_Start() .

    protected void Application_Start()
    {
        ModelValidatorProviders.Providers.Add(new ZipValidationProvider());
    }
    
    public class ZipValidationProvider:AssociatedValidatorProvider
    {
        protected override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context, IEnumerable<Attribute> attributes)
        {
            foreach (var attribute in attributes.OfType<EitherPropertyRequiredAttribute>())
            {
                yield return new EitherPropertyRequiredValidator(metadata,
                    context, attribute.FirstProperty, attribute.SecondProperty, attribute.Message);
            }
        }
    }
    
    [AttributeUsage(AttributeTargets.Class)]
    public class EitherPropertyRequiredAttribute : Attribute
    {
        public readonly string FirstProperty;
        public readonly string SecondProperty;
        public readonly string Message;
    
        public EitherPropertyRequiredAttribute(string firstProperty, string secondProperty, 
            string message)
        {
            FirstProperty = firstProperty;
            SecondProperty = secondProperty;
            Message = message;
        }
    }
    
    public class EitherPropertyRequiredValidator:ModelValidator
    {
        private readonly string firstProperty;
        private readonly string secondProperty;
        private readonly string message;
    
        public EitherPropertyRequiredValidator(ModelMetadata metadata,
                                        ControllerContext context,
            string firstProperty, 
            string secondProperty,
            string message)
            :base(metadata,context)
        {
            this.firstProperty = firstProperty;
            this.secondProperty = secondProperty;
            this.message = message;
        }
    
        private PropertyInfo GetPropertyInfoRecursive(Type type, string property)
        {
            var prop = type.GetProperty(property);
            if (prop != null) return prop;
    
            foreach (var p in type.GetProperties())
            {
                if (p.PropertyType.Assembly == typeof (object).Assembly)
                    continue;
    
                return GetPropertyInfoRecursive(p.PropertyType, property);
            }
    
            return null;
        }
    
        private object GetPropertyValueRecursive(object obj, PropertyInfo propertyInfo)
        {
            Type objectType = obj.GetType();
    
           if(objectType.GetProperty(propertyInfo.Name) != null)
                return propertyInfo.GetValue(obj, null);
    
            foreach (var p in objectType.GetProperties())
            {
                if (p.PropertyType.Assembly == typeof(object).Assembly)
                    continue;
    
                var o = p.GetValue(obj,null);
                return GetPropertyValueRecursive(o, propertyInfo);
            }
    
            return null;
        }
    
        public override IEnumerable<ModelValidationResult> Validate(object container)
        {
            if (Metadata.Model == null)
                yield break;
    
            var firstPropertyInfo = GetPropertyInfoRecursive(Metadata.Model.GetType(),firstProperty);
            if(firstPropertyInfo == null)
                throw new InvalidOperationException("Unknown property:" + firstProperty);
    
            var secondPropertyInfo = GetPropertyInfoRecursive(Metadata.Model.GetType(),secondProperty);
            if(secondPropertyInfo == null)
                throw new InvalidOperationException("Unknown property:" + secondProperty);
    
            var firstPropertyValue = GetPropertyValueRecursive(Metadata.Model, firstPropertyInfo);
            var secondPropertyValue = GetPropertyValueRecursive(Metadata.Model, secondPropertyInfo);
    
            bool firstPropertyIsEmpty = firstPropertyValue == null ||
                                        firstPropertyValue.ToString().Length == 0;
    
            bool secondPropertyIsEmpty = secondPropertyValue == null ||
                                         secondPropertyValue.ToString().Length == 0;
    
            if (firstPropertyIsEmpty && secondPropertyIsEmpty)
            {
                    yield return new ModelValidationResult
                    {
                        MemberName = firstProperty,
                        Message = message
                    };
            }
        }
    }
    
        2
  •  1
  •   Darin Dimitrov    14 年前
    [AttributeUsage(AttributeTargets.Class)]
    public class EitherPropertyRequiredAttribute : ValidationAttribute
    {
        public override bool IsValid(object value)
        {
            // value will be the model
    
            Address address = (Address)value;
    
            // TODO: Check the properties of address here and return true or false
    
            return true;
        }
    }
    

    您可以通过避免将其强制转换为地址并使用属性属性和反射来使其更通用。