¿Qué es ViewModel en MVC?

Soy nuevo en ASP.NET MVC. Tengo un problema para comprender el propósito de un ViewModel.

¿Qué es un ViewModel y por qué necesitamos un ViewModel para una aplicación ASP.NET MVC?

Es mejor si puedo tener un ejemplo simple.

    Un view model representa los datos que desea mostrar en su vista / página, ya sea que se utilicen para texto estático o para valores de entrada (como cuadros de texto y listas desplegables) que se pueden agregar a la base de datos (o editar). Es algo diferente a tu domain model . Es un modelo para la vista.

    Digamos que tiene una clase Employee que representa su modelo de dominio de empleado y que contiene las siguientes propiedades (identificador único, nombre, apellido y fecha de creación):

     public class Employee : IEntity { public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public DateTime DateCreated { get; set; } } 

    Los modelos de vista difieren de los modelos de dominio en esa vista, los modelos solo contienen los datos (representados por propiedades) que desea usar en su vista. Por ejemplo, digamos que desea agregar un nuevo registro de empleado, su modelo de vista podría tener este aspecto:

     public class CreateEmployeeViewModel { public string FirstName { get; set; } public string LastName { get; set; } } 

    Como puede ver, solo contiene dos de las propiedades. Estas dos propiedades también están en el modelo de dominio del empleado. ¿Por qué es esto lo puedes preguntar? Id posible que Id no se configure desde la vista, podría ser generado automáticamente por la tabla Empleado. Y DateCreated también puede establecerse en el procedimiento almacenado o en la capa de servicio de su aplicación. Entonces Id y DateCreated no son necesarios en el modelo de vista. Es posible que desee mostrar estas dos propiedades cuando vea los detalles de un empleado (un empleado que ya ha sido capturado) como texto estático.

    Al cargar la vista / página, el método de crear acción en su controlador de empleado creará una instancia de este modelo de vista, rellenará los campos si es necesario y luego pasará este modelo de vista a la vista / página:

     public class EmployeeController : Controller { private readonly IEmployeeService employeeService; public EmployeeController(IEmployeeService employeeService) { this.employeeService = employeeService; } public ActionResult Create() { CreateEmployeeViewModel model = new CreateEmployeeViewModel(); return View(model); } public ActionResult Create(CreateEmployeeViewModel model) { // Do what ever needs to be done before adding the employee to the database } } 

    Su vista / página podría verse así (suponiendo que está utilizando ASP.NET MVC y el motor de vista Razor ):

     @model MyProject.Web.ViewModels.CreateEmployeeViewModel 
    First Name: @Html.TextBoxFor(m => m.FirstName, new { maxlength = "50", size = "50" }) @Html.ValidationMessageFor(m => m.FirstName)
    Last Name: @Html.TextBoxFor(m => m.LastName, new { maxlength = "50", size = "50" }) @Html.ValidationMessageFor(m => m.LastName)

    La validación se haría solo en FirstName y LastName . Usando Validación fluida, es posible que tenga una validación como esta:

     public class CreateEmployeeViewModelValidator : AbstractValidator { public CreateEmployeeViewModelValidator() { RuleFor(m => m.FirstName) .NotEmpty() .WithMessage("First name required") .Length(1, 50) .WithMessage("First name must not be greater than 50 characters"); RuleFor(m => m.LastName) .NotEmpty() .WithMessage("Last name required") .Length(1, 50) .WithMessage("Last name must not be greater than 50 characters"); } } 

    Y con anotaciones de datos, podría verse así:

     public class CreateEmployeeViewModel : ViewModelBase { [Display(Name = "First Name")] [Required(ErrorMessage = "First name required")] public string FirstName { get; set; } [Display(Name = "Last Name")] [Required(ErrorMessage = "Last name required")] public string LastName { get; set; } } 

    La clave para recordar es que el modelo de vista solo representa los datos que desea usar , nada más. Puede imaginar todo el código innecesario y la validación si tiene un modelo de dominio con 30 propiedades y solo desea actualizar un único valor. Dado este escenario, solo tendrías este valor / propiedad en el modelo de vista y no todas las propiedades que están en el objeto de dominio.

    Un modelo de vista podría no solo tener datos de una tabla de base de datos. Puede combinar datos de otra tabla. Tome mi ejemplo anterior sobre cómo agregar un nuevo registro de empleado. Además de agregar solo los nombres y apellidos, es posible que también desee agregar el departamento del empleado. Esta lista de departamentos vendrá de su tabla Departments . Entonces ahora tiene datos de las tablas Employees y Departments en un modelo de vista. A continuación, deberá agregar las dos propiedades siguientes a su modelo de vista y completarlo con datos:

     public int DepartmentId { get; set; } public IEnumerable Departments { get; set; } 

    Al editar los datos de los empleados (un empleado que ya ha sido agregado a la base de datos) no difería mucho de mi ejemplo anterior. Cree un modelo de vista, EditEmployeeViewModel , por ejemplo, EditEmployeeViewModel . Solo tiene los datos que desea editar en este modelo de vista, como el nombre y el apellido. Edite los datos y haga clic en el botón Enviar. No me preocuparía demasiado sobre el campo Id porque probablemente el valor Id esté en la URL, por ejemplo:

     http://www.yourwebsite.com/Employee/Edit/3 

    Toma este Id y pásalo a tu capa de repository, junto con tu nombre y los valores de tu apellido.

    Al eliminar un registro, normalmente sigo la misma ruta que con el modelo de vista de edición. También tendría una URL, por ejemplo:

     http://www.yourwebsite.com/Employee/Delete/3 

    Cuando la vista se carga por primera vez, obtengo los datos del empleado de la base de datos usando el Id de 3. Luego, simplemente muestro texto estático en mi vista / página para que el usuario pueda ver qué empleado se está eliminando. Cuando el usuario hace clic en el botón Eliminar, simplemente usaría el valor Id de 3 y lo pasaría a mi capa de repository. Solo necesita el Id para eliminar un registro de la tabla.

    Otro punto, realmente no necesitas un modelo de vista para cada acción. Si se trata de datos simples, entonces estaría bien usar solo EmployeeViewModel . Si se trata de vistas / páginas complejas y difieren entre sí, le sugiero que utilice modelos de vista separados para cada una.

    Espero que esto aclare cualquier confusión que tengas sobre ver modelos y modelos de dominio.

    El modelo de vista es una clase que representa el modelo de datos utilizado en una vista específica. Podríamos usar esta clase como modelo para una página de inicio de sesión:

     public class LoginPageVM { [Required(ErrorMessage = "Are you really trying to login without entering username?")] [DisplayName("Username/e-mail")] public string UserName { get; set; } [Required(ErrorMessage = "Please enter password:)")] [DisplayName("Password")] public string Password { get; set; } [DisplayName("Stay logged in when browser is closed")] public bool RememberMe { get; set; } } 

    Usando este modelo de vista puede definir la vista (motor de vista Razor):

     @model CamelTrap.Models.ViewModels.LoginPageVM @using (Html.BeginForm()) { @Html.EditorFor(m => m);  } 

    Y acciones:

     [HttpGet] public ActionResult LoginPage() { return View(); } [HttpPost] public ActionResult LoginPage(LoginPageVM model) { ...code to login user to application... return View(model); } 

    Que produce este resultado (la pantalla se toma después de enviar el formulario, con mensajes de validación):

    Como puede ver, un modelo de vista tiene muchos roles:

    • Los modelos de vista documentan una vista mediante solo campos que se representan a la vista.
    • Los modelos de vista pueden contener reglas de validación específicas usando anotaciones de datos o IDataErrorInfo.
    • El modelo de vista define cómo debe verse una vista (para LabelFor , EditorFor , DisplayFor helpers).
    • Los modelos de vista pueden combinar valores de diferentes entidades de base de datos.
    • Puede especificar plantillas de visualización para ver modelos y reutilizarlos en muchos lugares utilizando DisplayFor o EditorFor helpers.

    Otro ejemplo de un modelo de vista y su recuperación: queremos mostrar los datos básicos del usuario, sus privilegios y el nombre de los usuarios. Creamos un modelo de vista especial, que contiene solo los campos obligatorios. Recuperamos datos de diferentes entidades de la base de datos, pero la vista solo tiene en cuenta la clase de modelo de vista:

     public class UserVM { public int ID { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public bool IsAdministrator { get; set; } public string MothersName { get; set; } } 

    Recuperación:

     var user = db.userRepository.GetUser(id); var model = new UserVM() { ID = user.ID, FirstName = user.FirstName, LastName = user.LastName, IsAdministrator = user.Proviledges.IsAdministrator, MothersName = user.Mother.FirstName + " " + user.Mother.LastName } 

    Editar: Actualicé esta respuesta en mi blog:

    http://www.samwheat.com/Post/The-function-of-ViewModels-in-MVC-web-development

    Mi respuesta es un poco larga, pero creo que es importante comparar los modelos de vista con otros tipos de modelos comúnmente utilizados para comprender por qué son diferentes y por qué son necesarios.

    Para resumir, y para responder directamente la pregunta que se hace:

    En términos generales, un modelo de vista es un objeto que contiene todas las propiedades y métodos necesarios para representar una vista. Las propiedades del modelo de vista a menudo están relacionadas con objetos de datos, como clientes y pedidos, y además contienen propiedades relacionadas con la página o la aplicación, como el nombre de usuario, el nombre de la aplicación, etc. Los modelos de vista proporcionan un objeto conveniente para pasar a un motor de representación. crea una página html Una de las muchas razones para usar un modelo de vista es que los modelos de vista proporcionan una manera de probar ciertas tareas de presentación, como manejar la entrada del usuario, validar datos, recuperar datos para visualizar, etc.

    Aquí hay una comparación de los modelos de Entity (a.ka. modelos a.ka. de DTO), los Modelos de Presentación y los Modelos de Vista.

    Objetos de transferencia de datos también conocidos como “Modelo”

    Un objeto de transferencia de datos (DTO) es una clase con propiedades que coinciden con un esquema de tabla en una base de datos. Los DTO son nombrados por su uso común para el transporte de datos hacia y desde un almacén de datos.
    Características de los DTO:

    • Son objetos comerciales: su definición depende de los datos de la aplicación.

    • Usualmente solo contiene propiedades – sin código.

    • Principalmente utilizado para transportar datos hacia y desde una base de datos.

    • Las propiedades coinciden exactamente o muy de cerca con los campos en una tabla específica en un almacén de datos.

    Las tablas de la base de datos suelen estar normalizadas, por lo que las DTO generalmente también se normalizan. Esto los hace de uso limitado para presentar datos. Sin embargo, para ciertas estructuras de datos simples a menudo les va bastante bien.

    Aquí hay dos ejemplos de lo que podría ser DTO:

     public class Customer { public int ID { get; set; } public string CustomerName { get; set; } } public class Order { public int ID { get; set; } public int CustomerID { get; set; } public DateTime OrderDate { get; set; } public Decimal OrderAmount { get; set; } } 

    Modelos de presentación

    Un modelo de presentación es una clase de utilidad que se utiliza para representar datos en una pantalla o informe. Los modelos de presentación se utilizan generalmente para modelar estructuras de datos complejas compuestas a partir de datos de múltiples DTO. Los modelos de presentación a menudo representan una visión desnormalizada de los datos.

    Características de los modelos de presentación:

    • Son objetos comerciales: su definición depende de los datos de la aplicación.

    • Contienen principalmente propiedades. El código generalmente se limita a datos de formato o conversión hacia o desde un DTO. Los modelos de presentación no deben contener lógica comercial.

    • A menudo presentan una visión desnormalizada de los datos. Es decir, a menudo combinan propiedades de múltiples DTO.

    • A menudo contienen propiedades de un tipo base diferente a un DTO. Por ejemplo, las cantidades en dólares se pueden representar como cadenas para que puedan contener comas y un símbolo de moneda.

    • A menudo se define por la forma en que se utilizan, así como sus características de objeto. En otras palabras, un DTO simple que se usa como modelo de respaldo para representar una cuadrícula es de hecho también un modelo de presentación en el contexto de esa cuadrícula.

    Los modelos de presentación se utilizan “según sea necesario” y “cuando sea necesario” (mientras que los DTO generalmente están vinculados al esquema de la base de datos). Un modelo de presentación se puede usar para modelar datos para una página completa, una cuadrícula en una página o un menú desplegable en una cuadrícula en una página. Los modelos de presentación a menudo contienen propiedades que son otros modelos de presentación. Los modelos de presentación a menudo se construyen para un propósito de un solo uso, como representar una cuadrícula específica en una sola página.

    Un ejemplo de modelo de presentación:

     public class PresentationOrder { public int OrderID { get; set; } public DateTime OrderDate { get; set; } public string PrettyDate { get { return OrderDate.ToShortDateString(); } } public string CustomerName { get; set; } public Decimal OrderAmount { get; set; } public string PrettyAmount { get { return string.Format("{0:C}", OrderAmount); } } } 

    Ver modelos

    Un modelo de vista es similar a un modelo de presentación en que es una clase de respaldo para representar una vista. Sin embargo, es muy diferente de un modelo de presentación o un DTO en cómo se construye. Los modelos de vista a menudo contienen las mismas propiedades que los modelos de presentación y los DTO y, por esta razón, a menudo se confunden uno por el otro.

    Características de los modelos de vista:

    • Son la única fuente de datos utilizada para representar una página o pantalla. Por lo general, esto significa que un modelo de vista expondrá todas las propiedades que cualquier control en la página necesitará para renderizarse correctamente. Hacer que el modelo de vista sea la única fuente de datos para la vista mejora enormemente su capacidad y valor para las pruebas unitarias.

    • Son objetos compuestos que contienen propiedades que constan de datos de la aplicación, así como propiedades que utiliza el código de la aplicación. Esta característica es crucial cuando se diseña el modelo de vista para la reutilización y se analiza en los ejemplos a continuación.

    • Contiene código de aplicación. Los modelos de vista generalmente contienen métodos que se invocan durante la representación y cuando el usuario interactúa con la página. Este código típicamente se relaciona con el manejo de eventos, la animación, la visibilidad de los controles, el estilo, etc.

    • Contienen código que llama a los servicios comerciales con el fin de recuperar datos o enviarlos a un servidor de base de datos. Este código a menudo se coloca erróneamente en un controlador. Llamar a los servicios comerciales desde un controlador generalmente limita la utilidad del modelo de vista para las pruebas unitarias. Para que quede claro, los modelos de vista en sí mismos no deben contener lógica comercial, pero deben hacer llamadas a servicios que sí contienen lógica comercial.

    • A menudo contienen propiedades que son otros modelos de vista para otras páginas o pantallas.

    • Están escritos “por página” o “por pantalla”. Un modelo de vista único generalmente se escribe para cada página o pantalla en una aplicación.

    • Por lo general, se derivan de una clase base, ya que la mayoría de las páginas y pantallas comparten propiedades comunes.

    Ver composición del modelo

    Como se indicó anteriormente, los modelos de vista son objetos compuestos en el sentido de que combinan propiedades de aplicaciones y propiedades de datos comerciales en un solo objeto. Los ejemplos de propiedades de aplicación utilizadas comúnmente que se utilizan en los modelos de vista son:

    • Propiedades que se utilizan para mostrar el estado de la aplicación, como mensajes de error, nombre de usuario, estado, etc.

    • Propiedades utilizadas para formatear, mostrar, estilizar o animar controles.

    • Propiedades utilizadas para el enlace de datos, como objetos de la lista y propiedades que contienen datos intermedios que ingresa el usuario.

    Los siguientes ejemplos muestran por qué la naturaleza compuesta de los modelos de vista es importante y cómo podemos construir mejor un modelo de vista que sea eficiente y reutilizable.

    Supongamos que estamos escribiendo una aplicación web. Uno de los requisitos del diseño de la aplicación es que el título de la página, el nombre de usuario y el nombre de la aplicación se muestren en cada página. Si queremos crear una página para mostrar un objeto de orden de presentación, podemos modificar el modelo de presentación de la siguiente manera:

     public class PresentationOrder { public string PageTitle { get; set; } public string UserName { get; set; } public string ApplicationName { get; set; } public int OrderID { get; set; } public DateTime OrderDate { get; set; } public string PrettyDate { get { return OrderDate.ToShortDateString(); } } public string CustomerName { get; set; } public Decimal OrderAmount { get; set; } public string PrettyAmount { get { return string.Format("{0:C}", OrderAmount); } } } 

    Este diseño podría funcionar … ¿pero qué ocurre si queremos crear una página que muestre una lista de pedidos? Las propiedades PageTitle, UserName y ApplicationName se repetirán y se volverán difíciles de manejar. Además, ¿qué ocurre si queremos definir alguna lógica de nivel de página en el constructor de la clase? Ya no podemos hacer eso si creamos una instancia para cada orden que se mostrará.

    Composición sobre la herencia

    Esta es una forma en que podríamos volver a factorizar el modelo de presentación de pedidos de manera que se convierta en un modelo de vista verdadero y sea útil para mostrar un solo objeto PresentationOrder o una colección de objetos PresentationOrder:

     public class PresentationOrderVM { // Application properties public string PageTitle { get; set; } public string UserName { get; set; } public string ApplicationName { get; set; } // Business properties public PresentationOrder Order { get; set; } } public class PresentationOrderVM { // Application properties public string PageTitle { get; set; } public string UserName { get; set; } public string ApplicationName { get; set; } // Business properties public List Orders { get; set; } } 

    Al observar las dos clases anteriores, podemos ver que una forma de pensar sobre un modelo de vista es que es un modelo de presentación que contiene otro modelo de presentación como propiedad. El modelo de presentación de nivel superior (es decir, modelo de vista) contiene propiedades que son relevantes para la página o aplicación, mientras que el modelo de presentación (propiedad) contiene propiedades que son relevantes para los datos de la aplicación.

    Podemos llevar nuestro diseño un paso más allá y crear una clase de modelo de vista base que se puede usar no solo para PresentationOrders, sino también para cualquier otra clase:

     public class BaseViewModel { // Application properties public string PageTitle { get; set; } public string UserName { get; set; } public string ApplicationName { get; set; } } 

    Ahora podemos simplificar nuestro PresentationOrderVM así:

     public class PresentationOrderVM : BaseViewModel { // Business properties public PresentationOrder Order { get; set; } } public class PresentationOrderVM : BaseViewModel { // Business properties public List Orders { get; set; } } 

    Podemos hacer que nuestro modelo BaseView sea aún más reutilizable haciéndolo genérico:

     public class BaseViewModel { // Application properties public string PageTitle { get; set; } public string UserName { get; set; } public string ApplicationName { get; set; } // Business property public T BusinessObject { get; set; } } 

    Ahora nuestras implementaciones son sin esfuerzo:

     public class PresentationOrderVM : BaseViewModel { // done! } public class PresentationOrderVM : BaseViewModel> { // done! } 

    Si tiene propiedades específicas para la vista y no están relacionadas con el almacén de DB / Servicio / Datos, es una buena práctica usar ViewModels. Supongamos que desea dejar seleccionada una checkbox basada en un campo de base de datos (o dos), pero el campo de base de datos en sí mismo no es un booleano. Si bien es posible crear estas propiedades en el propio Modelo y mantenerlo oculto del enlace a los datos, es posible que no desee saturar el Modelo en función de la cantidad de dichos campos y transacciones.

    Si hay muy pocos datos y / o transformaciones específicos de la vista, puede usar el propio Modelo

    No leí todas las publicaciones, pero a cada respuesta le falta un concepto que realmente me ayudó a “entenderlo” …

    Si un modelo es similar a una tabla de base de datos, entonces un modelo de vista es similar a una vista de base de datos: una vista normalmente devuelve pequeñas cantidades de datos de una tabla o conjuntos complejos de datos de varias tablas (combinaciones).

    Me encuentro usando ViewModels para pasar información a una vista / formulario, y luego transferir esos datos a un modelo válido cuando el formulario se envía al controlador, también es muy útil para almacenar listas (IEnumerable).

    MVC no tiene un modelo de vista: tiene un modelo, vista y controlador. Un modelo de vista es parte de MVVM (Model-View-Viewmodel). MVVM se deriva del modelo de presentación y se populariza en WPF. También debería haber un modelo en MVVM, pero la mayoría de la gente pierde el punto de ese patrón por completo y solo tendrán una vista y un modelo de vista. El modelo en MVC es similar al modelo en MVVM.

    En MVC, el proceso se divide en 3 responsabilidades diferentes:

    • View es responsable de presentar los datos al usuario
    • Un controlador es responsable del flujo de la página
    • Un modelo es responsable de la lógica comercial

    MVC no es muy adecuado para aplicaciones web. Es un patrón introducido por Smalltalk para crear aplicaciones de escritorio. Un entorno web se comporta completamente diferente. No tiene mucho sentido copiar un concepto de 40 años del desarrollo de escritorio y pegarlo en un entorno web. Sin embargo, mucha gente piensa que esto está bien, porque su aplicación comstack y devuelve los valores correctos. Es decir, en mi opinión, no es suficiente para declarar que una determinada opción de diseño está bien.

    Un ejemplo de un modelo en una aplicación web podría ser:

     public class LoginModel { private readonly AuthenticationService authentication; public LoginModel(AuthenticationService authentication) { this.authentication = authentication; } public bool Login() { return authentication.Login(Username, Password); } public string Username { get; set; } public string Password { get; set; } } 

    El controlador puede usarlo así:

     public class LoginController { [HttpPost] public ActionResult Login(LoginModel model) { bool success = model.Login(); if (success) { return new RedirectResult("/dashboard"); } else { TempData["message"] = "Invalid username and/or password"; return new RedirectResult("/login"); } } } 

    Sus métodos de control y sus modelos serán pequeños, fáciles de probar y al punto.

    El modelo de vista a es una clase simple que puede contener más de una propiedad de clase. Lo usamos para heredar todas las propiedades requeridas, por ejemplo, tengo dos clases, Estudiante y Asunto

     Public class Student { public int Id {get; set;} public string Name {get; set;} } Public class Subject { public int SubjectID {get; set;} public string SubjectName {get; set;} } 

    Ahora queremos mostrar los registros del nombre del alumno y el nombre del sujeto en la vista (en MVC), pero no es posible agregar más de una clase como:

      @model ProjectName.Model.Student @model ProjectName.Model.Subject 

    el código de arriba arrojará un error …

    Ahora creamos una clase y podemos darle cualquier nombre, pero este formato “XyzViewModel” lo hará más fácil de entender. Es un concepto de herencia. Ahora creamos una tercera clase con el siguiente nombre:

     public class StudentViewModel:Subject { public int ID {get; set;} public string Name {get; set;} } 

    Ahora usamos este ViewModel en la vista

    @model ProjectName.Model.StudentViewModel

    Ahora podemos acceder a todas las propiedades de StudentViewModel y la clase heredada en View.

    Una gran cantidad de grandes ejemplos, déjame explicarte de manera clara y crujiente.

    ViewModel = Modelo que se crea para servir la vista.

    La vista ASP.NET MVC no puede tener más de un modelo, por lo que si necesitamos mostrar propiedades de más de un modelo en la vista, no es posible. ViewModel cumple esta función.

    View Model es una clase de modelo que solo puede contener aquellas propiedades que se requieren para una vista. También puede contener propiedades de más de una entidad (tablas) de la base de datos. Como su nombre indica, este modelo se crea específicamente para los requisitos de Vista.

    Algunos ejemplos de View Models están debajo

    • Para listar datos de más de entidades en una página de vista, podemos crear un modelo de Vista y tener propiedades de todas las entidades para las cuales queremos listar datos. Únase a esas entidades de base de datos y establezca las propiedades del modelo de visualización y regrese a la vista para mostrar datos de diferentes entidades en una sola forma tabular
    • El modelo de vista puede definir solo campos específicos de una sola entidad que se requiere para la Vista.

    ViewModel también se puede usar para insertar y actualizar registros en más de una entidad. Sin embargo, el uso principal de ViewModel es mostrar columnas de múltiples entidades (modelo) en una sola vista.

    La forma de crear ViewModel es lo mismo que crear Model, la forma de crear view para Viewmodel es lo mismo que crear view for Model.

    Aquí hay un pequeño ejemplo de datos de lista usando ViewModel .

    Espero que esto sea útil.

    ViewModel es un workarround que corrige la torpeza conceptual del framework MVC. Representa la 4ª capa en la architecture Model-View-Controller de 3 capas. cuando el Modelo (modelo de dominio) no es apropiado, demasiado grande (más grande que 2-3 campos) para la Vista, creamos un Modelo de Vista más pequeño para pasarlo a la Vista.