2010-01-05 23 views
7

Actualmente estoy intentando trabajar con la validación MVC, y me estoy enfrentando a algunos problemas donde se requiere un campo dependiendo del valor de otro campo. A continuación, se incluye un ejemplo (que aún no he descifrado): si PaymentMethod == "Check", se debe solicitar ChequeName; de ​​lo contrario, se puede pasar.Validación Asp.Net MVC - campos dependientes

[Required(ErrorMessage = "Payment Method must be selected")] 
public override string PaymentMethod 
{ get; set; } 

[Required(ErrorMessage = "ChequeName is required")] 
public override string ChequeName 
{ get; set; } 

estoy usando los System.ComponentModel.DataAnnotations para el [Obligatorio], y también se han extendido una ValidationAttribute para tratar de conseguir este trabajo, pero no puedo pasar una variable a través de hacer la validación (extensión a continuación)

public class JEPaymentDetailRequired : ValidationAttribute 
{ 
    public string PaymentSelected { get; set; } 
    public string PaymentType { get; set; } 

    public override bool IsValid(object value) 
    { 
     if (PaymentSelected != PaymentType) 
      return true; 
     var stringDetail = (string) value; 
     if (stringDetail.Length == 0) 
      return false; 
     return true; 
    } 
} 

Implementación:

[JEPaymentDetailRequired(PaymentSelected = PaymentMethod, PaymentType = "Cheque", ErrorMessage = "Cheque name must be completed when payment type of cheque")] 

alguien ha tenido experiencia con este tipo de validación? ¿Sería mejor escribirlo en el controlador?

Gracias por su ayuda.

+0

Pensándolo bien ... ¿Cómo se puede configurar PaymentSelected = PaymentMethod? Debería recibir un error porque PaymentMethod no es una expresión constante. – Min

+0

Hola Min, tienes razón. Pensé que podría hacerlo de esta manera, pero no funciona. Solo quería mostrar lo que había intentado, pero también comenté que no me permitiría pasar la variable. –

Respuesta

3

Escribiría la lógica de validación en el modelo, no en el controlador. El controlador solo debe manejar la interacción entre la vista y el modelo. Dado que es el modelo que requiere validación, creo que es ampliamente considerado como el lugar para la lógica de validación.

Para la validación que depende del valor de otra propiedad o campo, desafortunadamente no veo cómo evitar completamente escribir algún código para eso en el modelo, como se muestra en el libro Wrox ASP.NET MVC, tipo de como:

public bool IsValid 
{ 
    get 
    { 
    SetRuleViolations(); 
    return (RuleViolations.Count == 0); 
    } 
} 

public void SetRuleViolations() 
{ 
    if (this.PaymentMethod == "Cheque" && String.IsNullOrEmpty(this.ChequeName)) 
    { 
    RuleViolations.Add("Cheque name is required", "ChequeName"); 
    } 
} 

Hacer todas las validaciones declarativamente sería genial. Estoy seguro de que podría hacer un RequiredDependentAttribute, pero eso solo manejaría este tipo de lógica. Las cosas que son incluso un poco más complejas requerirían otro atributo bastante específico, etc. que se vuelve loco rápidamente.

+0

gracias djuth, tomé un ModelStateDictionary y realicé la validación con esto en el modelo, y luego pasé el diccionario de nuevo al controlador para fusionarlo con el ModelState. Parece hacer el truco y me permite hacer un trabajo programático, no tan agradable como hacer una declaración por atributo, pero al menos puedo obtener todo en un solo lugar. No estoy seguro de cómo va a funcionar si hay más de un error por atributo. –

2

Su problema se puede resolver de manera relativamente sencilla mediante el uso de conditional validation attribute, p.

[RequiredIf("PaymentMethod == 'Cheque'")] 
public string ChequeName { get; set; } 
4

Si desea validación del lado del cliente, además de modelo de validación en el servidor, creo que el mejor camino a seguir es un atributo de validación personalizada (como sugirió Jaroslaw). Incluyo aquí la fuente de la que uso.

atributo personalizado:

public class RequiredIfAttribute : DependentPropertyAttribute 
{ 
    private readonly RequiredAttribute innerAttribute = new RequiredAttribute(); 

    public object TargetValue { get; set; } 


    public RequiredIfAttribute(string dependentProperty, object targetValue) : base(dependentProperty) 
    { 
     TargetValue = targetValue; 
    } 


    protected override ValidationResult IsValid(object value, ValidationContext validationContext) 
    { 
     // get a reference to the property this validation depends upon 
     var containerType = validationContext.ObjectInstance.GetType(); 
     var field = containerType.GetProperty(DependentProperty); 

     if (field != null) 
     { 
      // get the value of the dependent property 
      var dependentvalue = field.GetValue(validationContext.ObjectInstance, null); 

      // compare the value against the target value 
      if ((dependentvalue == null && TargetValue == null) || 
       (dependentvalue != null && dependentvalue.Equals(TargetValue))) 
      { 
       // match => means we should try validating this field 
       if (!innerAttribute.IsValid(value)) 
        // validation failed - return an error 
        return new ValidationResult(ErrorMessage, new[] { validationContext.MemberName }); 
      } 
     } 

     return ValidationResult.Success; 
    } 

    public override IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) 
    { 
     var rule = new ModelClientValidationRule 
         { 
          ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()), 
          ValidationType = "requiredif" 
         }; 

     var depProp = BuildDependentPropertyId(DependentProperty, metadata, context as ViewContext); 

     // find the value on the control we depend on; 
     // if it's a bool, format it javascript style 
     // (the default is True or False!) 
     var targetValue = (TargetValue ?? "").ToString(); 
     if (TargetValue != null) 
      if (TargetValue is bool) 
       targetValue = targetValue.ToLower(); 

     rule.ValidationParameters.Add("dependentproperty", depProp); 
     rule.ValidationParameters.Add("targetvalue", targetValue); 

     yield return rule; 
    } 
} 

extensión de la validación de jQuery:

$.validator.unobtrusive.adapters.add('requiredif', ['dependentproperty', 'targetvalue'], function (options) { 
    options.rules['requiredif'] = { 
     dependentproperty: options.params['dependentproperty'], 
     targetvalue: options.params['targetvalue'] 
    }; 
    options.messages['requiredif'] = options.message; 
}); 

$.validator.addMethod('requiredif', 
    function (value, element, parameters) { 
     var id = '#' + parameters['dependentproperty']; 

     // get the target value (as a string, 
     // as that's what actual value will be) 
     var targetvalue = parameters['targetvalue']; 
     targetvalue = (targetvalue == null ? '' : targetvalue).toString(); 

     // get the actual value of the target control 
     var actualvalue = getControlValue(id); 

     // if the condition is true, reuse the existing 
     // required field validator functionality 
     if (targetvalue === actualvalue) { 
      return $.validator.methods.required.call(this, value, element, parameters); 
     } 

     return true; 
    } 
); 

Decoración de una propiedad con el atributo:

[Required] 
public bool IsEmailGiftCertificate { get; set; } 

[RequiredIf("IsEmailGiftCertificate", true, ErrorMessage = "Please provide Your Email.")] 
public string YourEmail { get; set; } 
+0

Me doy cuenta de que esta respuesta tiene 2 años, pero estoy tratando de hacer que esto funcione y, básicamente, dispara la validación de la propiedad dependiente sin importar el valor de la primera propiedad. Cualquier ayuda sería apreciada. –

3

sólo tiene que utilizar la biblioteca de validación de toda prueba que está disponible en CodePlex : https://foolproof.codeplex.com/

Es compatible con los siguientes atributos de validación "requiredif"/decoraciones:

[RequiredIf] 
[RequiredIfNot] 
[RequiredIfTrue] 
[RequiredIfFalse] 
[RequiredIfEmpty] 
[RequiredIfNotEmpty] 
[RequiredIfRegExMatch] 
[RequiredIfNotRegExMatch] 

para empezar es fácil:

  1. descargar el paquete desde el enlace proporcionado
  2. Añadir una referencia a la archivo .dll incluido
  3. Importar los archivos javascript incluidos
  4. Asegúrese de que su vi ews hace referencia a los archivos javascript incluidos desde su HTML para una validación javascript y jquery discreta.
Cuestiones relacionadas