2010-12-20 10 views
6

Tengo un proyecto ASP.NET MVC 2 en el que he creado un objeto de transferencia de datos para recibir datos de un formulario de página web. El formulario tiene dos grupos de casillas de verificación. Quiero validar el objeto para asegurarme de que al menos una de las casillas de verificación de cada grupo esté marcada.Un validador MVC de ASP.NET para asegurarse de que al menos una casilla de verificación está marcada

Estoy haciendo la validación en el lado del servidor para que el usuario no pueda hackear ninguna validación del lado del cliente. (Añadiré la validación del lado del cliente con jQuery más tarde; eso es fácil.)

Tengo entendido que tengo que crear mi propio ValidationAttribute personalizado para mi clase de objeto de transferencia de datos, pero no entiendo cómo crear y usar uno que puede aceptar una lista arbitraria de propiedades de casilla de verificación para asegurarse de que al menos uno de ellos sea verdadero. Estoy adivinando voy a tener que llamar a los atributos de este tipo:

[AtLeastOneCheckbox("set1check1", "set1check2", "set1check3", 
    ErrorMessage = "You must check at least one checkbox in set 1.")] 
[AtLeastOneCheckbox("set2check1", "set2check2", "set2check3", "set2check4", "set2check5", 
    ErrorMessage = "You must check at least one checkbox in set 2.")] 
public class MyFormDTO 
{ 
    ... 
} 

¿Cómo sería la implementación de AtLeastOneCheckboxAttribute parece?

¿O hay una manera diferente en que debería hacer este tipo de validación?

+0

Además, me pregunto por qué Microsoft MVC me está empujando a este sistema de validación 'atributo' para todo. Si uso las comprobaciones realizadas por RequiredAttribute y StringLengthAttribute y otros atributos de validación que coloco en cada propiedad, y luego también agrego un método IsValid() a mi objeto que hace otras comprobaciones en las propiedades de este objeto para decidir si es válido. ¿Hay alguna manera de que el modelo de estado refleje el resultado de mi método IsValid()? –

Respuesta

4

si tiene varios grupos de casillas de verificación, solo necesita definir el atributo varias veces.

[AttributeUsage(AttributeTargets.Class)] 
public class AtLeastOneCheckboxAttribute : ValidationAttribute 
{ 
    private string[] _checkboxNames; 

    public AtLeastOneCheckboxAttribute(params string[] checkboxNames) 
    { 
     _checkboxNames = checkboxNames; 
    } 

    protected override ValidationResult IsValid(object value, ValidationContext validationContext) 
    { 
     var propertyInfos = value.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance) 
      .Where(x=>_checkboxNames.Contains(x.Name)); 

     var values = propertyInfos.Select(x => x.GetGetMethod().Invoke(value, null)); 
     if (values.Any(x => Convert.ToBoolean(x))) 
      return ValidationResult.Success; 
     else 
     { 
      ErrorMessage = "At least one checkbox must be selected"; 
      return new ValidationResult(ErrorMessage); 
     } 
    } 
} 

ACTUALIZACIÓN

como has descubierto, la validación de nivel de clase se llama sólo después de pasar todas las propiedades. Para obtener el error, simplemente use una cadena vacía como la clave.

+0

He intentado usar tu código, pero parece que no se ha invocado. Estoy configurando AtLeastOneCheckboxAttribute en mi objeto y luego comprobando ModelState en el controlador, pero el método IsValid() de este atributo nunca se está llamando, aunque mis atributos RequiredAttributes y StringLengthAttributes están generando correctamente mensajes de error. Además, ¿cómo obtendría el mensaje de validación de esto en mi opinión? <% = Html.ValidationMessageFor (Model => Model.Set1Check1)%>, o algo así? –

+0

Encontré una solución para la primera mitad de mi pregunta: aparentemente no se invocan atributos de nivel de clase a menos que pasen todos los atributos de nivel de propiedad. Puedo vivir con ello. Pero todavía estoy tratando de encontrar la forma de obtener el mensaje de error de este atributo en la vista ... –

+0

Ver mi actualización por favor. – Aliostad

0

Su DTO, supongo que su ViewModel puede hacer el IDataErrorInfo. entonces usted puede hacer su validación como esto (tenga en cuenta que no compilar este)

//I'm guessing you have a list of checkboxes 
IEnumerable<bool> checkBoxes1; 
IEnumerable<bool> checkBoxes2; 

public class MyFormDTO : IDataErrorInfo 
{ 
    public string this[string prop] 
    { 
     get 
     { 
      if(prop == "checkBoxes1") 
      { 
       if(checkBoxes1.Any(x => x == true)) 
       { 
        return "Error: You need to select atleast one checkbox from set1"; 
       } 
      } 
      else if(prop == "checkBoxes2") 
      { 
       if(checkBoxes2.Any(x => x == true)) 
       { 
        return "Error: You need to select atleast one checkbox from set2"; 
       } 
      } 
      return null; 
     } 
    } 
    public string Error { get { return null; } } 
} 
Cuestiones relacionadas