ASP.NET MVC 3 Data Annotation: Add validation dynamically
I'm new with data annotation. I'd like to know if it possible (and how) to add some validation dynamically. It is very extensive to explain why, but I've a ViewModel that receives and object 开发者_如何学编程when created. In that object I must check for some property and depending its value I should have or not some validations.
An example:
public class ProfileViewModel
{
[Required(ErrorMessage = "The field {0} is required")]
[Display(Name = "Client Code")]
public int ClientCode { get; set; }
[Required(ErrorMessage = "The field {0} is required")]
[StringLength(100, ErrorMessage = "The field {0} must have up to 100 characters.")]
[Display(Name = "Company")]
public string Company { get; set; }
[StringLength(50, ErrorMessage = "The field {0} must have up to 50 characters.")]
[Display(Name = "Name")]
public string Name { get; set; }
[StringLength(50, ErrorMessage = "The field {0} must have up to 50 characters.")]
[Display(Name = "LastName")]
public string LastName { get; set; }
public ProfileViewModel(User usr)
{
if (usuario.ClientCode != null)
{
ClientCode = Convert.ToInt32(usr.ClientCode);
}
else
{
//ClientCode and Company are not yet required.
//Name and LastName are now required.
}
Company = usr.Company;
Name = usr.Name;
LastName = usr.LastName;
}
}
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; }
Heres the updated MVC 3 version of that blog post http://blogs.msdn.com/b/simonince/archive/2011/02/04/conditional-validation-in-asp-net-mvc-3.aspx
精彩评论