2009-10-13 37 views
27

Estoy usando la validación de anotación de datos extensamente en ASP.NET MVC 2. Esta nueva característica ha sido un gran ahorro de tiempo, ya que ahora puedo definir la validación del lado del cliente y la validación del lado del servidor en un solo lugar. Sin embargo, mientras hacía algunas pruebas detalladas, me di cuenta de que es bastante fácil para alguien eludir la validación del lado del servidor si dependiera solo de la validación de la Anotación de datos. Por ejemplo, si definí un campo obligatorio anotando la propiedad con el atributo [Obligatorio] y coloqué un cuadro de texto para ese campo obligatorio en un formulario, un usuario simplemente podría eliminar el cuadro de texto del DOM (que puede hacerse fácilmente a través de Firebug) y ahora la validación de anotación de datos no se activará en esa propiedad durante el enlace modelo dentro de un controlador. Para asegurar que se active la validación "requerida", puedo repetir la validación después de que ocurre la vinculación del modelo, pero entonces estaría repitiendo mi lógica de validación.ASP.NET MVC: ¿Es suficiente la validación de anotación de datos?

¿Cuál es la recomendación de todos sobre la validación? ¿La validación de anotación de datos es suficiente? ¿O es necesario repetir la validación para garantizar que las validaciones se activen en todas las situaciones?

Seguimiento comentario: Sobre la base de las respuestas a continuación, parece que no puedo confiar en la validación del modelo Binder y anotación de datos solo. Dado que estamos concluyendo que se requiere una validación adicional del lado del servidor, ¿hay alguna manera fácil para que mi capa de Servicio active la validación en función de lo que se ha definido en las Anotaciones de datos? Parece que esto nos dará lo mejor de ambas palabras ... no necesitaremos repetir el código de validación, pero aún así nos aseguraremos de que la validación se ejecute incluso si la Carpeta del modelo no la desencadena.

Voy a publicar este comentario de seguimiento como una pregunta separada, ya que plantea una pregunta diferente a la original.

+0

respuesta de Koritnik responde a la consulta de seguimiento. Hago mi validación similar a la respuesta que publicó. La misma definición de DataAnnotation se puede usar tanto para la validación del servidor como del cliente. –

+1

La validación de la anotación de datos está bien si los atributos de validación provistos y el marco mismo le conviene. El comportamiento con Required se modificó para ASP.NET MVC 2 RTM debido a los comentarios de la comunidad, por lo que [Obligatorio] ahora funciona como era de esperar. Opcionalmente, echa un vistazo a: Validation Block (Enterprise Library), xVal, NHibernate Validators (supuestamente no tiene dependencia de NHibernate ORM). – miha

+0

'" Voy a publicar este comentario de seguimiento como una pregunta separada, ya que plantea una pregunta diferente a la original "." Un enlace a eso no sería una mala idea, ¿eh? – Sinjai

Respuesta

18

creo que sea vigilante en cuanto a la seguridad que debe elegir para usted, la validación del servidor es la prioridad y asegúrese de que este sea siempre su respaldo. La validación de su servidor debería funcionar sin la validación del cliente. La validación del cliente es más para UX y eso es primordial para su diseño, es secundario a la seguridad. Con esto en mente, se encontrará repitiendo su validación. Un objetivo a menudo es tratar de diseñar su aplicación para que la validación del servidor y del cliente pueda integrarse tanto como sea posible para reducir el trabajo requerido para validar en el servidor y el cliente. Pero ten la seguridad de que debes hacer ambas cosas.

Si eludir la validación del cliente (mediante la manipulación DOM) es evitar la validación del servidor (que parece que está indicando), entonces la validación del servidor para esta instancia no se puede utilizar de forma adecuada. Debería invocar la validación de su servidor nuevamente en su acción de controlador o en una capa de servicio. El escenario que describes no debería estar derrotando la validación de tu servidor.

Con el escenario que describe, el método de atributos DataAnnotación debe ser suficiente. Parece que solo necesita hacer algunos cambios de código para asegurarse de que se invoque la validación de su servidor también al enviar el formulario.

2

La anotación de datos ciertamente no es suficiente. Lo uso extensivamente también para validar previamente mis llamadas al modelo de dominio para obtener mejores informes de errores y fallar tan pronto como sea posible.

Sin embargo, usted puede modificar el Modelo de Anotación de Datos usted mismo para asegurarse de que las propiedades con [Obligatorio] DEBEN publicarse. (Seguiremos con el código más tarde hoy).

ACTUALIZACIÓN obtener el código fuente para DataAnnotations Modelo Binder y encontramos esta línea en DataAnnotationsModelBinder.cs

// Only bind properties that are part of the request 
if (bindingContext.ValueProvider.DoesAnyKeyHavePrefix(fullPropertyKey)) { 

cambiarlo a

// Only bind properties that are part of the request 
bool contextHasKey = bindingContext.ValueProvider.DoesAnyKeyHavePrefix(fullPropertyKey); 
bool isRequired = GetValidationAttributes(propertyDescriptor).OfType<RequiredAttribute>().Count() > 0; 
if (contextHasKey || (!contextHasKey && isRequired)) { 
+0

Gracias Martijn. Espero ver tu código. –

+0

Claro, publiqué esto antes de irme al trabajo (en el trabajo todavía) así que no tengo tiempo para codificar :(. Modifiqué el encuadernador ligeramente antes ya que no comprobaba los objetos anidados y restablecía las propiedades inválidas a nulas con las que no estaba de acuerdo http://stackoverflow.com/questions/820468/how-does-dataannotationsmodelbinder-work-with-custom-viewmodels/864541#864541 He añadido las comprobaciones requeridas desde entonces también pero me gustaría probarlas cuando llegue a casa antes publicarlos. –

+0

Actualizado con el código, pero no estoy en posición de probarlo correctamente lo volveré a hacer mañana, pero lo publiqué para que pueda evaluarlo más rápido. Pasa las pruebas unitarias del proyecto, pero para ser justos. No hay pruebas para probar este caso: D. –

7

Emparejé xVal con DataAnnotaciones y escribí mi propio filtro de acción que verifica cualquier parámetro de tipo de entidad con fines de validación. Por lo tanto, si falta algún campo en la devolución de datos, este validador rellenará el diccionario de ModelState y, por lo tanto, tendrá el modelo no válido.

Requisitos:

  • mi entidad/modelo de objetos Todos implementar IObjectValidator interfaz que declara Validate() método.
  • mi clase de atributo se llama ValidateBusinessObjectAttribute
  • validación XVal biblioteca

código del filtro acción:

public void OnActionExecuting(ActionExecutingContext filterContext) 
{ 
    IEnumerable<KeyValuePair<string, object>> parameters = filterContext.ActionParameters.Where<KeyValuePair<string, object>>(p => p.Value.GetType().Equals(this.ObjectType ?? p.Value.GetType()) && p.Value is IObjectValidator); 
    foreach (KeyValuePair<string, object> param in parameters) 
    { 
     object value; 
     if ((value = param.Value) != null) 
     { 
      IEnumerable<ErrorInfo> errors = ((IObjectValidator)value).Validate(); 
      if (errors.Any()) 
      { 
       new RulesException(errors).AddModelStateErrors(filterContext.Controller.ViewData.ModelState, param.Key); 
      } 
     } 
    } 
} 

Mi acción del controlador se define como esto entonces:

[ValidateBusinessObject] 
public ActionResult Register(User user, Company company, RegistrationData registrationData) 
{ 
    if (!this.ModelState.IsValid) 
    { 
     return View(); 
    } 
    ... 
} 
+0

tiene un ejemplo más detallado sobre cómo usar esto o un proyecto descargable, tal vez –

+0

@geocine: ¿Dónde parece estar el problema? ¿Estás usando MVC1? Las versiones más nuevas no requieren hacer esto, porque validan automáticamente los parámetros de tipo fuerte ... Pero este ejemplo aquí es tan detallado como debería ser en realidad. Entonces, ¿dónde parece estar el problema? –

+0

Acabo de pasar y soy nuevo en aspmvc leyendo sobre problemas de validación. Olvidé que estaba usando MVC 2. mi mal. –

2

escribí mi propio ValidationService para MVC 1.0 copiando patrones de ambos xV al DataAnnotationsRuleProvider de al y DataAnnotationsModelBinder de Microsoft (y los comentarios de Martijn). La interfaz de servicio es el siguiente:

public interface IValidationService 
{ 
    void Validate(object instance); 

    IEnumerable<ErrorInfo> GetErrors(object instance); 
} 

public abstract class BaseValidationService : IValidationService 
{ 
    public void Validate(object instance) 
    { 
     var errors = GetErrors(instance); 

     if (errors.Any()) 
      throw new RulesException(errors); 
    } 

    public abstract IEnumerable<ErrorInfo> GetErrors(object instance); 
} 

El servicio es un corredor de validación que recorre el árbol de propiedades de la instancia del objeto que recibe y ejecuta realmente los atributos de validación que se encuentra en cada propiedad, la construcción de una lista de objetos errorInfo cuando los atributos no son válidos (Publicaba toda la fuente pero estaba escrita para un cliente y todavía no sé si estoy autorizado para hacerlo).

Luego puede tener sus controladores, los servicios de lógica de negocios invocan explícitamente la validación cuando está listo, en lugar de depender exclusivamente del encuadernador modelo para la validación.

Hay un par de otras trampas que usted debe tener en cuenta:

  • El valor predeterminado en los datos DataTypeAttribute anotaciones en realidad no hace ninguna validación tipo de datos , por lo que tendrá que escribir un nuevo atributo que en realidad usa xVal regular expresiones (u otra cosa) a realiza validación del tipo de datos del lado del servidor .
  • XVal no camina propiedades para crear en el cliente validación, por lo que es posible que desee hacer algunos cambios allí para obtener más robusta validación en el cliente .

Si me permiten y tengo tiempo, intentaré hacer más fuente disponible ...

1

Ver CodeProject Server-side Input Validation using Data Annotations

Validación de entrada se puede hacer de forma automática en el lado del cliente en ASP.NET MVC o validar de manera explícita el modelo contra las reglas. Esta sugerencia de describirá cómo se puede hacer manualmente en el lado del servidor de una aplicación ASP.NET o dentro del código de repositorio de las aplicaciones WPF .

 // Use the ValidationContext to validate the Product model against the product data annotations 
     // before saving it to the database 
     var validationContext = new ValidationContext(productViewModel, serviceProvider: null, items:null); 
     var validationResults = new List<ValidationResult>(); 

     var isValid = Validator.TryValidateObject(productViewModel, validationContext,validationResults, true); 
Cuestiones relacionadas