¿Por qué usamos ViewModels?

Recientemente comencé a trabajar como desarrollador web. Trabajo con ASP .NET MVC 4 y NHibernate.

En mi lugar de trabajo, estamos estrictamente diseñados para usar viewmodels para transferir datos entre un controlador y una vista. Y los viewmodels no deben contener ningún objeto de un modelo. Entiendo que es una especie de nivel entre el controlador y la vista.

Pero me parece repetitivo y redundante escribir una clase de modelo de vista incluso si podemos enviar directamente el objeto del modelo a la vista (en la mayoría de los casos).

Por ejemplo, si quiero mostrar una orden, puedo hacer esto en la acción del controlador:

return View(Repository.Get(id)); 

Pero en su lugar, tengo que escribir un modelo de vista, llenarlo con el orden obtenido y luego pasarlo a la vista.

Entonces, mi pregunta es, ¿para qué sirve escribir modelos de vista cuando podemos usar el objeto del modelo tal como es?

Para proyectos más pequeños, tienes razón. Escucho tu argumento y simpatizo; sin embargo, hay buenas razones para este trabajo pesado y repetitivo, especialmente en aplicaciones más grandes y complicadas:

  • Es esencial realizar todo el procesamiento dentro de la acción del Controlador. Sin embargo, en el ejemplo que proporcionó, el método Repository.Get podría devolver un objeto IQueryable evaluado de forma IQueryable , lo que significaría que no se golpearía el DB hasta que se evalúe la Vista. Por una variedad de razones, esto es malo. (Una solución alternativa es llamar a .ToList mientras aún está en el controlador).
  • “Una vista no debe contener ninguna lógica no presentacional” y “No debe confiar en la Vista” (porque una Vista podría ser proporcionada por el usuario). Al proporcionar un objeto Model (potencialmente aún conectado a un DatabaseContext activo), una vista puede realizar cambios maliciosos en su base de datos.
  • Los datos a visualizar de una vista no siempre se correlacionan 1: 1 con los datos de su modelo, por ejemplo, consideran una página de detalles del usuario:

    El objeto Modelo de EF de un usuario representa su entidad en la base de datos, por lo que probablemente User { UserId, UserName, PasswordHash, PasswordSalt, EmailAddress, CreatedDate } aspecto: User { UserId, UserName, PasswordHash, PasswordSalt, EmailAddress, CreatedDate } , mientras que los campos en una página “Detalles de usuario” serán User { UserId, UserName, Password, ConfirmYourPassword, EmailAddress } , ¿ves la diferencia? Ergo, no puedes usar el modelo de usuario de EF como el modelo de vista, tienes que usar una clase separada.

  • Los peligros de la manipulación del modelo: si deja que ASP.NET MVC (o cualquier otro marco) haga el enlace del modelo a la solicitud HTTP POST entrante (tomando el ejemplo de detalles del usuario anterior), un usuario podría restablecer la contraseña de cualquier persona fingiendo la propiedad UserId valor. ASP.NET reescribirá ese valor durante el enlace y, a menos que lo desinfecte específicamente (lo que será tan pesado como hacer modelos de vista individuales de todos modos), esta vulnerabilidad se mantendrá.

  • En proyectos con múltiples desarrolladores que trabajan en una situación de equipo, es importante que todo sea coherente . No es coherente tener algunas páginas usando ViewModels a medida, pero otras páginas usan EF Models porque el equipo no comparte una mente consciente, las cosas deben documentarse y, en general, tienen sentido. Por la misma razón, un solo desarrollador puede escaparse sin poner demasiada documentación XML en su código fuente, pero en una situación de equipo se derrumbará si no lo hace.

Hay una pequeña solución en su caso que compartiré con usted, pero tenga en cuenta las condiciones previas:

  • Tus puntos de vista pueden ser completamente confiables
  • Sus puntos de vista contienen solo lógica de presentación
  • Su aplicación es en gran medida CRUD
  • Sus puntos de vista corresponden a 1: 1 con cada modelo de entidad EF (es decir, sin uniones)
  • Sus puntos de vista solo se refieren a modelos sencillos simples para formularios POST, no a modelos complejos (es decir, un gráfico de objetos)

… entonces puedes hacer esto:

  • Coloque todos los datos de una vía, no relacionados con la forma, en su colección ViewBag , o la ViewBag en MVC 4 (o incluso una ViewData genérica si es hardcore). Esto es útil para almacenar títulos de páginas HTML y compartir datos con páginas maestras.
  • Utilice sus modelos de EF totalmente evaluados y cargados como sus modelos de View .

Pero use este enfoque con precaución porque puede presentar incoherencias.

Bueno, estoy empezando a pensar que se requiere un enfoque pragmático para cada problema y no solo para suscribirme a los estándares arquitectónicos puristas que existen. Es posible que su aplicación se ejecute en estado salvaje y que muchos desarrolladores que la atiendan sirva a un gran grupo de clientes, etc., y esto puede dirigir o impulsar su architecture.

  • ViewModel es esencial cuando desea separar las preocupaciones entre su DomainModel (DataModel) y el rest de su código.

Cuantas menos dependencias tenga entre el Modelo, la Vista y el Controlador, más fácil será realizar cambios en el Modelo de Dominio sin romper los contratos de interfaz en la Vista y el Controlador, etc. Pero una vez más es algo para ser pragmático. Me gusta el enfoque ya que el re-factoring de código es una gran parte del mantenimiento del sistema -la refactorización puede incluir un error ortográfico simple en una propiedad de un Modelo-, que el cambio podría extenderse a través del código al nivel de Contrato si las dependencias no están separadas; por ejemplo.

  • ViewModel se usa para traducir los datos entre su DomainModel y sus Vistas

Un simple ejemplo de una fecha y hora almacenada en Informix debe traducirse a .Net DateTime. ViewModel es el lugar perfecto para hacer esta traducción y no te obliga a poner código de traducción en todo tipo de lugares no deseados.

Un atributo de un buen diseño [de cualquier cosa] es la capacidad de reemplazar o modificar una parte de la implementación con poco o ningún efecto en el rest de las partes del sistema. Pero esto requiere tiempo y esfuerzo: depende de usted encontrar ese equilibrio práctico entre un diseño perfecto y un diseño que sea suficiente.

Pero sí, hay muchas otras buenas razones para usar ciertos patrones, pero la conclusión es la siguiente:

Nada te obliga a utilizar ViewModels … ASP.NET MVC no te obligará. Toma el consejo del pragmático dentro de ti.

Si usa los mismos Modelos que sus Modelos de Vista, su aplicación debe ser muy pequeña y simple y debe contener solo operaciones CRUD. Pero si está creando aplicaciones grandes o empresariales con equipos grandes (con dos o probablemente más desarrolladores), debe tener conceptos como Inyección de Dependencia, Servicios, Repositorios, Fachadas, Unidades de Trabajo, Objetos de Acceso a los Datos, etc.

Para simplificar sus necesidades de mapeo entre Modelos y Modelos de Vista, puede usar AutoMapper https://github.com/AutoMapper/AutoMapper

o instalar con Nuget Install-Package AutoMapper

Según mi opinión, es esencial tener una capa más (ViewModel) encima de la capa del modelo para aplicaciones complejas que realizan la mayoría de las operaciones CRUD porque tiene las siguientes ventajas:

  1. Para establecer un acoplamiento flexible entre el modelo y el controlador. De modo que las modificaciones relacionadas con DataModel no se verán afectadas por el controlador.
  2. Si ha implementado la capa ViewModel de su aplicación correctamente proporcionando el nivel máximo de IOC (Inversión de control) a través de DI (Injerto de dependencia usando Unity / otros frameworks), etc., también lo ayudará a MOQ sus ViewModels (dependencias) para pruebas solo la lógica del controlador.