2011-06-27 5 views
14

Leo en alguna publicación, pero ahora no puedo encontrarla que en MVC 3 no era realmente necesaria para crear un Validator, solo el Atributo. ¿Es esto cierto? Sí digo que me resulta confuso que el atributo tenga IClientValidatable en él. Entonces, ¿qué hace la clase DataAnnotationsModelValidator si la anotación tiene el nombre del script del lado del cliente (IClientValidatable) y la capacidad de validar (ValidationAttribute IsValid)?MVC 2 vs MVC 3 atributos de validación personalizados utilizando DataAnnotationsModelValidatorProvider.RegisterAdapter

Sería muy bueno si no tuviera que registrar el atributo con el Validator en el global. Se puede hacer esto? ¿Leí algunos consejos malos?

EDITAR: Curiosamente acabo de probarlo excluyendo el validador, puse toda la lógica en IsValid y funciona muy bien. Supongo que lo único que podría faltar sería el contexto del controlador, pero no estoy seguro de que sea útil en la validación. IsValid tiene ValidationContext que tiene ServiceContainer si necesito un servicio. ¿Alguna desventaja real que no estoy recogiendo aquí?

EDIT 2: que se iniciará con un validador de este ejemplo: http://blogs.msdn.com/b/simonince/archive/2010/06/04/conditional-validation-in-mvc.aspx

El Atributo:

public class RequiredIfAttribute : ValidationAttribute, IClientValidatable 
{ 
    private RequiredAttribute innerAttribute = new RequiredAttribute(); 
    public string DependentProperty { get; set; } 
    public object TargetValue { get; set; } 

    public RequiredIfAttribute(string dependentProperty, object targetValue) 
    { 
     this.DependentProperty = dependentProperty; 
     this.TargetValue = targetValue; 
    } 

    public override bool IsValid(object value) 
    { 
     return innerAttribute.IsValid(value); 
    } 

    public System.Collections.Generic.IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) 
    { 
     ModelClientValidationRule modelClientValidationRule = new ModelClientValidationRule() 
     { 
      ErrorMessage = FormatErrorMessage(metadata.DisplayName), 
      ValidationType = "requiredifattribute" 
     }; 
     modelClientValidationRule.ValidationParameters.Add("requiredifattribute", DependentProperty); 
     yield return modelClientValidationRule; 
    } 
} 

El Validador:

public class RequiredIfValidator : DataAnnotationsModelValidator<RequiredIfAttribute> 
{ 
    public RequiredIfValidator(ModelMetadata metadata, ControllerContext context, RequiredIfAttribute attribute) 
     : base(metadata, context, attribute) 
    { 
    } 

    public override IEnumerable<ModelClientValidationRule> GetClientValidationRules() 
    { 
     return base.GetClientValidationRules(); 
    } 

    public override IEnumerable<ModelValidationResult> Validate(object container) 
    { 
     var field = Metadata.ContainerType.GetProperty(Attribute.DependentProperty); 
     if (field != null) 
     { 
      var value = field.GetValue(container, null); 
      if ((value == null && Attribute.TargetValue == null) || 
       (value.Equals(Attribute.TargetValue))) 
      { 
       if (!Attribute.IsValid(Metadata.Model)) 
        yield return new ModelValidationResult { Message = ErrorMessage }; 
      } 
     } 
    } 
} 

Con el actual código anterior, debe registrarse en el archivo Global.asax.cs:

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

Pero si muevo todo en sólo el atributo, no tengo que registrarlo:

public class RequiredIfAttribute : ValidationAttribute, IClientValidatable 
{ 
    private RequiredAttribute innerAttribute = new RequiredAttribute(); 
    public string DependentProperty { get; set; } 
    public object TargetValue { get; set; } 

    public RequiredIfAttribute(string dependentProperty, object targetValue) 
    { 
     this.DependentProperty = dependentProperty; 
     this.TargetValue = targetValue; 
    } 

    protected override ValidationResult IsValid(object value, ValidationContext validationContext) 
    { 
     var field = validationContext.ObjectInstance.GetType().GetProperty(DependentProperty); 
     if (field != null) 
     { 
      var dependentValue = field.GetValue(validationContext.ObjectInstance, null); 
      if ((dependentValue == null && TargetValue == null) || 
       (dependentValue.Equals(TargetValue))) 
      { 
       if (!innerAttribute.IsValid(value)) 
        return new ValidationResult(ErrorMessage); 
      } 
     } 
     return ValidationResult.Success; 
    } 

    public System.Collections.Generic.IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) 
    { 
     ModelClientValidationRule modelClientValidationRule = new ModelClientValidationRule() 
     { 
      ErrorMessage = FormatErrorMessage(metadata.DisplayName), 
      ValidationType = "requiredifattribute" 
     }; 
     modelClientValidationRule.ValidationParameters.Add("requiredifattribute", DependentProperty); 
     yield return modelClientValidationRule; 
    } 
} 

¿Hay un problema con el último bit de código de sustitución de todos los otros códigos? ¿Por qué debería mantener la clase de validador?

+0

Dónde leíste este consejo? –

+0

Ojalá pudiera encontrarlo, pero no puedo. Fue más un comentario sobre la publicación de alguien. ¿Qué piensa usted al respecto? – CrazyDart

+0

por el momento no creo nada ya que todavía estoy tratando de entender cuál es el problema/pregunta.Solo esperaba ver un poco más de contexto, ejemplos de códigos particulares, etc., es por eso que pedí la fuente para tratar de ver más contexto ya que no me has proporcionado suficiente en tu pregunta. Esperemos que proporciones un ejemplo de código específico que ilustre el problema que estás enfrentando. –

Respuesta

10

CrazyDart,

Se añadió la interfaz IClientValidatable en MVC3.

Su segundo ejemplo muestra un uso válido de esta nueva interfaz. Tiene razón en que no tiene que estar registrado, y proporcionará las reglas necesarias del lado del cliente para la validación, además de realizar la validación necesaria del lado del servidor.

Adelante, disfrútalo.

counsellorben

+1

Bueno, resulta que estás en lo cierto. Usaré IClientValidatable, y me veré bien mientras lo hago. ;-) – CrazyDart

+1

Creo que IClientValidatable aún requiere que se agregue una secuencia de comandos del lado del cliente para el adaptador de validación de jquery y los métodos de validación según mi comprensión de IClientValidatable. – afr0

0

Cuando uso la última opción de CrazyDart la parte del lado del servidor funciona muy bien en MVC4.

Excepto que no puedo obtener la validación del lado del cliente para que funcione. Nunca busca un campo obligatorio en el lado del cliente (aunque hay algunas etiquetas agregadas).

También hemos comprobado la segunda entrada del blog (primera es la inspiración del cartel) de Simón Ince en esto: http://blogs.msdn.com/b/simonince/archive/2011/02/04/conditional-validation-in-asp-net-mvc-3.aspx

Cuestiones relacionadas