Passando dados para a página mestra na ASP.NET MVC

102

Qual é a sua maneira de passar dados para a página mestra (usando ASP.NET MVC) sem quebrar as regras do MVC?

Pessoalmente, prefiro codificar controlador abstrato (controlador de base) ou classe base que é passada para todas as visualizações.

Łukasz Sowa
fonte
1
Eu escrevi um guia sobre como eu consegui isso: britishdeveloper.co.uk/2010/06/… deve ajudar
BritishDeveloper

Respostas:

77

Se você preferir que suas visualizações tenham classes de dados de visualização fortemente tipadas, isso pode funcionar para você. Outras soluções são provavelmente mais corretas, mas este é um bom equilíbrio entre design e praticidade IMHO.

A página mestra tem uma classe de dados de visualização fortemente tipada contendo apenas informações relevantes a ela:

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

Cada visualização que usa essa página mestra tem uma classe de dados de visualização fortemente tipada contendo suas informações e derivando dos dados de visualização das páginas mestras:

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

Como não quero que os controladores individuais saibam nada sobre como reunir os dados das páginas mestras, encapsulo essa lógica em uma fábrica que é passada para 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);
    }
}

A herança corresponde bem ao relacionamento mestre para visualizar, mas quando se trata de renderizar parciais / controles de usuário, irei compor seus dados de visualização nos dados de visualização de páginas, por exemplo

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 é apenas um código de exemplo e não se destina a compilar como está. Projetado para ASP.Net MVC 1.0.

Erro Genérico
fonte
4
Este é o método recomendado por Scott Gutherie, então eu tenho que concordar.
Simon Fox,
@Simon Fox - tem um link para a recomendação de scottgu? Não foi possível encontrar.
orip
Desculpe. Tendo um pouco de dificuldade para entender parte disso. O construtor do controlador recebe uma instância de IViewDataFactory, mas o sistema espera um construtor sem parâmetros. Também não estou familiarizado com a sintaxe C # (especificamente o "MasterViewData, new ()") para a interface. Alguém pode me explicar ou apontar um bom recurso. Obrigado.
Jason
5
Gosto de ter modelos fortemente tipados para trabalhar, mas não sou um grande fã de acoplar os dados mestre com todos os meus outros modelos e ações. Entrando neste tópico um pouco tarde, eu postei minha abordagem para dados mestres que mantém as coisas mais soltas.
Todd Menier
59

Eu prefiro quebrar as partes orientadas por dados da visualização mestre em parciais e renderizá-las usando Html.RenderAction . Isso tem várias vantagens distintas sobre a abordagem de herança de modelo de visão popular:

  1. Os dados da visão mestre são completamente dissociados dos modelos de visão "regulares". Isso é composição sobre herança e resulta em um sistema mais fracamente acoplado que é mais fácil de alterar.
  2. Os modelos de visualização mestre são construídos por uma ação de controlador completamente separada. Ações "regulares" não precisam se preocupar com isso e não há necessidade de uma fábrica de dados de exibição, o que parece muito complicado para o meu gosto.
  3. Se acontecer de você usar uma ferramenta como o AutoMapper para mapear seu domínio para seus modelos de visualização, você achará mais fácil configurar porque seus modelos de visualização serão mais semelhantes aos seus modelos de domínio quando eles não herdarem os dados de visualização mestre.
  4. Com métodos de ação separados para dados mestres, você pode aplicar facilmente o cache de saída a certas regiões da página. Normalmente, as visualizações principais contêm dados que mudam com menos frequência do que o conteúdo da página principal.
Todd Menier
fonte
3
+1. Outra vantagem é que você pode fazer com que a mesma visualização use páginas-mestre diferentes, dependendo do estado do tempo de execução atual.
StriplingWarrior
1
Gosto muito desta resposta - as outras abordagens descritas parecem um pouco complicadas demais.
Paddy
2
Esta é a solução mais elegante na minha opinião.
autonomatt
1
Essa solução também parece a melhor para mim. Obrigado um milhão!
JimDaniel de
1
Esta é uma ótima maneira, mas lembre-se de que você ainda precisa especificar rotas para suas "ações parciais". Veja esta resposta stackoverflow.com/a/3553617/56621
Alex
20

EDITAR

Erro genérico forneceu uma resposta melhor abaixo. Por favor, leia!

Resposta Original

A Microsoft publicou uma entrada sobre a maneira "oficial" de lidar com isso. Isso fornece um passo a passo com uma explicação de seu raciocínio.

Resumindo, eles recomendam o uso de uma classe de controlador abstrata, mas veja por si mesmo.

Michael La Voie
fonte
OBRIGADO! Esse exemplo é EXATAMENTE o que estou fazendo ... categoria em cada página proveniente do banco de dados.
Martin
Scott Gutherie, um dos autores do MVC, recomenda a solução fornecida por @Generic Error abaixo
Simon Fox
1
+1 para direcionar a melhor resposta mesmo quando a sua está oficialmente certa e aceita como resposta pela OP.
IsmailS
+1 para direcionar a melhor resposta mesmo quando a sua está oficialmente certa e aceita como resposta pela OP.
Dave Jellison
Na verdade, Todd Menier é atualmente a melhor resposta para isso.
andreialecu
7

Controladores abstratos são uma boa ideia e não encontrei uma maneira melhor. Estou interessado em ver o que outras pessoas também fizeram.

Ian P
fonte
2

Acho que um pai comum para todos os objetos de modelo que você passa para a visualização é excepcionalmente útil.

Sempre haverá a tendência de haver algumas propriedades de modelo comuns entre as páginas.

Matt Mitchell
fonte
0

O objeto Request.Params é mutável. É muito fácil adicionar valores escalares a ele como parte do ciclo de processamento da solicitação. Do ponto de vista da visão, essas informações podem ter sido fornecidas no QueryString ou no FORM POST. hth


fonte
0

Acho que outra boa maneira poderia ser criar uma interface para visualização com alguma propriedade, como ParentView de alguma interface, para que você possa usá-la tanto para controles que precisam de uma referência à página (controle pai) quanto para visualizações principais que devem ser acessadas de Visualizações.

dimarzionista
fonte
0

As outras soluções carecem de elegância e demoram muito. Peço desculpas por fazer essa coisa tão triste e empobrecida quase um ano inteiro depois:

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

    protected SiteMasterViewData MasterModel;
</script>

Portanto, claramente tenho este método estático Get () em SiteMasterViewData que retorna SiteMasterViewData.

rasx
fonte
para muitos, isso pode parecer um pouco hacky ou "sujo", mas faz o trabalho muito rapidamente
argh
Ugh. Seu código parece muito mais difícil de manter do que se você tivesse usado Html.RenderAction ().
Dan Esparza