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?
Dónde leíste este consejo? –
Ojalá pudiera encontrarlo, pero no puedo. Fue más un comentario sobre la publicación de alguien. ¿Qué piensa usted al respecto? – CrazyDart
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. –