O surgimento do ASP.NET MVC ampliou, sem sombra de dúvidas, os horizontes do desenvolvimento Web dentro da plataforma .NET. Este framework (atualmente na versão 4.0) é baseado em um pattern também chamado de MVC (sigla em inglês "para Model-View-Controller"), diferindo do modelo Web Forms por assegurar, basicamente, uma mínima estruturação em camadas de uma aplicação construída sob o mesmo. Esta característica não significa que a implementação de arquiteturas mais elaboradas seja algo difícil em Web Forms; contudo, tal empreitada dependerá do engajamento da equipe envolvida num projeto em buscar uma solução que melhor se adeque ao contexto.
Do ponto de vista arquitetural, aplicações em conformidade com o padrão MVC são formadas por três camadas principais:
- Model: engloba tipos utilizados na representação de informações, além de prováveis regras para a manipulação destes últimos. Estruturas implementadas neste ponto são normalmente utilizadas por Controllers ou ainda, Views que são retornadas como resultado da execução destes elementos;
- View: contém páginas e controles que se prestam à visualização e/ou à entrada de dados por parte de usuários. É também um dos pontos em que se geram requisições enviadas a Controllers para posterior processamento;
- Controller: local em que se encontram classes responsáveis pelo tratamento de requisições (Controllers), sendo que isto acontece através de métodos especiais, os quais são conhecidos como Actions. Considerando o ASP.NET MVC, a execução de uma Action pode devolver como resultado uma página HTML (instância do tipo ViewResult), um arquivo a partir do qual será possível se efetuar o download do mesmo (instância do tipo FileResult), dados no formato JSON (instância do tipo JsonResult), dentre outros tipos de objetos.
Uma View baseada em HTML corresponde, normalmente, a uma forma de visualização de dados retornados por apenas uma Action de um Controller. Contudo, este tipo de equivalência (uma Action x uma View) não deve ser encarado como algo definitivo. Em diversas situações será necessário exibir informações de diferentes fontes em uma mesma View, com cada uma destas apontando para outras Actions de um ou mais Controllers. É neste ponto que um recurso do ASP.NET MVC conhecido como Partial View poderá ser grande valia.
Partial Views equivalem, dentro do framework MVC, aos User Controls comumente utilizados em soluções ASP.NET Web Forms. Trata-se, portanto, de um recurso que enfatiza o reuso de código: uma Partial View representando uma função genérica pode vir a ser consumida em diversos pontos de um site ASP.NET MVC. Com isto se consegue evitar que a funcionalidade em questão seja implementada mais de uma vez ao longo de uma aplicação, facilitando deste modo prováveis atividade futuras de manutenção.
Além desta forma de uso mais convencional, diferentes Partial Views podem ser combinadas dentro de uma View principal, permitindo assim que a partir de uma mesma página HTML se torne possível a visualização de informações originárias de diferentes fontes. O objetivo deste artigo é abordar essa forma de utilização das Partial Views, sendo que isto acontecerá através de um exemplo demonstrado mais adiante.
Criando a solução de exemplo
A aplicação apresentada neste artigo foi criada no Visual Studio 2012 Release Candidate, fazendo uso do .NET Framework 4.5 e da versão 4.0 do ASP.NET MVC. O exemplo implementado procura abordar a construção de uma View em que são exibidos dados quantitativos sobre a população de cada continente, bem como das dez maiores cidades do globo (neste caso, serão criadas duas Partial Views, com cada uma destas manipulando um tipo de informação específico).
Para gerar o projeto de testes será necessário, dentro do Visual Studio, acessar o menu File, opção New e, por fim, opção Project. Dentro da tela New Project (Figura 1) selecionar o template ASP.NET MVC 4 Web Application, preenchendo o campo Name com o nome da aplicação a ser gerada (“TestePartialViews”, neste caso); no campo Location é possível ainda definir o diretório no qual serão criados os arquivos para este projeto.
Figura 1: Figura 1: Criando um projeto ASP.NET MVC 4 para testes
Aparecerá então uma janela como a que consta na Figura 2. Deverão ser escolhidos o template para a criação do projeto (selecionar “Internet Application”), além do Engine utilizado para a geração das Views (marcar aqui a opção “Razor”).
Figura 2: Criando um projeto ASP.NET MVC 4 para testes
Criação dos tipos utilizados na manipulação de informações populacionais
Com o projeto TestePartialViews já criado, chega o momento de se proceder com a codificação das classes empregadas na manipulação de informações populacionais. As estruturas aqui criadas pertencerão à camada Model.
Primeiramente será implementada a classe Continente. Dentro do Solution Explorer será necessário clicar com o botão direito do mouse sobre a pasta Models, escolhendo em seguida no menu de atalho o item Add, opção Class. Nesse instante será exibida a tela Add New Item, com o template para a criação de classes já selecionado (Figura 3); preencher o campo Name com “Continente.cs”.
Figura 3: Criando o arquivo para implementação da classe Continente
A Listagem 1 apresenta a implementação da classe Continente. Conforme pode ser observado, este tipo é bastante simples, servindo de base para a apresentação de informações como o nome do continente, a posição no ranking que engloba as demais regiões, além do total populacional do mesmo.
Listagem 1: Classe Continente
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace TestePartialViews.Models
{
public class Continente
{
public int PosicaoRanking { get; set; }
public string Nome { get; set; }
public Int64 Populacao { get; set; }
}
}
OBSERVAÇÃO: para a criação das demais classes especificadas adiante, seguir os mesmos procedimentos utilizados na geração do tipo Continente (a fim de evitar repetições desnecessárias, estes passos serão omitidos a partir deste ponto).
Como a solução aqui elaborada se presta tão somente à realização de testes, não será necessária a criação de um banco de dados para o armazenamento e a recuperação de informações. Em virtude disto, uma classe que simulará o processo de obtenção de dados sobre continentes precisará ser implementada. A este tipo (que será estático) se dará o nome SimulacaoInformacoesContinentes (Listagem 2).
Foi declarado em SimulacaoInformacoesContinentes um método também estático e de nome ObterInformacoes, o qual devolverá como resultado de sua coleção uma lista de instâncias da classe Continente.
Listagem 2: Classe SimulacaoInformacoesContinentes
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace TestePartialViews.Models
{
public static class SimulacaoInformacoesContinentes
{
public static List<Continente> ObterInformacoes()
{
List<Continente> continentes = new List<Continente>();
Continente continente;
continente = new Continente();
continente.PosicaoRanking = 1;
continente.Nome = "Ásia";
continente.Populacao = 4164252000;
continentes.Add(continente);
continente = new Continente();
continente.PosicaoRanking = 2;
continente.Nome = "África";
continente.Populacao = 1022234000;
continentes.Add(continente);
continente = new Continente();
continente.PosicaoRanking = 3;
continente.Nome = "América";
continente.Populacao = 934611000;
continentes.Add(continente);
continente = new Continente();
continente.PosicaoRanking = 4;
continente.Nome = "Europa";
continente.Populacao = 738199000;
continentes.Add(continente);
continente = new Continente();
continente.PosicaoRanking = 5;
continente.Nome = "Oceania";
continente.Populacao = 36593000;
continentes.Add(continente);
return continentes;
}
}
}
Na Listagem 3 está a definição da classe Cidade. Este tipo será utilizado para a exibição de informações sobre as dez cidades mais populosas do mundo, considerando para isto dados como o nome e a localização da cidade, a posição da mesma neste ranking e ainda, a respectiva população estimada.
Listagem 3: Classe Cidade
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace TestePartialViews.Models
{
public class Cidade
{
public int PosicaoRanking { get; set; }
public string Nome { get; set; }
public string Pais { get; set; }
public Int64 Populacao { get; set; }
}
}
Assim como aconteceu com a geração de instâncias baseadas no tipo Continente, uma classe que retornará informações sobre as cidades mais populosas também será implementada. A Listagem 4 apresenta a implementação do tipo estático SimulacaoInformacoesCidades; a obtenção de referências do tipo Cidade se dará através da invocação do método chamado ObterInformacoes.
Listagem 4: Classe SimulacaoInformacoesCidades
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace TestePartialViews.Models
{
public static class SimulacaoInformacoesCidades
{
public static List<Cidade> ObterInformacoes()
{
List<Cidade> cidades = new List<Cidade>();
Cidade cidade;
cidade = new Cidade();
cidade.PosicaoRanking = 1;
cidade.Nome = "Xangai";
cidade.Pais = "China";
cidade.Populacao = 17836133;
cidades.Add(cidade);
cidade = new Cidade();
cidade.PosicaoRanking = 2;
cidade.Nome = "Istambul";
cidade.Pais = "Turquia";
cidade.Populacao = 13483052;
cidades.Add(cidade);
cidade = new Cidade();
cidade.PosicaoRanking = 3;
cidade.Nome = "Karachi";
cidade.Pais = "Paquistão";
cidade.Populacao = 13052000;
cidades.Add(cidade);
cidade = new Cidade();
cidade.PosicaoRanking = 4;
cidade.Nome = "Mumbai";
cidade.Pais = "Índia";
cidade.Populacao = 12478447;
cidades.Add(cidade);
cidade = new Cidade();
cidade.PosicaoRanking = 5;
cidade.Nome = "Moscou";
cidade.Pais = "Rússia";
cidade.Populacao = 11810000;
cidades.Add(cidade);
cidade = new Cidade();
cidade.PosicaoRanking = 6;
cidade.Nome = "Pequim";
cidade.Pais = "China";
cidade.Populacao = 11716000;
cidades.Add(cidade);
cidade = new Cidade();
cidade.PosicaoRanking = 7;
cidade.Nome = "São Paulo";
cidade.Pais = "Brasil";
cidade.Populacao = 11316149;
cidades.Add(cidade);
cidade = new Cidade();
cidade.PosicaoRanking = 8;
cidade.Nome = "Tianjin";
cidade.Pais = "China";
cidade.Populacao = 11090314;
cidades.Add(cidade);
cidade = new Cidade();
cidade.PosicaoRanking = 9;
cidade.Nome = "Guangzhou";
cidade.Pais = "China";
cidade.Populacao = 11070654;
cidades.Add(cidade);
cidade = new Cidade();
cidade.PosicaoRanking = 10;
cidade.Nome = "Nova Délhi";
cidade.Pais = "Índia";
cidade.Populacao = 11007835;
cidades.Add(cidade);
return cidades;
}
}
}
Implementando o Controller que irá processar as Partial Views
Com os tipos da camada Model já definidos, deve-se proceder agora com a implementação do Controller responsável pelo processamento das Partial Views contendo dados populacionais.
Um novo Controller pode ser criado por meio da janela Solution Explorer: para isto, clicar com o botão direito do mouse sobre a pasta Controllers, selecionando em seguida no menu de atalho o item Add, opção Controller. Aparecerá então a janela Add Controller; preencher o campo Controller Name com o valor "PopulacaoController" (Figura 4), enquanto em Template deverá estar marcada a opção "Empty MVC Controller.
Figura 4: Criando um novo Controller
Na Listagem 5 encontra-se o código-fonte referente à classe PopulacaoController.
Listagem 5: Classe PopulacaoController
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using TestePartialViews.Models;
namespace TestePartialViews.Controllers
{
public class PopulacaoController : Controller
{
public ActionResult ListarPopulacaoContinentes()
{
return PartialView(
SimulacaoInformacoesContinentes.ObterInformacoes());
}
public ActionResult ListarPopulacaoCidades()
{
return PartialView(
SimulacaoInformacoesCidades.ObterInformacoes());
}
}
}
Foram definidas duas Actions neste Controller:
- ListarPopulacaoContinentes: utilizada para a exibição de informações sobre a população dos diferentes continentes;
- ListarPopulacaoCidades: empregada na apresentação de dados relativos às dez cidades mais populosas do mundo.
Ambas as Actions acionam o método PartialView, fornecendo como parâmetros a este uma coleção de objetos. No caso de ListarPopulacaoContinentes, uma lista de instâncias do tipo Continente é repassada, sendo que isto é obtido a partir de uma chamada ao método ObterInformacoes da classe SimulacaoInformacoesCidades. Já a Action ListarPopulacaoCidades invoca a operação ObterInformacoes de SimulacaoInformacoesCidades, com o resultado desta instrução sendo passado como parâmetro ao método PartialView.
Implementação das Views da aplicação
Por fim, será preciso criar as Partial Views para a exibição de informações populacionais, bem como proceder com ajustes na View que conterá tais estruturas.
No caso da classe PopulacaoController, a criação da View que conterá o resultado da execução da Action ListarPopulacaoContinentes pode ser feita clicando-se com o botão direito do mouse sobre o método correspondente; no menu de atalho apresentado selecionar a opção Add View.
Com a janela “Add View” ativa, certificar-se de que o campo “View Engine” está preenchido com o valor “Razor (CSHTML)”. Marcar então a opção “Create a strongly typed-view”, selecionando em “Model class” o tipo Continente; já em “Scaffold template”, escolher o valor “List”, a fim de que seja gerada uma listagem/tabela com os diferentes registros relativos a dados dos diferentes continentes. Concluindo este processo, selecionar ainda a opção “Create as a partial view”. Na Figura 5 estão ilustrados todos esses ajustes.
Figura 5: Criação de uma Partial View
Ao se acionar o botão Add da janela Add View será criado o arquivo ListarPopulacaoContinentes.cshtml (Listagem 6). Trata-se de uma View “fortemente tipada”, ou seja, através da propriedade Model desta estrutura se tem acesso a uma coleção de objetos de um tipo específico (no caso, a classe Continente).
Listagem 6: Partial View ListarPopulacaoContinentes.cshtml
@model IEnumerable<TestePartialViews.Models.Continente>
<table>
<tr>
<th style="text-align: center; width: 80px;">
Posição
</th>
<th style="width: 120px;">
Continente
</th>
<th style="width: 100px;">
População Estimada
</th>
</tr>
@foreach (var item in Model) {
<tr>
<td style="text-align: center;">
@item.PosicaoRanking
</td>
<td>
@item.Nome
</td>
<td style="text-align: right;">
@item.Populacao.ToString("#,##0")
</td>
</tr>
}
</table>
Já a Listagem 7 exibe o código do arquivo ListarPopulacaoCidades, o qual permitirá a visualização de informações sobre as cidades mais populosas. Este elemento foi criado seguindo o mesmo procedimento empregado na geração da Partial View de Continentes, diferindo apenas pela utilização do tipo Cidade.
Listagem 7: Partial View ListarPopulacaoCidades.cshtml
@model IEnumerable<TestePartialViews.Models.Cidade>
<table>
<tr>
<th style="text-align: center; width: 80px;">
Posição
</th>
<th style="width: 120px;">
Nome
</th>
<th style="width: 120px;">
País
</th>
<th style="width: 100px;">
População Estimada
</th>
</tr>
@foreach (var item in Model) {
<tr>
<td style="text-align: center;">
@item.PosicaoRanking
</td>
<td>
@item.Nome
</td>
<td>
@item.Pais
</td>
<td style="text-align: right;">
@item.Populacao.ToString("#,##0")
</td>
</tr>
}
</table>
Ajustes precisarão ser realizados agora na View Index (Listagem 8), que está vinculada à Action de mesmo nome na classe HomeController (este Controller é gerado por default ao se utilizar o template “Internet Application”). Essa estrutura será exibida ao se executar a aplicação por meio do Visual Studio.
Ao ser visualizada, a ideia é que a View Index produza como resultado um documento HTML que englobe o conteúdo do processamento
das Partial Views ListarPopulacaoContinentes e ListarPopulacaoCidades. Para que isto seja possível, o método Action do objeto Html foi acionado duas vezes no código-fonte do arquivo Index.cshtml, recebendo como parâmetros:
- O nome da Action que será executada;
- O Controller ao qual pertence a Action em questão;
- Prováveis parâmetros necessários à execução da Action. Normalmente, é repassado como parâmetro um array de objetos contendo os dados esperados, muito embora no exemplo citado isto não tenha sido necessário (tanto que se informou o valor null ao método Action).
Listagem 8: View Index.cshtml
@section featured {
<section class="featured">
<div class="content-wrapper">
<hgroup class="title">
<h1>Informações Populacionais - 2012</h1>
</hgroup>
</div>
</section>
}
<h3>Dados sobre a População Mundial - Ano de Referência: 2012</h3>
<ol class="round">
<li class="one">
<h5>População por Continente</h5>
@Html.Action(
"ListarPopulacaoContinentes",
"Populacao",
null)
</li>
<li class="two">
<h5>Listagem das 10 Cidades mais Populosas do Mundo</h5>
@Html.Action(
"ListarPopulacaoCidades",
"Populacao",
null)
</li>
</ol>
A escolha pelo método Action do objeto Html se deve ao fato das Partial Views estarem ligadas a outro Controller (classe PopulacaoController). Se essas estruturas pertencessem a HomeController, o acesso às mesmas dentro da View Index poderia ser feito por meio dos seguintes métodos de Html:
- Partial: gera uma string em que consta o resultado do processamento da Partial View;
- RenderPartial: bastante similar à operação Partial, diferindo desta apenas pelo fato de que não será produzido um valor de retorno, com o resultado da execução da Partial View sendo escrito diretamente no conteúdo da View principal.
Executando a aplicação de testes
Iniciando a execução da aplicação criada neste artigo, será exibida uma tela como a que consta na Figura 6. Conforme já mencionado anteriormente, por default é acionada a View Index, a qual é parte integrante do Controller de nome Home.
Figura 6: Aplicação TestePartialViews em execução
Acionando a barra de rolagem do browser, será possível perceber que a View Index apresenta em seu conteúdo o resultado do processamento dos arquivos ListarPopulacaoContinentes.cshtml e ListarPopulacaoCidades.cshtml (Figura 7).
Figura 7: conteúdo de duas Partial Views numa mesma página HTML
Conclusão
Procurei com este artigo demonstrar uma dúvida que costuma ser bastante comum, sobretudo por parte daqueles que ainda estão se familiarizando com a tecnologia ASP.NET MVC.
Além de aumentar o potencial de reutilização em soluções deste tipo, Partial Views também podem ser usadas de outras maneiras. Um bom exemplo disto consiste na combinação dessas estruturas gerando uma View mais complexa, em que são exibidas informações de várias fontes (com cada uma destas correspondendo ao resultado do processamento de uma Action diferente). Espero que este conteúdo possa ser útil no seu dia a dia. Até uma próxima oportunida