2011-06-24 14 views
12

Tengo clases de model y viewmodel por separado. Donde las clases de viewmodel solo hacen la validación de nivel de UI (refiérase a: Validation: Model or ViewModel).Práctica recomendada de validación para Model y ViewModel

Puedo verificar en la acción posterior en un controlador que el modelo (modelo de vew) es válido.

Pregunta: Cómo validar el modelo (la entidad principal con anotaciones de datos).

No estoy desarrollando el modelo de vista utilizando el objeto modelo. Simplemente duplicando las propiedades y agregando todas las propiedades posiblemente requeridas en esa vista particular.

//Model Class 
public class User 
{ 
    [Required] 
    public string Email {get; set;} 

    [Required] 
    public DateTime Created {get; set;} 
} 

//ViewModel Class 
public class UserViewModel 
{ 
    [Required] 
    public string Email {get; set;} 

    [Required] 
    public string LivesIn {get; set;} 
} 

//Post action 
public ActionResult(UserViewModel uvm) 
{ 
    if(ModelState.IsValid) 
     //means user entered data correctly and is validated 

    User u = new User() {Email = uvm.Email, Created = DateTime.Now}; 
    //How do I validate "u"? 

    return View(); 
} 

debe hacer algo como esto:

var results = new List<ValidationResult>(); 
var context = new ValidationContext(u, null, null); 
var r = Validator.TryValidateObject(u, context, results); 

Lo que estoy pensando es la adición de esta técnica de validación en la clase base (de la entidad), y verifique que cuando estoy mapeo de clase viewmodel a la entidad comercial.

¿Alguna sugerencia?

Respuesta

9

1) Use validación fluida en el modelo que recupera información del usuario. es más flexible que la anotación de datos y más fácil de probar.

2) Es posible que desee buscar en automapper, utilizando automapper no tiene que escribir x.name = y.name.

3) Para su modelo de base de datos me quedaré con las anotaciones de datos.

Todo continuación está basada en la nueva información

En primer lugar usted debe colocar la validación tanto en ubicación como lo hizo ahora para la validación del modelo real así es como yo lo haría. responsabilidad: esta no es la manera perfecta

Primero y todas las actualizaciones de la UserViewModel a

public class UserViewModel 
    { 
     [Required()] 
     [RegularExpression(@"^(([A-Za-z0-9]+_+)|([A-Za-z0-9]+\-+)|([A-Za-z0-9]+\.+)|([A-Za-z0-9]+\++))*[A-Za-z0-9][email protected]((\w+\-+)|(\w+\.))*\w{1,63}\.[a-zA-Z]{2,6}$")] 
     public String Email { get; set; } 
    } 

luego actualizar el método de acción a

 // Post action 
     [HttpPost] 
     public ActionResult register (UserViewModel uvm) 
     { 
      // This validates the UserViewModel 
      if (ModelState.IsValid) 
      { 

       try 
       { 
        // You should delegate this task to a service but to keep it simple we do it here 
        User u = new User() { Email = uvm.Email, Created = DateTime.Now }; 
        RedirectToAction("Index"); // On success you go to other page right? 
       } 
       catch (Exception x) 
       { 
        ModelState.AddModelError("RegistrationError", x); // Replace x with your error message 
       } 

      }  

      // Return your UserViewModel to the view if something happened    
      return View(uvm); 
     } 

Ahora, para el modelo de usuario se pone difícil y tienes muchas soluciones posiblesLa solución que se me ocurrió (probablemente no es el mejor) es la siguiente:

public class User 
    { 
     private string email; 
     private DateTime created; 

     public string Email 
     { 
      get 
      { 
       return email; 
      } 
      set 
      { 
       email = ValidateEmail(value); 
      } 
     } 

     private string ValidateEmail(string value) 
     { 
      if (!validEmail(value)) 
       throw new NotSupportedException("Not a valid email address");  

      return value; 
     } 

     private bool validEmail(string value) 
     { 
      return Regex.IsMatch(value, @"^(([A-Za-z0-9]+_+)|([A-Za-z0-9]+\-+)|([A-Za-z0-9]+\.+)|([A-Za-z0-9]+\++))*[A-Za-z0-9][email protected]((\w+\-+)|(\w+\.))*\w{1,63}\.[a-zA-Z]{2,6}$"); 
     } 

pasado alguna prueba para comprobar la unidad de mi propio código:

[TestClass()] 
    public class UserTest 
    { 

     /// <summary> 
     /// If the email is valid it is stored in the private container 
     /// </summary> 
     [TestMethod()] 
     public void UserEmailGetsValidated() 
     { 
      User x = new User(); 
      x.Email = "[email protected]"; 
      Assert.AreEqual("[email protected]", x.Email); 
     } 

     /// <summary> 
     /// If the email is invalid it is not stored and an error is thrown in this application 
     /// </summary> 
     [TestMethod()] 
     [ExpectedException(typeof(NotSupportedException))] 
     public void UserEmailPropertyThrowsErrorWhenInvalidEmail()  
     { 
      User x = new User(); 
      x.Email = "blah blah blah"; 
      Assert.AreNotEqual("blah blah blah", x.Email); 
     } 


     /// <summary> 
     /// Clears an assumption that on object creation the email is validated when its set 
     /// </summary> 
     [TestMethod()] 
     public void UserGetsValidatedOnConstructionOfObject() 
     { 
      User x = new User() { Email = "[email protected]" }; 
      x.Email = "[email protected]"; 
      Assert.AreEqual("[email protected]", x.Email); 
     } 
    } 
+0

PRD @Serghei realidad quería saber cómo puedo validar la clase de modelo (que no está obligado a ver). Mantener que mis Vistas tengan propiedades de diferentes clases de modelos (en una clase ViewModel) para cumplir con todos los requisitos en esa Vista en particular. – Yahya

+0

@Yahya ¿Puedes publicar un ejemplo? será más fácil señalar dónde debe y cómo hacer la validación. – David

+0

prd He agregado el código de muestra en la pregunta original para usted. Espero que tenga sentido ahora. – Yahya

Cuestiones relacionadas