ASP.NET MVC 3 Data Annotation: Add validation dynamically ASP.NET MVC 3 Data Annotation: Add validation dynamically asp.net asp.net

ASP.NET MVC 3 Data Annotation: Add validation dynamically


I think that the simplest way of doing what I wanted is implementing IValidatableObject:

public class Product : IValidatableObject{    public int Prop1 { get; set; }    public int Prop2 { get; set; }    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)    {        if (Prop1 < Prop2)            yield return new ValidationResult("Property 1 can't be less than Property 2");    }}

See also: Class-Level Model Validation with ... ASP.NET MVC 3


Custom Attribute:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)]public class CustomRequiredIfAttribute : CustomAttribute{    private RequiredAttribute innerAttribute = new RequiredAttribute();    public string DependentProperty { get; set; }    public object TargetValue { get; set; }    public CustomRequiredIfAttribute()    {    }    public CustomRequiredIfAttribute(string dependentProperty, object targetValue)        : base()    {        this.DependentProperty = dependentProperty;        this.TargetValue = targetValue;    }    public override bool IsValid(object value)    {        return innerAttribute.IsValid(value);    }}


Custom RequiredIfValidator

using System;using System.Collections.Generic;using System.Web.Mvc;namespace Custom.Web.Validation{    public class RequiredIfValidator : DataAnnotationsModelValidator<CustomRequiredIfAttribute>    {        public RequiredIfValidator(ModelMetadata metadata, ControllerContext context, CustomRequiredIfAttribute attribute)            : base(metadata, context, attribute)        {        }        public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()        {            return base.GetClientValidationRules();        }        public override IEnumerable<ModelValidationResult> Validate(object container)        {            // get a reference to the property this validation depends upon            var field = Metadata.ContainerType.GetProperty(Attribute.DependentProperty);            if (field != null)            {                // get the value of the dependent property                object value = field.GetValue(container, null);                // compare the value against the target value                if (this.IsEqual(value) || (value == null && Attribute.TargetValue == null))                {                    // match => means we should try validating this field                    if (!Attribute.IsValid(Metadata.Model))                    {                        // validation failed - return an error                        yield return new ModelValidationResult { Message = ErrorMessage };                    }                }            }        }        private bool IsEqual(object dependentPropertyValue)        {            bool isEqual = false;            if (Attribute.TargetValue != null && Attribute.TargetValue.GetType().IsArray)            {                foreach (object o in (Array)Attribute.TargetValue)                {                    isEqual = o.Equals(dependentPropertyValue);                    if (isEqual)                    {                        break;                    }                }            }            else            {                isEqual = Attribute.TargetValue.Equals(dependentPropertyValue);            }            return isEqual;        }    }}


Register custom DataAnnotationsModelValidatorProvider

DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(CustomRequiredIfAttribute), typeof(RequiredIfValidator));


Use this CustomRequiredIf in the ViewModel

[CustomRequiredIf("CategoryId", 3, ErrorMessageResourceName = GlobalResourceLiterals.AccountGroup_Required)]public string AccountGroup { get; set; }