¿Qué es ViewModel en MVC?

429

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?

Si obtengo un buen ejemplo sobre su funcionamiento y explicación, sería mejor.

único
fuente
44
Esta publicación es lo que busca: "¿Qué es un ViewModel ASP.NET MVC?"
Yusubov
66
Este artículo se ve muy bien: rachelappel.com/…
Andrew
posible duplicado de En MVC, ¿qué es un ViewModel?
rogerdeuce

Respuestas:

607

A view modelrepresenta los datos que desea mostrar en su vista / página, ya sea que se use 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 Employeeclase que representa el modelo de dominio de su 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 que los modelos de vista solo contienen los datos (representados por las propiedades) que desea usar en su vista. Por ejemplo, supongamos que desea agregar un nuevo registro de empleado, su modelo de vista podría verse así:

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 que puedes preguntar? Idpodría no establecerse desde la vista, podría generarse automáticamente por la tabla Empleado. Y DateCreatedtambién se puede configurar en el procedimiento almacenado o en la capa de servicio de su aplicación. Por lo tanto Id, y DateCreatedno 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 acción de creación en el controlador de su empleado creará una instancia de este modelo de vista, completará 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 MVCy el Razormotor de visualización):

@model MyProject.Web.ViewModels.CreateEmployeeViewModel

<table>
     <tr>
          <td><b>First Name:</b></td>
          <td>@Html.TextBoxFor(m => m.FirstName, new { maxlength = "50", size = "50" })
              @Html.ValidationMessageFor(m => m.FirstName)
          </td>
     </tr>
     <tr>
          <td><b>Last Name:</b></td>
          <td>@Html.TextBoxFor(m => m.LastName, new { maxlength = "50", size = "50" })
              @Html.ValidationMessageFor(m => m.LastName)
          </td>
     </tr>
</table>

Por lo tanto, la validación se haría solo en FirstNamey LastName. Usando FluentValidation puede tener una validación como esta:

public class CreateEmployeeViewModelValidator : AbstractValidator<CreateEmployeeViewModel>
{
     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 las 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 y la validación innecesarios si tiene un modelo de dominio con 30 propiedades y solo desea actualizar un solo valor. Dado este escenario, solo tendría 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 no solo puede tener datos de una tabla de base de datos. Puede combinar datos de otra tabla. Tome mi ejemplo anterior sobre agregar un nuevo registro de empleado. Además de agregar solo el nombre y el apellido, es posible que también desee agregar el departamento del empleado. Esta lista de departamentos vendrá de su Departmentsmesa. Entonces ahora tiene datos de las tablas Employeesy Departmentsen un modelo de vista. Solo tendrá que agregar las siguientes dos propiedades a su modelo de vista y llenarlo con datos:

public int DepartmentId { get; set; }

public IEnumerable<Department> Departments { get; set; }

Al editar datos de empleados (un empleado que ya se ha agregado a la base de datos), no diferiría mucho de mi ejemplo anterior. Cree un modelo de vista, llámelo por ejemplo EditEmployeeViewModel. Solo tenga los datos que desea editar en este modelo de vista, como nombre y apellido. Edite los datos y haga clic en el botón Enviar. No me preocuparía demasiado por el Idcampo porque el Idvalor probablemente estará en la URL, por ejemplo:

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

Tome esto Idy páselo a su capa de repositorio, junto con sus valores de nombre y 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, obtenía los datos del empleado de la base de datos usando el Id3. Entonces, simplemente mostraba 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 Idvalor de 3 y lo pasaría a mi capa de repositorio. Solo necesita Ideliminar un registro de la tabla.

Otro punto, realmente no necesita un modelo de vista para cada acción. Si se trata de datos simples, estaría bien usarlos 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 haya tenido sobre los modelos de vista y los modelos de dominio.

Brendan Vogt
fuente
55
@Kenny: Entonces muéstralo :) Lo que estaba tratando de decir es que digamos que tienes un modelo de dominio con 50 propiedades y tu vista solo necesita mostrar 5, entonces no sirve de nada enviar las 50 propiedades solo para mostrar 5.
Brendan Vogt
55
@BrendanVogt: hizo un buen trabajo al explicar eso, pero no entiendo cuál es el costo de "enviar las 50 propiedades". Otro código ya ha creado un objeto Modelo, con las 50 propiedades, y no parece valioso mantener otra clase solo para no enviar 45 propiedades, especialmente si es posible que desee enviar cualquiera de esas 45 propiedades en el futuro.
Kenny Evitt
55
@BrendanVogt: creo que tal vez la respuesta de LukLed me ayude a comprender por qué esto podría ser útil, particularmente que un ViewModel (puede) "... combinar valores de diferentes entidades de la base de datos" [donde supongo que la frase es igual de verdadera " entidades de base de datos "que se reemplazarán por" Objetos de modelo "]. Pero aún así, ¿qué problemas específicos pretendían abordar los ViewModels? ¿Tienes algún enlace? No pude encontrar nada yo mismo. [¡Y me disculpo si parece que me estoy
molestando
1
Acabo de escuchar a alguien decir que ViewModels es una buena manera de enviar múltiples colecciones (o propiedades de modelos cruzados) en una sola vista sin tener que rellenarlas en viewBag. Tiene sentido para mi.
Ayyash
3
Lamento ser crítico, pero esta respuesta es, lamentablemente, incompleta. Definir un modelo de vista como solo lo que necesita mostrar en su página es como preguntar "¿Qué es un automóvil?" y recibir una respuesta "No es un avión". Bueno, eso es cierto pero no muy útil. La definición más correcta de una VM es "Todo lo que necesita para representar su página". Si lees hasta el fondo, he identificado los componentes que necesitas para construir tu VM de manera correcta y fácil, en muchos casos aprovechando tus modelos de dominio y modelos de presentación existentes.
Sam
133

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; }
}

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

@model CamelTrap.Models.ViewModels.LoginPageVM

@using (Html.BeginForm()) {
    @Html.EditorFor(m => m);
    <input type="submit" value="Save" class="submit" />
}

Y acciones:

[HttpGet]
public ActionResult LoginPage()
{
    return View();
}

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

Lo 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:

  • Ver modelos documenta una vista al constar solo de campos, que están representados en la vista.
  • Los modelos de vista pueden contener reglas de validación específicas mediante anotaciones de datos o IDataErrorInfo.
  • Ver modelo define cómo una debe aparecer la vista (por LabelFor, EditorFor,DisplayFor ayudantes).
  • Los modelos de vista pueden combinar valores de diferentes entidades de bases de datos.
  • Puede especificar plantillas de visualización fáciles para ver modelos y reutilizarlas en muchos lugares utilizando los ayudantes DisplayFor o EditorFor.

Otro ejemplo de un modelo de vista y su recuperación: queremos mostrar los datos básicos del usuario, sus privilegios y el nombre del usuario. 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 conoce 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
} 
LukLed
fuente
Creo que user.Mother.FirstName + "" + user.Mother.LastName debe hacerse en View Model End. Toda la lógica debe hacerse en el extremo Ver modelo.
Kurkula
3
@Chandana: Creo que se puede hacer una concatenación simple en view model. No hay razón para exponer dos campos, si están destinados a ser presentados juntos.
LukLed
82

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 de uso común para comprender por qué son diferentes y por qué son necesarios.

Para resumir y responder directamente a 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 en sí, 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 renderizado. crear una página html Una de las muchas razones para usar un modelo de vista es que los modelos de vista proporcionan una forma de probar unitariamente ciertas tareas de presentación, como manejar la entrada del usuario, validar datos, recuperar datos para mostrar, etc.

Aquí hay una comparación de los modelos de entidad (también conocidos como modelos DTO), modelos de presentación y modelos de vista.

Objetos de transferencia de datos, también conocido 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 se nombran por su uso común para transferir 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.

• Por lo general, solo contienen propiedades, sin código.

• Se utiliza principalmente para transportar datos hacia y desde una base de datos.

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

Las tablas de la base de datos generalmente se normalizan, por lo tanto, los DTO también se normalizan. Esto los hace de uso limitado para presentar datos. Sin embargo, para ciertas estructuras de datos simples, a menudo funcionan bastante bien.

Aquí hay dos ejemplos de cómo se verían los 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 utilidad. clase de que se utiliza para representar datos en una pantalla o informe. Los modelos de presentación generalmente se usan para modelar estructuras de datos complejas que se componen de datos de múltiples DTO. Los modelos de presentación a menudo representan una vista desnormalizada de 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 formatear datos o convertir ao desde un DTO. Los modelos de presentación no deben contener lógica empresarial.

• A menudo presentan una vista desnormalizada de datos. Es decir, a menudo combinan propiedades de múltiples DTO.

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

• A menudo se define por cómo se usan, así como por sus características de objeto. En otras palabras, un DTO simple que se utiliza 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 usan "según sea necesario" y "donde sea necesario" (mientras que los DTO generalmente están vinculados al esquema de la base de datos). Se puede usar un modelo de presentación 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, ya 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 cuanto a 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 con 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á cada propiedad que cualquier control en la página necesitará para representarse correctamente. Hacer que el modelo de vista sea la única fuente de datos para la vista mejora en gran medida su capacidad y valor para las pruebas unitarias.

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

• Contiene el código de la 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 generalmente se relaciona con el manejo de eventos, la animación, la visibilidad de los controles, el estilo, etc.

• Contener código que llame a servicios comerciales con el propósito de recuperar datos o enviarlos a un servidor de base de datos. Este código a menudo se coloca por error en un controlador. Llamar a los servicios comerciales desde un controlador generalmente limita la utilidad del modelo de vista para pruebas unitarias. Para ser claros, los modelos de vista en sí mismos no deben contener lógica empresarial, sino que deben realizar llamadas a servicios que sí contienen lógica empresarial.

• 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". Por lo general, se escribe un modelo de vista único para cada página o pantalla de una aplicación.

• Generalmente 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 aplicación y propiedades de datos comerciales en un solo objeto. Los ejemplos de propiedades de aplicación de uso común que se usan 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 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 deben mostrar 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é pasa si queremos crear una página que muestre una lista de pedidos? Las propiedades PageTitle, UserName y ApplicationName se repetirán y serán difíciles de manejar. Además, ¿qué pasa si queremos definir alguna lógica a nivel de página en el constructor de la clase? Ya no podemos hacer eso si creamos una instancia para cada pedido que se mostrará.

Composición sobre herencia

Aquí hay una manera en que podríamos re-factorizar el modelo de presentación de orden de modo que se convierta en un modelo de vista real 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<PresentationOrder> Orders { get; set; }
}

Mirando 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 una propiedad. El modelo de presentación de nivel superior (es decir, el modelo de vista) contiene propiedades que son relevantes para la página o la 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 pueda 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<PresentationOrder> Orders { get; set; }
}

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

public class BaseViewModel<T>
{
    // 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 fáciles:

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

public class PresentationOrderVM : BaseViewModel<List<PresentationOrder>>
{
    // done!
}
Sam
fuente
2
Sam gracias !! Esto me ayudó a comprender completamente la entidad multifacética que es un: Modelo de vista. Soy un estudiante universitario que acaba de aprender la arquitectura MVC, y esto aclaró un montón de funcionalidades capaces que están expuestas al desarrollador. Si pudiera, pondría una estrella al lado de tu respuesta.
Chef_Code
1
@Sam '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 con el otro'. ¿Eso significa que se usan comúnmente en lugar de modelos de presentación, o están destinados a contener los modelos / dtos de presentación?
Alexander Derck
2
@AlexanderDerck Se utilizan para diferentes propósitos. Están confundidos uno por el otro (por error). No, normalmente no utilizará un modelo pres en lugar de un modelo de vista. Mucho más común es que la VM "contiene" el modelo de presentación, es decir MyViewModel<MyPresModel>
Sam
2
@Sam Suponiendo que los objetos modelo son objetos vivos, por ejemplo, modelos nhibernate ... así que al tener BusinessObject, ¿no estamos exponiendo los objetos modelo / vivos directamente a la vista? es decir, ¿el objeto comercial se puede usar para modificar el estado de la base de datos directamente? Además, ¿qué pasa con los modelos de vista anidada? Eso requeriría múltiples propiedades de objeto de negocio, ¿verdad?
Muhammad Ali
22

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

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

fozylet
fuente
19

No leí todas las publicaciones, pero en cada respuesta me 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 generalmente 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 transfiero esos datos a un Modelo válido cuando el formulario se publica nuevamente en el controlador, lo que también es muy útil para almacenar Listas (IEnumerable).

halfacreSal
fuente
11

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 las personas pierden completamente el punto de ese patrón 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 del negocio.

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 compila y devuelve los valores correctos. En mi opinión, eso no es suficiente para declarar que una determinada elecció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 controlador y sus modelos serán pequeños, fácilmente comprobables y al grano.

Jeroen
fuente
Gracias por la información sobre la arquitectura MVVM, pero ¿por qué MVC no está bien? Su razonamiento es cuestionable y sospechoso de favoritismo. De acuerdo, no sé nada acerca de MVVM, pero si una arquitectura como MVC puede imitar el comportamiento sin tener que escribir 50 mil líneas de código, ¿cuál es el problema?
Chef_Code
@Chef_Code: no es cuestionable ni es un favoritismo: solo lea el documento original sobre MVC. Volver a la fuente es mucho mejor que seguir ciegamente al rebaño sin cuestionarlo (también conocido como "mejores prácticas"). MVC está diseñado para unidades mucho más pequeñas: por ejemplo, un botón en una pantalla se compone de un modelo, vista y controlador. En Web-MVC, toda la página tiene un controlador, un modelo y una vista. Se supone que el modelo y la vista están conectados, de modo que los cambios en el modelo se reflejan inmediatamente en la vista y viceversa. Imitar es un gran problema. Una arquitectura no debería mentirle a sus desarrolladores.
Jeroen
1
@jeroen El acrónimo MVC ha sido robado y destrozado. Sí, MVC no tiene una VM, pero tampoco tiene un Repositorio o una capa de servicio y esos objetos son ampliamente utilizados en sitios web. Creo que el OP pregunta "cómo presento y uso una VM en MVC". En el nuevo significado de MVC, un modelo no es donde pertenece la lógica de negocios. La lógica empresarial pertenece a una capa de servicio para una aplicación web o de escritorio que utiliza MVC o MVVM. El término modelo describe los objetos de negocio que se pasan a / desde la capa de servicio. Estas definiciones son muy diferentes de la descripción original de MVC.
Sam
1
@Sam No todo lo que forma parte de un sitio web se puede llamar parte de MVC. No hay un nuevo significado de MVC. Existe el significado correcto y el significado de "algo completamente no relacionado que la gente confunde con MVC". Decir que el modelo es responsable de la lógica de negocios no es lo mismo que la lógica de negocios está codificada en el modelo. La mayoría de las veces el modelo actúa como una fachada para la aplicación.
Jeroen
La falla principal que veo en el MVC de Microsoft es el bloqueo de un modelo con vista. Eso en sí mismo derrota el propósito de toda esta separación que ha estado sucediendo en los diseños de N-Tier en los últimos 20 años. Perdieron nuestro tiempo obligándonos a usar "WebForms" en 2002, que fue otro modelo inspirado en el escritorio que apareció en Web World. Ahora lo han descartado pero han vuelto a levantar otro modelo de escritorio sobre este nuevo paradigma para el desarrollador web. Mientras tanto, Google y otros están construyendo modelos gigantes del lado del cliente que lo separan todo. Estoy pensando que el viejo ASP VBScript de 1998 era su verdadero sistema de desarrollo web.
Stokely
11

Ver modelo 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 Nombre del alumno y 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 anterior arrojará un error ...

Ahora creamos una clase y podemos darle cualquier nombre, pero este formato "XyzViewModel" hará que sea más fácil de entender. Es el 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 View

@model ProjectName.Model.StudentViewModel

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

Mayank
fuente
10

Muchos ejemplos importantes, déjenme explicarles de una manera clara y crujiente.

ViewModel = Modelo creado 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 sirve para este propósito.

Ver modelo es una clase de modelo que puede contener solo 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.

Pocos ejemplos de modelos de vista están a continuación

  • Para enumerar 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 que queremos enumerar datos. Únase a esas entidades de la base de datos y configure las propiedades del modelo Ver y regrese a la Vista para mostrar datos de diferentes entidades en una 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, 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 la misma que crear Modelo, la forma de crear vista para Viewmodel es igual que crear vista para Modelo.

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

Espero que esto sea útil.

Sheo Narayan
fuente
6

ViewModel es una solución alternativa que parchea la torpeza conceptual del marco MVC. Representa la cuarta capa en la arquitectura Modelo-Vista-Controlador de 3 capas. cuando el Modelo (modelo de dominio) no es apropiado, demasiado grande (más de 2-3 campos) para la Vista, creamos un Modelo de vista más pequeño para pasarlo a la Vista.

gsivanov
fuente
1

Un modelo de vista es un modelo conceptual de datos. Su uso es, por ejemplo, obtener un subconjunto o combinar datos de diferentes tablas.

Es posible que solo desee propiedades específicas, por lo que esto le permite cargar solo esas y no propiedades innecesarias adicionales


fuente
1
  • ViewModel contiene campos que están representados en la vista (para ayudantes LabelFor, EditorFor, DisplayFor)
  • ViewModel puede tener reglas de validación específicas mediante anotaciones de datos o IDataErrorInfo.
  • ViewModel puede tener múltiples entidades u objetos de diferentes modelos de datos o fuentes de datos.

Diseñando ViewModel

public class UserLoginViewModel 
{ 
[Required(ErrorMessage = "Please enter your username")] 
[Display(Name = "User Name")]
[MaxLength(50)]
public string UserName { get; set; }
 [Required(ErrorMessage = "Please enter your password")]
 [Display(Name = "Password")]
 [MaxLength(50)]
 public string Password { get; set; } 
} 

Presentación del modelo de vista en la vista

@model MyModels.UserLoginViewModel 
@{
 ViewBag.Title = "User Login";
 Layout = "~/Views/Shared/_Layout.cshtml";
}
@using (Html.BeginForm())
{
<div class="editor-label">
 @Html.LabelFor(m => m.UserName)
</div>
<div class="editor-field">
 @Html.TextBoxFor(m => m.UserName)
 @Html.ValidationMessageFor(m => m.UserName)
</div>
<div class="editor-label">
 @Html.LabelFor(m => m.Password)
</div>
<div class="editor-field">
 @Html.PasswordFor(m => m.Password)
 @Html.ValidationMessageFor(m => m.Password)
</div>
<p>
 <input type="submit" value="Log In" />
</p>
</div>
}

Trabajando con acción

public ActionResult Login()
{ 
return View();
}
[HttpPost]
public ActionResult Login(UserLoginViewModel user)
{
// To acces data using LINQ
DataClassesDataContext mobjentity = new DataClassesDataContext();
 if (ModelState.IsValid) 
{ 
try
 {
 var q = mobjentity.tblUsers.Where(m => m.UserName == user.UserName && m.Password == user.Password).ToList(); 
 if (q.Count > 0) 
 { 
 return RedirectToAction("MyAccount");
 }
 else
 {
 ModelState.AddModelError("", "The user name or password provided is incorrect.");
 }
 }
 catch (Exception ex)
 {
 } 
 } 
 return View(user);
} 
  1. En ViewModel, coloque solo los campos / datos que desea mostrar en la vista / página.
  2. Como view representa las propiedades de ViewModel, por lo tanto, es fácil de renderizar y mantener.
  3. Use un mapeador cuando ViewModel se vuelva más complejo.
codificador salvaje
fuente
1

View Model es una clase que podemos usar para representar datos en View. Supongamos que tiene dos entidades Place y PlaceCategory y desea acceder a los datos de ambas entidades usando un solo modelo, luego usamos ViewModel.

  public class Place
    {
       public int PlaceId { get; set; }
        public string PlaceName { get; set; }
        public string Latitude { get; set; }
        public string Longitude { get; set; }
        public string BestTime { get; set; }
    }
    public class Category
    {
        public int ID { get; set; }
        public int? PlaceId { get; set; }
        public string PlaceCategoryName { get; set; }
        public string PlaceCategoryType { get; set; }
    }
    public class PlaceCategoryviewModel
    {
        public string PlaceName { get; set; }
        public string BestTime { get; set; }
        public string PlaceCategoryName { get; set; }
        public string PlaceCategoryType { get; set; }
    }

Entonces, en el Ejemplo anterior, Lugar y Categoría son las dos entidades diferentes y el modelo de vista PlaceCategory es ViewModel que podemos usar en View.

Sagar Shinde
fuente
Tus ejemplos no son tan claros. Lo que se indicó anteriormente es que un ViewModel conecta datos a su vista. Si observa los ViewModels en BlipAjax, verá las clases que son perfectas para ello.
Herman Van Der Blom
0

Si desea estudiar el código de cómo configurar una aplicación web "Baseline" con ViewModels, puedo aconsejarle que descargue este código en GitHub: https://github.com/ajsaulsberry/BlipAjax . Desarrollé aplicaciones para grandes empresas. Cuando hace esto, es problemático configurar una buena arquitectura que maneje toda esta funcionalidad "ViewModel". Creo que con BlipAjax tendrás una muy buena "línea de base" para comenzar. Es solo un sitio web simple, pero excelente en su simplicidad. Me gusta la forma en que usaron el idioma inglés para señalar lo que realmente se necesita en la aplicación.

Herman Van Der Blom
fuente