Transmitir dados para Exibir páginas mestras (C#)
pela Microsoft
O objetivo deste tutorial é explicar como você pode passar dados de um controlador para um modo de exibição master página. Examinamos duas estratégias para passar dados para uma página master de exibição. Primeiro, discutimos uma solução fácil que resulta em um aplicativo difícil de manter. Em seguida, examinamos uma solução muito melhor que requer um pouco mais de trabalho inicial, mas resulta em um aplicativo muito mais mantenedor.
Passando dados para exibir páginas mestras
O objetivo deste tutorial é explicar como você pode passar dados de um controlador para um modo de exibição master página. Examinamos duas estratégias para passar dados para uma página master de exibição. Primeiro, discutimos uma solução fácil que resulta em um aplicativo difícil de manter. Em seguida, examinamos uma solução muito melhor que requer um pouco mais de trabalho inicial, mas resulta em um aplicativo muito mais mantenedor.
O problema
Imagine que você está criando um aplicativo de banco de dados de filme e deseja exibir a lista de categorias de filmes em cada página do aplicativo (consulte a Figura 1). Imagine, além disso, que a lista de categorias de filmes é armazenada em uma tabela de banco de dados. Nesse caso, faria sentido recuperar as categorias do banco de dados e renderizar a lista de categorias de filme em uma exibição master página.
Figura 01: Exibindo categorias de filme em um modo de exibição master página (Clique para exibir imagem em tamanho real)
Este é o problema. Como recuperar a lista de categorias de filmes na página master? É tentador chamar métodos de suas classes de modelo diretamente na página master. Em outras palavras, é tentador incluir o código para recuperar os dados do banco de dados diretamente na página master. No entanto, ignorar seus controladores MVC para acessar o banco de dados violaria a separação limpo de preocupações que é um dos principais benefícios da criação de um aplicativo MVC.
Em um aplicativo MVC, você deseja que toda a interação entre as exibições do MVC e o modelo MVC seja tratada pelos controladores MVC. Essa separação de preocupações resulta em um aplicativo mais mantenedor, adaptável e testável.
Em um aplicativo MVC, todos os dados passados para uma exibição – incluindo uma exibição master página – devem ser passados para uma exibição por uma ação do controlador. Além disso, os dados devem ser passados aproveitando os dados de exibição. No restante deste tutorial, examinei dois métodos de passar dados de exibição para uma exibição master página.
A solução simples
Vamos começar com a solução mais simples para passar dados de exibição de um controlador para um modo de exibição master página. A solução mais simples é passar os dados de exibição para a página master em cada ação do controlador.
Considere o controlador na Listagem 1. Ele expõe duas ações denominadas Index()
e Details()
. O Index()
método de ação retorna todos os filmes na tabela de banco de dados Filmes. O Details()
método de ação retorna todos os filmes em uma categoria de filme específica.
Listagem 1 – Controllers\HomeController.cs
using System.Linq;
using System.Web.Mvc;
using MvcApplication1.Models;
namespace MvcApplication1.Controllers
{
[HandleError]
public class HomeController : Controller
{
private MovieDataContext _dataContext = new MovieDataContext();
/// <summary>
/// Show list of all movies
/// </summary>
public ActionResult Index()
{
ViewData["categories"] = from c in _dataContext.MovieCategories
select c;
ViewData["movies"] = from m in _dataContext.Movies
select m;
return View();
}
/// <summary>
/// Show list of movies in a category
/// </summary>
public ActionResult Details(int id)
{
ViewData["categories"] = from c in _dataContext.MovieCategories
select c;
ViewData["movies"] = from m in _dataContext.Movies
where m.CategoryId == id
select m;
return View();
}
}
}
Observe que as ações Index() e Details() adicionam dois itens para exibir dados. A ação Index() adiciona duas chaves: categorias e filmes. A chave de categorias representa a lista de categorias de filme exibidas pela página master exibição. A chave de filmes representa a lista de filmes exibidos pela página exibição Índice.
A ação Detalhes() também adiciona duas chaves chamadas categorias e filmes. A chave de categorias, mais uma vez, representa a lista de categorias de filme exibidas pela página master exibição. A chave de filmes representa a lista de filmes em uma categoria específica exibida pela página exibição Detalhes (consulte a Figura 2).
Figura 02: a exibição Detalhes (Clique para exibir a imagem em tamanho real)
A exibição Índice está contida na Listagem 2. Ele simplesmente itera por meio da lista de filmes representados pelo item filmes em dados de exibição.
Listagem 2 – Views\Home\Index.aspx
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" AutoEventWireup="true" CodeBehind="Index.aspx.cs" Inherits="MvcApplication1.Views.Home.Index" %>
<%@ Import Namespace="MvcApplication1.Models" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
<ul>
<% foreach (var m in (IEnumerable<Movie>)ViewData["movies"])
{ %>
<li><%= m.Title %></li>
<% } %>
</ul>
</asp:Content>
A página master de exibição está contida na Listagem 3. O modo de exibição master página itera e renderiza todas as categorias de filme representadas pelo item de categorias dos dados de exibição.
Listagem 3 – Views\Shared\Site.master
<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Site.Master.cs" Inherits="MvcApplication1.Views.Shared.Site" %>
<%@ Import Namespace="MvcApplication1.Models" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title></title>
<asp:ContentPlaceHolder ID="head" runat="server">
</asp:ContentPlaceHolder>
</head>
<body>
<div>
<h1>My Movie Website</h1>
<% foreach (var c in (IEnumerable<MovieCategory>)ViewData["categories"])
{%>
<%= Html.ActionLink(c.Name, "Details", new {id=c.Id} ) %>
<% } %>
<asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
</asp:ContentPlaceHolder>
</div>
</body>
</html>
Todos os dados são passados para a exibição e a exibição master página por meio de dados de exibição. Essa é a maneira correta de passar dados para a página master.
Então, o que há de errado com essa solução? O problema é que essa solução viola o princípio DRY (Don't Repeat Yourself). Cada ação do controlador deve adicionar a mesma lista de categorias de filme para exibir dados. Ter código duplicado em seu aplicativo torna seu aplicativo muito mais difícil de manter, adaptar e modificar.
A boa solução
Nesta seção, examinamos uma solução alternativa e melhor para passar dados de uma ação do controlador para uma exibição master página. Em vez de adicionar as categorias de filme para a página master em cada ação de controlador, adicionamos as categorias de filme aos dados de exibição apenas uma vez. Todos os dados de exibição usados pela página master de exibição são adicionados em um controlador de aplicativo.
A classe ApplicationController está contida na Listagem 4.
Listagem 4 – Controllers\ApplicationController.cs
using System.Linq;
using System.Web.Mvc;
using MvcApplication1.Models;
namespace MvcApplication1.Controllers
{
public abstract class ApplicationController : Controller
{
private MovieDataContext _dataContext = new MovieDataContext();
public MovieDataContext DataContext
{
get { return _dataContext; }
}
public ApplicationController()
{
ViewData["categories"] = from c in DataContext.MovieCategories
select c;
}
}
}
Há três coisas que você deve observar sobre o controlador de aplicativo na Listagem 4. Primeiro, observe que a classe herda da classe base System.Web.Mvc.Controller. O controlador de aplicativo é uma classe de controlador.
Em segundo lugar, observe que a classe de controlador de aplicativo é uma classe abstrata. Uma classe abstrata é uma classe que deve ser implementada por uma classe concreta. Como o controlador de aplicativo é uma classe abstrata, você não pode invocar nenhum método definido na classe diretamente. Se você tentar invocar a classe Application diretamente, receberá uma mensagem de erro Recurso Não Encontrado.
Em terceiro lugar, observe que o controlador de aplicativo contém um construtor que adiciona a lista de categorias de filme para exibir dados. Cada classe de controlador que herda do controlador de aplicativo chama o construtor do controlador de aplicativo automaticamente. Sempre que você chama qualquer ação em qualquer controlador herdado do controlador de aplicativo, as categorias de filme são incluídas nos dados de exibição automaticamente.
O controlador Filmes na Listagem 5 herda do controlador de aplicativo.
Listagem 5 – Controllers\MoviesController.cs
using System.Linq;
using System.Web.Mvc;
namespace MvcApplication1.Controllers
{
public class MoviesController : ApplicationController
{
/// <summary>
/// Show list of all movies
/// </summary>
public ActionResult Index()
{
ViewData["movies"] = from m in DataContext.Movies
select m;
return View();
}
/// <summary>
/// Show list of movies in a category
/// </summary>
public ActionResult Details(int id)
{
ViewData["movies"] = from m in DataContext.Movies
where m.CategoryId == id
select m;
return View();
}
}
}
O controlador Movies, assim como o controlador Home discutido na seção anterior, expõe dois métodos de ação chamados Index()
e Details()
. Observe que a lista de categorias de filme exibidas pelo modo de exibição master página não é adicionada para exibir dados no Index()
método ou Details()
. Como o controlador movies herda do controlador de aplicativo, a lista de categorias de filme é adicionada para exibir dados automaticamente.
Observe que essa solução para adicionar dados de exibição para uma exibição master página não viola o princípio DRY (Não Repita a Si mesmo). O código para adicionar a lista de categorias de filme para exibir dados está contido em apenas um local: o construtor do controlador de aplicativo.
Resumo
Neste tutorial, discutimos duas abordagens para passar dados de exibição de um controlador para um modo de exibição master página. Primeiro, examinamos uma abordagem simples, mas difícil de manter. Na primeira seção, discutimos como você pode adicionar dados de exibição para uma exibição master página em cada ação do controlador em seu aplicativo. Concluímos que essa era uma abordagem ruim porque viola o princípio DRY (Don't Repeat Yourself).
Em seguida, examinamos uma estratégia muito melhor para adicionar dados exigidos por um modo de exibição master página para exibir dados. Em vez de adicionar os dados de exibição em cada ação do controlador, adicionamos os dados de exibição apenas uma vez em um controlador de aplicativo. Dessa forma, você pode evitar código duplicado ao passar dados para uma página master de exibição em um aplicativo MVC ASP.NET.