Pasar datos a la página maestra en ASP.NET MVC

102

¿Cuál es su forma de pasar datos a la página maestra (utilizando ASP.NET MVC) sin romper las reglas de MVC?

Personalmente, prefiero codificar el controlador abstracto (controlador base) o la clase base que se pasa a todas las vistas.

Łukasz Sowa
fuente
1
Escribí una guía sobre cómo manejé esto: britishdeveloper.co.uk/2010/06/… debería ayudar
BritishDeveloper

Respuestas:

77

Si prefiere que sus vistas tengan clases de datos de vistas fuertemente tipadas, esto podría funcionar para usted. Otras soluciones son probablemente más correctas, pero este es un buen equilibrio entre diseño y practicidad en mi humilde opinión.

La página maestra toma una clase de datos de vista fuertemente tipada que contiene solo información relevante para ella:

public class MasterViewData
{
    public ICollection<string> Navigation { get; set; }
}

Cada vista que usa esa página maestra toma una clase de datos de vista fuertemente tipada que contiene su información y que se deriva de los datos de vista de las páginas maestras:

public class IndexViewData : MasterViewData
{
    public string Name { get; set; }
    public float Price { get; set; }
}

Como no quiero que los controladores individuales sepan nada sobre cómo reunir los datos de las páginas maestras, encapsulo esa lógica en una fábrica que se pasa a cada controlador:

public interface IViewDataFactory
{
    T Create<T>()
        where T : MasterViewData, new()
}

public class ProductController : Controller
{
    public ProductController(IViewDataFactory viewDataFactory)
    ...

    public ActionResult Index()
    {
        var viewData = viewDataFactory.Create<ProductViewData>();

        viewData.Name = "My product";
        viewData.Price = 9.95;

        return View("Index", viewData);
    }
}

La herencia coincide con el maestro para ver bien la relación, pero cuando se trata de representar parciales / controles de usuario, compondré sus datos de vista en los datos de vista de páginas, por ejemplo

public class IndexViewData : MasterViewData
{
    public string Name { get; set; }
    public float Price { get; set; }
    public SubViewData SubViewData { get; set; }
}

<% Html.RenderPartial("Sub", Model.SubViewData); %>

Este es solo un código de ejemplo y no está destinado a compilarse tal cual. Diseñado para ASP.Net MVC 1.0.

Error generico
fuente
4
Este es el método recomendado por Scott Gutherie, así que estaría de acuerdo.
Simon Fox
@Simon Fox: ¿tienes un enlace a la recomendación de scottgu? No pude encontrarlo.
orip
Lo siento. Me cuesta un poco entender parte de esto. Al constructor del controlador se le pasa una instancia de IViewDataFactory pero el sistema espera un constructor sin parámetros. Tampoco estoy familiarizado con esa sintaxis de C # (específicamente el "MasterViewData, new ()") para la interfaz. ¿Alguien puede explicarlo o señalarme un buen recurso? Gracias.
Jason
5
Me gusta tener modelos fuertemente tipados para trabajar, pero no soy un gran fanático de acoplar los datos maestros con todos mis otros modelos y acciones. Saltar a este hilo un poco tarde, pero publiqué mi enfoque de los datos maestros que mantiene las cosas más sueltas.
Todd Menier
59

Prefiero dividir las partes basadas en datos de la vista maestra en parciales y renderizarlas usando Html.RenderAction . Esto tiene varias ventajas distintas sobre el enfoque de herencia del modelo de vista popular:

  1. Los datos de la vista maestra están completamente desacoplados de los modelos de vista "normales". Esto es composición sobre herencia y da como resultado un sistema más débilmente acoplado que es más fácil de cambiar.
  2. Los modelos de vista maestra se crean mediante una acción de controlador completamente separada. Las acciones "regulares" no necesitan preocuparse por esto, y no hay necesidad de una factoría de datos de visualización, que parece demasiado complicada para mi gusto.
  3. Si utiliza una herramienta como AutoMapper para asignar su dominio a sus modelos de vista, le resultará más fácil de configurar porque sus modelos de vista se parecerán más a sus modelos de dominio cuando no hereden los datos de la vista maestra.
  4. Con métodos de acción separados para datos maestros, puede aplicar fácilmente el almacenamiento en caché de salida a ciertas regiones de la página. Normalmente, las vistas maestras contienen datos que cambian con menos frecuencia que el contenido de la página principal.
Todd Menier
fuente
3
+1. Otra ventaja es que puede hacer que la misma vista utilice diferentes páginas maestras según el estado de tiempo de ejecución actual.
StriplingWarrior
1
Me gusta mucho esta respuesta: los otros enfoques descritos parecen un poco complicados.
Paddy
2
Esta es la solución más elegante en mi opinión.
autonomatt
1
Esta solución también me parece la mejor. ¡Un millón de gracias!
JimDaniel
1
Esta es una excelente manera, pero recuerde que aún debe especificar rutas para sus "acciones parciales". Vea esta respuesta stackoverflow.com/a/3553617/56621
Alex
20

EDITAR

Error genérico ha proporcionado una mejor respuesta a continuación. ¡Por favor leelo!

Respuesta original

Microsoft ha publicado una entrada sobre la forma "oficial" de manejar esto. Esto proporciona un recorrido paso a paso con una explicación de su razonamiento.

En resumen, recomiendan usar una clase de controlador abstracto, pero compruébelo usted mismo.

Michael La Voie
fuente
¡GRACIAS! Ese ejemplo es EXACTAMENTE lo que estoy haciendo ... categoría en cada página que proviene de la base de datos.
Martin
Scott Gutherie, uno de los autores de MVC recomienda la solución proporcionada por @Generic Error a continuación
Simon Fox
1
+1 para dirigir a la mejor respuesta incluso cuando la suya es oficialmente correcta y OP es aceptada como respuesta.
IsmailS
+1 para dirigir a la mejor respuesta incluso cuando la suya es oficialmente correcta y OP es aceptada como respuesta.
Dave Jellison
De hecho, Todd Menier es actualmente la mejor respuesta para esto.
andreialecu
7

Los controladores abstractos son una buena idea y no he encontrado una mejor manera. También me interesa ver lo que han hecho otras personas.

Ian P
fuente
2

Encuentro que un padre común para todos los objetos de modelo que pasa a la vista es excepcionalmente útil.

De todos modos, siempre habrá algunas propiedades de modelo comunes entre las páginas.

Matt Mitchell
fuente
0

El objeto Request.Params es mutable. Es bastante fácil agregarle valores escalares como parte del ciclo de procesamiento de solicitudes. Desde la perspectiva de la vista, esa información podría haberse proporcionado en QueryString o FORM POST. hth


fuente
0

Creo que otra buena manera podría ser crear una interfaz para ver con alguna propiedad como ParentView de alguna interfaz, para que pueda usarla tanto para los controles que necesitan una referencia a la página (control principal) como para las vistas maestras a las que se debe acceder desde puntos de vista.

dimarzionista
fuente
0

Las otras soluciones carecen de elegancia y tardan demasiado. Pido disculpas por hacer esto muy triste y empobrecido casi un año después:

<script runat="server" type="text/C#">
    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        MasterModel = SiteMasterViewData.Get(this.Context);
    }

    protected SiteMasterViewData MasterModel;
</script>

Claramente tengo este método estático Get () en SiteMasterViewData que devuelve SiteMasterViewData.

rasx
fuente
para muchos, esto puede parecer un poco extraño o 'sucio', pero hace el trabajo rápidamente
argh
Ugh. Su código parece mucho más difícil de mantener que si hubiera utilizado Html.RenderAction ().
Dan Esparza