tag net mvc for cshtml asp asp.net-mvc model-view-controller

for - Uso correcto de Modelo vs Controlador en MVC/ASP.NET MVC



tag helper asp net core 2 (9)

En una arquitectura MVC clásica, su modelo no debe ser mucho más que un contenedor para sus datos de vista, de ahí la razón por la que a menudo se lo llama un modelo de vista . Un modelo de vista es diferente de los modelos de entidad que gestiona su capa de servicio.

Su controlador es entonces responsable de llenar su ViewModel de los modelos de entidad devueltos por su capa de servicio.

Debido a la conveniencia, algunos desarrolladores utilizarán sus entidades de capa de servicio directamente en sus Modelos de Vista pero a largo plazo que pueden generar dolores de cabeza. Una forma de AutoMapper es utilizar una herramienta como AutoMapper para automatizar la mezcla de datos hacia y desde su ViewModel y modelos de entidad.

Esto es lo que podría parecer un controlador. Tenga en cuenta que los datos, como el SSN, no se exponen a la vista, ya que existe una asignación de los Modelos de su Entidad a su Modelo de Vista.

public class Customer : IEntity { public string CustomerID { get; set; } public string SSN { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public Address Address { get; set; } } public class CustomerEditViewModel { public string FirstName { get; set; } public string LastName { get; set; } public string Address1 { get; set; } public string Address2 { get; set; } public string Country { get; set; } public string City { get; set; } public string State { get; set; } public string Zip { get; set; } public string PhoneNumber { get; set; } } public class CustomerController { [AcceptVerbs (HttpVerbs.Get)] public ActionResult Edit () { Customer customer = _customerService.GetCustomer (User.Identity.Name); var model = new CustomerEditViewModel () { FirstName = customer.FirstName, LastName = customer.LastName, Address1 = customer.Address.Address1, Address2 = customer.Address.Address2, Country = customer.Address.Country, City = customer.Address.City, State = customer.Address.State, Zip = customer.Address.Zip, PhoneNumber = customer.Address.PhoneNumber, }; return View (model); } }

Tengo una clase de servicio con un método llamado GetProducts (). Eso encapsula la lógica empresarial y llama al repositorio para obtener una lista de productos.

Mi vista de MVC quiere mostrar esa lista de productos como MVC SelectList. ¿Dónde está el lugar correcto para que esa lógica vaya? Parece que tengo 3 opciones:

  1. Modelo

    El Modelo debe exponer una propiedad llamada ProductSelectList . Cuando el Visualizador llama a la captadora de esta propiedad, el Modelo debe llamar a Service.GetProducts() y convertir el resultado a una SelectList antes de pasarla.

    Argumento plausible: el Modelo debe hacer llamadas a la lógica comercial y al repositorio. La vista debería simplemente representar datos predeterminados. El controlador no debe participar, salvo para pasar datos contextuales al modelo.

  2. Ver

    La Vista debe contener código que llame a Service.GetProducts() directamente y convierta el resultado en una SelectList en línea.

    Argumento plausible: la vista debe llamar a estos datos directamente, ya que es específicamente para su uso en la vista. No es necesario involucrar el Modelo o el Controlador, ya que estamos llamando a un método de Servicio abstraído de todos modos, por lo que cualquier otra cosa simplemente agrega una sobrecarga adicional.

  3. Controlador

    El Controlador debe realizar la llamada a Service.GetProducts() , convertir los resultados en una SelectList y pasarla al Modelo, que debe contener una propiedad simple ProductSelectList . La Vista accederá a esta propiedad para renderizar.

    Argumento plausible: el controlador sabe qué parámetros debe proporcionar al método de servicio, por lo que debe realizar la llamada. El Modelo debe ser un simple marcador de posición para los datos, rellenado por el Controlador. El trabajo de View es simplemente renderizar los datos del Modelo.

Tengo la sensación de que la respuesta correcta es Modelo , pero los otros dos hacen algunos puntos razonables. Quizás he enturbiado las aguas al tener ya una clase de Servicio separada del Modelo.

¿Alguien le importaría compartir su opinión? ¿Es solo una cuestión de gusto?


Estoy dividido entre la opción 1 y la opción 3. He descartado completamente la opción 2 en cuanto a mí, que está contaminando la vista con llamadas a procedimientos y no solo a la capa de presentación.

Personalmente, lo haría en el modelo y el getter llamaría a la capa de servicio, pero también me suscribo a la creencia de que el modelo solo debería contener la información que la vista necesita para representar la página, al no contener completamente los datos en el modelo en el vez que lo pasas a la vista estás rompiendo esto.

Otra opción aquí sería evitar acoplar estrechamente la vista y el modelo al incluir un Dictionary de productos en la vista a través de una llamada de servicio y luego usar la vista para transformar el Dictionary a una lista de SelectList pero esto también le da la capacidad de simplemente generar el información también.

Creo que esto se reduce a una preferencia en cuanto a dónde estás contento de tener tu lógica.


Me gustaría ir con la opción 3. En general, construiré mis aplicaciones MVC de manera que el controlador realice una llamada al servicio para devolver un modelo (o una colección de modelos) que luego se pasan a la vista.

Generalmente mantengo mis modelos muy delgados. Son una representación plana de los datos con atributos de validación y eso es todo. Utilizo una capa de servicio (o generador de modelos) para construir los modelos y hacer lógica de negocios en ellos. Algunas personas incorporan eso en el modelo, pero creo que eso lo convierte en un proyecto complicado.

Definitivamente no desea que la vista realice llamadas a sus servicios.

Actualizar...
Estoy asumiendo que esta SelectList es tu modelo. Si, en cambio, es parte de su modelo, entonces tiene razón, debe ponerlo en su modelo. Sin embargo, en general no me gusta hacer una llamada a método. Tendría una propiedad en mi modelo:

public SelectList Products { get; set; }

Y que mi servicio o clase de generador de modelos realmente lo llene. Normalmente no tengo ningún método orientado a los datos en mis modelos.


Ninguna de las anteriores.

En mi capa web, básicamente solo tengo vistas html y javascript. El modelo no debe filtrarse a la vista y tampoco deberían los servicios.

También tengo una capa de infraestructura que vincula los servicios y el modelo a las vistas. En esta capa hay ViewModels, que son clases que representan lo que se mostrará en la pantalla, Mappers, que hacen el trabajo obteniendo datos de los servicios / modelos y asignándolos al modelo de visualización, y Tasks, que realizan tareas tales como Saving, Actualización y eliminación de datos.

Es posible poner una gran cantidad de esta infraestructura en los Controladores, similar al ejemplo que Todd Smith ha dado más arriba, pero creo que para cualquier cosa que no sean vistas triviales, el Controlador se llena de código para cargar datos y poblar modelos de vista. Prefiero una clase dedicada sola mapeador de responsabilidad para cada modelo de vista. Entonces mi controlador se verá algo así como

public class CustomerController { [AcceptVerbs (HttpVerbs.Get)] public ActionResult Edit (int id) { return View (CustomerEditMapper.Map(id)); } [AcceptVerbs (HttpVerbs.Post)] public ActionResult Save(CustomerEditViewModel model) { var errors = CustomerEditUpdatorCommand.Execute(model); ModelState.AddErrors(errors); return View (); } }


Personalmente me suscribo a la lógica del Número 3 , lo que permite al controlador poblar el Modelo (o Ver el Modelo como a veces se diferencia).

  • Tengo mis opiniones tontas y solo mostrar datos.
  • Mis View Models almacenan la información que necesitará View, exponiendo de vez en cuando las propiedades ''get only'' que formatean otras propiedades en un formato más agradable. Si mi modelo necesita acceso a mis servicios, entonces siento que estoy haciendo algo mal.
  • Los controladores organizan y reúnen toda la información en conjunto (pero no hacen ningún trabajo real, que queda para los servicios).

En su ejemplo, mi acción de controlador sería similar a la siguiente:

public ActionResult Index() { IndexViewModel viewModel = new IndexViewModel(); viewModel.ProductSelectList = new SelectList(Service.GetProducts(), "Value", "Name"); return View(viewModel); }

y mi modelo de vista similar a:

public class IndexViewModel() { public SelectList ProductSelectList { get; set; } public int ProductID { get; set; } }

Con la parte apropiada de la vista parecida a:

@Html.DropDownListFor(x => x.ProductID, Model.ProductSelectList);

De esta manera estoy contento de que sé dónde buscar si hay un problema con algo y todo tiene un lugar muy específico.

Sin embargo, no hay una forma correcta, como parece ser siempre el caso con estas cosas. Stephen Walther tiene una buena serie de blogs sobre consejos MVC . En una, él habla sobre el énfasis en el Modelo de Vista y aunque no es una Lista Selecta que completa, la Lista de Selección sigue siendo datos casi de la misma manera que su lista de productos.


Tiene razón en que hay varias maneras de manejar esto, y eso incluso antes de considerar variaciones como MVP, MVVM, etc. Dado que usted está preguntando sobre ASP.Net MVC en particular, lo someteré a Microsoft:

Un modelo MVC contiene toda su lógica de aplicación que no está contenida en una vista o un controlador. El modelo debe contener toda la lógica de negocio de la aplicación, la lógica de validación y la lógica de acceso a la base de datos. Por ejemplo, si está utilizando Microsoft Entity Framework para acceder a su base de datos, entonces debería crear las clases de Entity Framework (su archivo .edmx) en la carpeta Models.

Una vista debe contener solo lógica relacionada con la generación de la interfaz de usuario. Un controlador solo debe contener la mínima lógica necesaria para devolver la vista correcta o redirigir al usuario a otra acción (control de flujo). Todo lo demás debe estar contenido en el modelo.

En general, debe esforzarse por modelos gordos y controladores flacos. Sus métodos de controlador deben contener solo unas pocas líneas de código. Si una acción del controlador se vuelve demasiado grande, entonces debería considerar mover la lógica a una nueva clase en la carpeta Modelos.

Source

Yo diría que su llamada pertenece al Modelo.


Tuve este problema cuando comencé en MVC y se me ocurrió esta solución.

El controlador habla con una capa de servicio. La capa de servicio contiene mis modelos de Dominio y hace todo el procesamiento para solicitud de los Controladores. La capa de servicio también devuelve ViewModels para satisfacer las solicitudes del controlador.

La capa de servicio llama a un repositorio y obtiene las entidades que necesitará para construir ViweModels. A menudo uso Automapper para poblar ViewModel o colecciones dentro del modelo de vista.

Por lo tanto, mis modelos de vista contienen todo lo que necesita la Vista, y el Controlador no hace nada más que manejar la solicitud y reenviarlos al controlador de servicio apropiado.

No veo ningún problema para ver elementos específicos de la vista, como listas de selección en el modelo de vista.


Una cosa a tener en cuenta es que la clase SelectList es específica solo para MVC. Por lo tanto, en mi opinión, no debería incluirse en ninguna lógica comercial, y las clases modelo entran en esa categoría. Por lo tanto, su lista de selección debería formar parte de una clase de modelo de vista.

Esta es la forma en que funciona en mis proyectos:

  • El método del controlador se llama
  • El controlador usa el repositorio (lógica de negocios, en otras palabras) para obtener datos del modelo
  • El controlador convierte los datos del modelo si es necesario y crea un objeto modelo de vista
  • El controlador pasa el modelo de vista a la vista
  • La vista muestra los datos en el modelo de vista con una lógica limitada para mostrar u ocultar cosas, etc.

Voy con la opción 1.

Los modelos son el lugar para hacer llamadas a la lógica de negocios, etcétera.

Ver: debe mostrar solo con qué ViewModel ya se ha rellenado.

Controlador: el trabajo del Controlador es dirigir el tráfico que entra (desde las solicitudes Web) a la Lógica responsable de gestionar la solicitud. De ahí el término '' controlador ''.

Siempre hay excepciones a estos, pero el mejor lugar (estructuralmente) es el Modelo.