2011-05-24 17 views
17

Soy nuevo con la anotación de datos. Me gustaría saber si es posible (y cómo) agregar alguna validación de forma dinámica. Es muy extenso explicar por qué, pero tengo un ViewModel que recibe y se opone cuando se crea. En ese objeto debo verificar algunas propiedades y dependiendo de su valor debería tener o no algunas validaciones.ASP.NET MVC 3 Anotación de datos: Agregar validación dinámicamente

Un ejemplo:

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

Respuesta

9

Creo que la forma más sencilla de hacer lo que quería está implementando 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"); 
    } 
} 

Véase también: Class-Level Model Validation with ... ASP.NET MVC 3

+1

El problema es que esto no suma del lado del cliente. Por lo tanto, si ya está utilizando la validación del lado del cliente en función de los atributos, esto ocasiona una experiencia de usuario incoherente. MS lo tiene todo mal atar la validación de los atributos. – xr280xr

+0

Tienes razón. Esto no agrega validación del lado del cliente. Si lo necesita, creo que la mejor manera sería escribir su propia secuencia de comandos para agregar esta validación. – Diego

5

personalizada Atributo:

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


personalizada 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; 
     } 
    } 
} 


Registro encargo DataAnnotationsModelValidatorProvider

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


Utilice esta CustomRequiredIf en la validación modelo de vista

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