Cómo manejar vistas complejas (que constan de varias partes) en la aplicación web MVC

7

Digamos que estoy escribiendo una aplicación web de blog usando el patrón MVC. El diseño típico de la página principal de la aplicación de blog es: algún tipo de índice de publicación en la parte principal, y aparte hay algunas partes adicionales, como la línea de tiempo, el panel de navegación de etiquetas, el panel de suscripción, etc. Esos controles también aparecen en un solo vista de publicación, y puede aparecer en otras vistas que tengo.

Mi pregunta es: ¿cómo debo manejar esos paneles a un lado en mis vistas y controladores? Veo tres enfoques aquí:

  1. Cree una clase de modelo de vista grande que contenga toda la información requerida para representar las vistas (ya sea índice o publicación única). Ese caso podría hacer que estos paneles a un lado sean vistas parciales, y llamarlos desde la vista que se representa pasando parte de ese gran modelo de vista. El inconveniente es que tendré el código que llena el modelo de vista distribuido entre varios métodos de controlador, lo que significa que el código está duplicado. Lo cual es bastante malo.

  2. Cree otra capa de representación de vista. Digamos, la capa superior de renderizado recibe partes ya representadas de html, o funciones que cuando se llama generan un html. La capa debajo de esta "capa de combinación de parciales" daría solo vistas parciales para cada panel que desee, incluyendo contenido principal. El inconveniente aquí: uso de memoria. La mayoría de los marcos modernos procesan htmls directamente en la secuencia de salida, pero en este enfoque las vistas parciales se procesarían primero en objetos de cadena, lo que lleva a una sobrecarga de memoria.

  3. Use algo como "RenderAction" de asp.net mvc, que llama a un método de controlador desde una vista. Creo que esta es la peor solución de 3 dado, porque deja caer un enfoque MVC.

La pregunta no está vinculada a ningún marco específico, quiero entender la forma general de hacer cosas así.

ACTUALIZAR

Después de una respuesta dada, descubrí que la publicación no está clara. Así que una actualización razonable aquí:

Bajo el término viewmodel , entiendo un objeto que contiene todos los datos necesarios para representar una vista en particular.

Los tres enfoques implican la construcción de vistas parciales con su propio modelo de vista. Por ejemplo (usando la sintaxis de C #):

class SinglePostViewModel {
  string Text {get;set;}
  string Title {get;set;}
  string Slug {get;set;}
  DateTime PublishedDate {get;set;}
  ...
}

class TagNavigationPanelViewModel {
  string TagText {get;set;}
  int PostsCount {get;set;}
}

class CalendarNavigationPanelViewModel {
  DateTime YearAndMonth {get;set;}
  int PostsCount {get;set;} 
}

Mi pregunta es: cómo combinar bien esas vistas parciales.

Hedin
fuente

Respuestas:

1

Veo otro método que, a menos que haya entendido mal su publicación, no se ha mencionado:

La vista principal post, tendría su modelo. Este modelo consistiría en SÓLO las propiedades necesarias para visualizar este post ( author, title, body, etc). Entonces, cada pieza de la postopinión de que se pueda imaginar ( timeline, tag navigation panel, subscribing panel, etc.), se dividiría en sus propios puntos de vista y cada uno tendría su propio modelo. De esta manera, puede construir esos modelos en su controlador cuando los necesite.

Puede parecer una cantidad innecesaria de trabajo adicional dividirlos de esta manera, pero se presta al principio de responsabilidad única . Mantenga cada "vista / modelo" enfocado en sí mismo para que pueda ser reutilizado donde sea necesario.

Si cree que su código está comenzando a duplicarse, lo que podría depender de su situación, debería considerar escribir algún tipo de "clase auxiliar". Esta clase auxiliar manejaría toda la acumulación del modelo en un lugar, y todos los demás códigos duplicados se eliminarían a una llamada de clase auxiliar.

ethorn10
fuente
Este es un enfoque general que trato de seguir. Mi pregunta era sobre cómo combinar estas vistas parciales con modelos propios. Aún así, actualizaría la pregunta para que quede más clara.
Hedin
1
Ya veo ... perdón por la confusión inicial. Yo iría con la vista de contenedor que contiene todas las vistas parciales necesarias, personalmente.
ethorn10
1

Lo que estoy haciendo es una variación / combinación de sus puntos 1 y 3. Combino los modelos de vista en una clase de contenedor, y lo uso como un modelo de vista "principal". Pasan las partes como modelos a los parciales.

Siguiendo su ejemplo, crearía este modelo de vista para la página predeterminada:

class DefaultViewModel {
  public List<SinglePostViewModel> Posts ...
  public TagNavigationPanelViewModel Tags ...
  public CalendarNavigationPanelViewModel Calendar ...
  ...
}

En Default.cshtml

@model DefaultViewModel
...html for rendering the default page...


@Html.Partial("_TagNavigationPanel", Model.Tags)
...etc...

En _TagNavigationPanel.cshtml

@model TagNavigationPanelViewModel
...html+razor for rendering the tags...

Luego, siga el mismo enfoque para una sola página de publicación:

class SinglePostPageViewModel {
  public SinglePostViewModel Post ...
  // no tags in single view, for example..
  // public TagNavigationPanelViewModel Tags ...
  public CalendarNavigationPanelViewModel Calendar ...
  // But a list of related, perhaps?
  public List<RelatedPosts> RelatedPosts
  ...
}

Y cree sus vistas (cshtml (s)) en consecuencia

Lorenzo Dematté
fuente
De esto se trata 1 enfoque. 3rd es solo acerca de llamar a RenderAction o @ Html.Action, lo que implica llamar al método controlador. ¡Gracias por responder!
Hedin
1
@Hedin oh, ok ... pensé que tu enfoque # 1 era más "monolítico", con un modelo de vista grande (diferente). Entonces sí, uso 1 y me parece bueno. También me gusta el tercero menos, pero es un buen almacenamiento en caché. Si tiene problemas de rendimiento o necesita almacenar en caché partes de la vista, puede valer la pena intentarlo.
Lorenzo Dematté
¿Qué hay de omitir una vista parcial? por ejemplo, basado en un rol de usuario?
LifeH2O
0

Es posible crear una única visión "contenedor" con los tres subvistas - SinglePostView, TagNavigationPanelViewy CalendarNavigationPanelView. También puede reemplazarlo SinglePostViewcon cualquier otra vista que requiera una página. De esta forma, solo necesita reemplazar la vista "central" (publicación) para diferentes páginas con otro tipo de vista (por ejemplo, lista de publicaciones) y las otras vistas solo necesitan actualizarse con los datos correspondientes, no reemplazados.

Su vista de contenedor (por ejemplo MyView) debe contener referencias a todas las subvistas. Puede tener diferentes updatemétodos que se utilizan para actualizar diferentes subvistas. Por ejemplo, updateCalendar(CalendarNavigationPanelViewModel calendarData)o updatePost(SinglePostViewModel postData). O incluso uno solo update(IViewModel modelData), entonces deberá verificar el tipo de (y emitir) modelDatapara determinar qué vista actualizar

stan0
fuente