Compartilhar via


Parte 3: Exibições e ViewModels

por Jon Galloway

O MVC Music Store é um aplicativo de tutorial que apresenta e explica passo a passo como usar ASP.NET MVC e Visual Studio para desenvolvimento na Web.

A MVC Music Store é uma implementação leve de loja de exemplo que vende álbuns de música online e implementa a administração básica do site, a entrada do usuário e a funcionalidade do carrinho de compras.

Esta série de tutoriais detalha todas as etapas executadas para criar o aplicativo de exemplo ASP.NET MVC Music Store. A parte 3 abrange Exibições e ViewModels.

Até agora, acabamos de retornar cadeias de caracteres de ações do controlador. Essa é uma boa maneira de ter uma ideia de como os controladores funcionam, mas não é assim que você deseja criar um aplicativo Web real. Vamos querer uma maneira melhor de gerar HTML de volta para navegadores que visitam nosso site – uma em que podemos usar arquivos de modelo para personalizar com mais facilidade o envio de conteúdo HTML de volta. É exatamente isso que o Views faz.

Adicionando um modelo de exibição

Para usar um modelo de exibição, alteraremos o método HomeController Index para retornar um ActionResult e fazer com que ele retorne View(), como abaixo:

public class HomeController : Controller
{
    //
    // GET: /Home/
    public ActionResult Index()
    {
        return View();
    }
}

A alteração acima indica que, em vez de retornar uma cadeia de caracteres, queremos usar uma "Exibição" para gerar um resultado de volta.

Agora, adicionaremos um modelo de Exibição apropriado ao nosso projeto. Para fazer isso, posicionaremos o cursor de texto dentro do método de ação Índice e, em seguida, clicaremos com o botão direito do mouse e selecionaremos "Adicionar Exibição". Isso abrirá a caixa de diálogo Adicionar Exibição:

Captura de tela do menu que mostra a seleção adicionar exibição.Captura de tela da caixa de diálogo adicionar exibição, com opções de menu para selecionar e adicionar sua exibição.

A caixa de diálogo "Adicionar Exibição" nos permite gerar arquivos de modelo de exibição de forma rápida e fácil. Por padrão, a caixa de diálogo "Adicionar Exibição" preenche previamente o nome do modelo De exibição a ser criado para que ele corresponda ao método de ação que o usará. Como usamos o menu de contexto "Adicionar Exibição" dentro do método de ação Index() de nosso HomeController, a caixa de diálogo "Adicionar Exibição" acima tem "Index" como o nome de exibição pré-preenchido por padrão. Não precisamos alterar nenhuma das opções nessa caixa de diálogo, portanto, clique no botão Adicionar.

Quando clicarmos no botão Adicionar, o Desenvolvedor do Visual Web criará um novo modelo de exibição Index.cshtml para nós no diretório \Views\Home, criando a pasta se ainda não existir.

Captura de tela do menu suspenso Gerenciador de Soluções, mostrando os diferentes arquivos na M V C Music Store.

O nome e o local da pasta do arquivo "Index.cshtml" é importante e segue o padrão ASP.NET convenções de nomenclatura do MVC. O nome do diretório, \Views\Home, corresponde ao controlador , que é chamado de HomeController. O nome do modelo de exibição, Index, corresponde ao método de ação do controlador que exibirá a exibição.

ASP.NET MVC nos permite evitar a necessidade de especificar explicitamente o nome ou o local de um modelo de exibição quando usamos essa convenção de nomenclatura para retornar uma exibição. Por padrão, ele renderizará o modelo de exibição \Views\Home\Index.cshtml quando escrevermos código como abaixo em nosso HomeController:

public class HomeController : Controller
{
    //
    // GET: /Home/
    public ActionResult Index()
    {
        return View();
    }
}

O Visual Web Developer criou e abriu o modelo de exibição "Index.cshtml" depois que clicamos no botão "Adicionar" na caixa de diálogo "Adicionar Exibição". O conteúdo de Index.cshtml é mostrado abaixo.

@{
    ViewBag.Title = "Index";
}
<h2>Index</h2>

Essa exibição está usando a sintaxe Razor, que é mais concisa do que o mecanismo de exibição Web Forms usado em ASP.NET Web Forms e versões anteriores do ASP.NET MVC. O mecanismo de exibição Web Forms ainda está disponível no ASP.NET MVC 3, mas muitos desenvolvedores acham que o mecanismo de exibição razor se encaixa ASP.NET desenvolvimento de MVC muito bem.

As três primeiras linhas definem o título da página usando ViewBag.Title. Veremos como isso funciona mais detalhadamente em breve, mas primeiro vamos atualizar o texto do título de texto e exibir a página. Atualize a <marca h2> para dizer "Esta é a Home Page", conforme mostrado abaixo.

@{
    ViewBag.Title = "Index";
}
<h2>This is the Home Page</h2>

A execução do aplicativo mostra que nosso novo texto está visível na home page.

Captura de tela da home page do navegador da loja de música, mostrando o texto

Usando um layout para elementos comuns do site

A maioria dos sites tem conteúdo que é compartilhado entre muitas páginas: navegação, rodapés, imagens de logotipo, referências de folha de estilos etc. O mecanismo de exibição razor facilita o gerenciamento usando uma página chamada _Layout.cshtml que foi criada automaticamente para nós dentro da pasta /Views/Shared.

Captura de tela do menu de arquivo suspenso da Loja de Música, mostrando o caminho do arquivo para a pasta compartilhada localizada dentro da pasta de exibição.

Clique duas vezes nessa pasta para exibir o conteúdo, que são mostrados abaixo.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>@ViewBag.Title</title>
    <link href="@Url.Content("~/Content/Site.css")"
rel="stylesheet" type="text/css" />
    <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")"     
            type="text/javascript"></script> 
    <script src="@Url.Content("~/Scripts/modernizr-1.7.min.js")"
            type="text/javascript"></script>
</head>
<body>
    @RenderBody()
</body>
</html>

O conteúdo de nossos modos de exibição individuais será exibido pelo @RenderBody() comando e qualquer conteúdo comum que queremos que apareça fora dele pode ser adicionado à marcação _Layout.cshtml. Queremos que nossa MVC Music Store tenha um cabeçalho comum com links para nossa home page e área da Loja em todas as páginas do site, portanto, adicionaremos isso ao modelo diretamente acima dessa @RenderBody() instrução.

<!DOCTYPE html>
<html>
<head>
    <title>@ViewBag.Title</title>
    <link href="@Url.Content("~/Content/Site.css")"
rel="stylesheet" type="text/css" />
    <script src="@Url.Content("~/Scripts/jquery-1.4.4.min.js")"
type="text/javascript"></script>
</head>
<body>
    <div id="header">
        <h1>
            ASP.NET MVC MUSIC STORE</h1>
        <ul id="navlist">
            <li class="first"><a href="/"
id="current">Home</a></li>
            <li><a
href="/Store/">Store</a></li>
        </ul>
    </div>
    @RenderBody()
</body>
</html>

Atualizando o StyleSheet

O modelo de projeto vazio inclui um arquivo CSS muito simplificado que inclui apenas estilos usados para exibir mensagens de validação. Nosso designer forneceu alguns CSS adicionais e imagens para definir a aparência do nosso site, portanto, vamos adicioná-los agora.

O arquivo CSS atualizado e as Imagens estão incluídos no diretório Conteúdo do MvcMusicStore-Assets.zip que está disponível no MVC-Music-Store. Selecionaremos ambos no Windows Explorer e os soltaremos em nossa pasta Conteúdo da Solução no Desenvolvedor Web Visual, conforme mostrado abaixo:

Captura de tela lado a lado do diretório de conteúdo e do menu suspenso da Music Store, mostrando o caminho do arquivo para a pasta de imagens na pasta de conteúdo.

Você será solicitado a confirmar se deseja substituir o arquivo Site.css existente. Clique em Sim.

Captura de tela da caixa pop-up de aviso exibida, solicitando que confirme a ação de substituição perguntando se você deseja substituir o arquivo existente.

A pasta Conteúdo do aplicativo agora aparecerá da seguinte maneira:

Captura de tela do repositório de música, menu suspenso, realçando a pasta de conteúdo, mostrando a nova pasta de imagem com a lista de imagens abaixo.

Agora, vamos executar o aplicativo e ver como estão nossas alterações na Página Inicial.

Captura de tela da home page da janela do navegador da loja de música, com a imagem selecionada, juntamente com as palavras

  • Vamos examinar o que mudou: o método de ação Índice do HomeController encontrou e exibiu o modelo \Views\Home\Index.cshtmlView, mesmo que nosso código chamado "modo de exibição de retorno()", porque nosso modelo view seguiu a convenção de nomenclatura padrão.
  • A Home Page está exibindo uma mensagem de boas-vindas simples definida no modelo de exibição \Views\Home\Index.cshtml.
  • A Home Page está usando nosso modelo _Layout.cshtml e, portanto, a mensagem de boas-vindas está contida no layout HTML do site padrão.

Usando um modelo para passar informações para nossa exibição

Um modelo de exibição que apenas exibe HTML codificado não criará um site muito interessante. Para criar um site dinâmico, queremos passar informações de nossas ações do controlador para nossos modelos de exibição.

No padrão Model-View-Controller, o termo Modelo refere-se a objetos que representam os dados no aplicativo. Muitas vezes, os objetos de modelo correspondem a tabelas no banco de dados, mas não precisam.

Métodos de ação do controlador que retornam um ActionResult podem passar um objeto de modelo para a exibição. Isso permite que um Controlador empacote de forma limpa todas as informações necessárias para gerar uma resposta e, em seguida, passe essas informações para um modelo de exibição a ser usado para gerar a resposta HTML apropriada. Isso é mais fácil de entender vendo-o em ação, então vamos começar.

Primeiro, criaremos algumas classes de modelo para representar Gêneros e Álbuns em nossa loja. Vamos começar criando uma classe De gênero. Clique com o botão direito do mouse na pasta "Modelos" em seu projeto, escolha a opção "Adicionar Classe" e nomeie o arquivo "Genre.cs".

Captura de tela de três caixas de menu lado a lado, mostrando as direções do caminho do arquivo, da direita para a esquerda, até a seleção de classe

Captura de tela das opções de menu adicionar novo item, exibindo três menus selecionando um modelo, estilo de classificação e tipo; em seguida, a barra de campo de nome na parte inferior.

Em seguida, adicione uma propriedade Name de cadeia de caracteres pública à classe que foi criada:

public class Genre
{
    public string Name { get; set; }
}

Observação: caso esteja se perguntando, a notação { get; set; } está fazendo uso do recurso de propriedades autoimplementadas do C#. Isso nos dá os benefícios de uma propriedade sem exigir que declaremos um campo de apoio.

Em seguida, siga as mesmas etapas para criar uma classe Album (chamada Album.cs) que tenha uma propriedade Title e Genre:

public class Album
{
    public string Title { get; set; }
    public Genre Genre { get; set; }
}

Agora podemos modificar o StoreController para usar Exibições que exibem informações dinâmicas do nosso Modelo. Se , para fins de demonstração agora , nomeássemos nossos Álbuns com base na ID da solicitação, poderíamos exibir essas informações como na exibição abaixo.

Captura de tela da home page no navegador, com o logotipo da imagem, o nome do álbum atual e botões de página inicial e armazenamento clicáveis no canto superior direito.

Começaremos alterando a ação Detalhes da Loja para que ela mostre as informações de um único álbum. Adicione uma instrução "using" à parte superior da classe StoreControllers para incluir o namespace MvcMusicStore.Models, portanto, não precisamos digitar MvcMusicStore.Models.Album sempre que quisermos usar a classe de álbum. A seção "usings" dessa classe agora deve aparecer como abaixo.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MvcMusicStore.Models;

Em seguida, atualizaremos a ação Controlador de detalhes para que ela retorne um ActionResult em vez de uma cadeia de caracteres, como fizemos com o método Index do HomeController.

public ActionResult Details(int id)

Agora podemos modificar a lógica para retornar um objeto Album à exibição. Posteriormente neste tutorial, recuperaremos os dados de um banco de dados, mas, por enquanto, usaremos "dados fictícios" para começar.

public ActionResult Details(int id)
 {
    var album = new Album { Title = "Album " + id };
    return View(album);
 }

Observação: se você não estiver familiarizado com C#, pode presumir que usar var significa que nossa variável de álbum está associada tardiamente. Isso não está correto – o compilador C# está usando a inferência de tipo com base no que estamos atribuindo à variável para determinar que o álbum é do tipo Álbum e compilar a variável de álbum local como um tipo de álbum, portanto, obtemos verificação em tempo de compilação e suporte ao editor de código do Visual Studio.

Agora vamos criar um modelo de exibição que usa nosso Álbum para gerar uma resposta HTML. Antes de fazermos isso, precisamos criar o projeto para que a caixa de diálogo Adicionar Exibição saiba sobre nossa classe de Álbum recém-criada. Você pode criar o projeto selecionando o item de menu Depurar⇨Criar MvcMusicStore (para crédito extra, você pode usar o atalho Ctrl-Shift-B para compilar o projeto).

Captura de tela do editor de documentos da loja de música, com a guia 'build' selecionada no menu suspenso, realçando a opção 'build M V C music store.

Agora que configuramos nossas classes de suporte, estamos prontos para criar nosso modelo de Exibição. Clique com o botão direito do mouse no método Detalhes e selecione "Adicionar Exibição..." no menu de contexto.

Captura de tela do menu exibir modelo, exibindo um snippet de código e realçando a opção

Vamos criar um novo modelo de Exibição como fizemos antes com o HomeController. Como o estamos criando do StoreController, por padrão, ele será gerado em um arquivo \Views\Store\Index.cshtml.

Ao contrário de antes, vamos marcar caixa de seleção "Criar um modo de exibição fortemente tipado". Em seguida, selecionaremos nossa classe "Álbum" na lista suspensa "Exibir classe de dados". Isso fará com que a caixa de diálogo "Adicionar Exibição" crie um modelo de Exibição que espera que um objeto Album seja passado para ele a ser usado.

Captura de tela da janela do menu Adicionar exibição, mostrando a caixa de seleção clicável

Quando clicarmos no botão "Adicionar", nosso modelo de exibição \Views\Store\Details.cshtml será criado, contendo o código a seguir.

@model MvcMusicStore.Models.Album
@{
    ViewBag.Title = "Details";
}
<h2>Details</h2>

Observe a primeira linha, que indica que essa exibição é fortemente tipada para nossa classe Album. O mecanismo de exibição razor entende que ele foi passado por um objeto Album, para que possamos acessar facilmente as propriedades do modelo e até mesmo ter o benefício do IntelliSense no editor do Visual Web Developer.

Atualize a <marca h2> para que ela exiba a propriedade Título do Álbum modificando essa linha para aparecer da seguinte maneira.

<h2>Album: @Model.Title</h2>

Observe que o IntelliSense é disparado quando você entra no período após o @Model palavra-chave, mostrando as propriedades e os métodos aos quais a classe Album dá suporte.

Agora vamos executar novamente nosso projeto e visitar a URL /Store/Details/5. Veremos detalhes de um Álbum, como abaixo.

Captura de tela da janela do navegador da home page, com o logotipo da imagem no canto superior esquerdo e o nome do álbum sob ela.

Agora, faremos uma atualização semelhante para o método de ação Procurar na Loja. Atualize o método para que ele retorne um ActionResult e modifique a lógica do método para que ele crie um novo objeto Genre e o retorne ao View.

public ActionResult Browse(string genre)
 {
    var genreModel = new Genre { Name = genre };
    return View(genreModel);
 }

Clique com o botão direito do mouse no método Browse e selecione "Adicionar Exibição..." no menu de contexto, adicione um Modo de Exibição fortemente tipado e adicione um fortemente tipado à classe Genre.

Captura de tela do menu de contexto, que mostra a opção

Atualize o <elemento h2> no código de exibição (em /Views/Store/Browse.cshtml) para exibir as informações de Gênero.

@model MvcMusicStore.Models.Genre
@{
    ViewBag.Title = "Browse";
}
<h2>Browsing Genre: @Model.Name</h2>

Agora vamos executar novamente nosso projeto e navegar até /Store/Procurar? Genre=Disco URL. Veremos a página Procurar exibida como abaixo.

Captura de tela da janela da home page do navegador, exibindo a mensagem

Por fim, vamos fazer uma atualização um pouco mais complexa para o método de ação Índice da Loja e exibir para exibir uma lista de todos os Gêneros em nossa loja. Faremos isso usando uma Lista de Gêneros como nosso objeto modelo, em vez de apenas um único Gênero.

public ActionResult Index()
{
    var genres = new List<Genre>
    {
        new Genre { Name = "Disco"},
        new Genre { Name = "Jazz"},
        new Genre { Name = "Rock"}
    };
    return View(genres);
 }

Clique com o botão direito do mouse no método de ação Índice da Loja e selecione Adicionar Exibição como antes, selecione Gênero como a classe Modelo e pressione o botão Adicionar.

Captura de tela do menu da janela 'adicionar exibição', mostrando a seleção de classe de modelo em uma caixa vermelha e, em seguida, o botão Adicionar abaixo.

Primeiro, alteraremos a @model declaração para indicar que a exibição estará esperando vários objetos Genre em vez de apenas um. Altere a primeira linha de /Store/Index.cshtml para ler da seguinte maneira:

@model IEnumerable<MvcMusicStore.Models.Genre>

Isso informa ao mecanismo de exibição razor que ele trabalhará com um objeto de modelo que pode conter vários objetos Genre. Estamos usando um Gênero IEnumerable<em vez de um Gênero> de Lista<, pois ele é mais genérico, permitindo que alteremos nosso tipo de modelo posteriormente para qualquer tipo de objeto que dê suporte à interface IEnumerable.>

Em seguida, vamos percorrer os objetos Genre no modelo, conforme mostrado no código de exibição concluído abaixo.

@model IEnumerable<MvcMusicStore.Models.Genre>
@{
    ViewBag.Title = "Store";
}
<h3>Browse Genres</h3>
<p>
    Select from @Model.Count()
genres:</p>
<ul>
    @foreach (var genre in Model)
    {
        <li>@genre.Name</li>
    }
</ul>

Observe que temos suporte completo do IntelliSense à medida que inserimos esse código, para que quando digitamos "@Model". Vemos todos os métodos e propriedades compatíveis com um IEnumerable do tipo Genre.

Captura de tela do snippet de código H TML, com uma barra de menus sobre ele, selecionando o comando 'count <>'.

Em nosso loop "foreach", o Visual Web Developer sabe que cada item é do tipo Gênero, portanto, vemos o IntelliSense para cada tipo de Gênero.

Captura de tela do código 'loop foreach', com uma janela de menu suspensa e a opção 'name' selecionada com 'string Genre dot name' aparecendo ao lado dele.

Em seguida, o recurso de scaffolding examinou o objeto Genre e determinou que cada um terá uma propriedade Name, para que ele faça um loop e os grave. Ele também gera links editar, detalhes e excluir para cada item individual. Vamos aproveitar isso mais tarde em nosso gerente de loja, mas por enquanto gostaríamos de ter uma lista simples em vez disso.

Quando executamos o aplicativo e navegamos até /Store, vemos que a contagem e a lista de Gêneros são exibidas.

Captura de tela da janela do navegador mostrando o título 'procurar gênero', depois uma mensagem, solicitando uma seleção de gênero, seguida pelos títulos abaixo dela.

Nossa URL da /Store que lista gêneros atualmente lista os nomes de Gênero simplesmente como texto sem formatação. Vamos alterar isso para que, em vez de texto sem formatação, tenhamos os nomes de gênero vinculados à URL apropriada /Store/Browse, para que clicar em um gênero musical como "Disco" navegue até a URL /Store/Browse?genre=Disco. Podemos atualizar nosso modelo de exibição \Views\Store\Index.cshtml para gerar esses links usando código como abaixo (não digite isso – vamos melhorar isso):

<ul>
    @foreach (var genre in Model)
    {
        <li><a href="/Store/Browse?genre=@genre.Name">@genre.Name</a></li>
    }
</ul>

Isso funciona, mas pode causar problemas mais tarde, pois depende de uma cadeia de caracteres codificada. Por exemplo, se quiséssemos renomear o Controlador, precisaríamos pesquisar nosso código procurando links que precisam ser atualizados.

Uma abordagem alternativa que podemos usar é aproveitar um método auxiliar HTML. ASP.NET MVC inclui métodos auxiliares HTML que estão disponíveis em nosso código de modelo de exibição para executar uma variedade de tarefas comuns assim. O método auxiliar Html.ActionLink() é particularmente útil e facilita a criação de links> HTML <e cuida de detalhes irritantes, como garantir que os caminhos de URL sejam codificados corretamente em URL.

Html.ActionLink() tem várias sobrecargas diferentes para permitir a especificação do máximo de informações necessárias para seus links. No caso mais simples, você fornecerá apenas o texto do link e o método Action para acessar quando o hiperlink for clicado no cliente. Por exemplo, podemos vincular ao método "/Store/" Index() na página Detalhes da Loja com o texto do link "Ir para o Índice da Loja" usando a seguinte chamada:

@Html.ActionLink("Go
to the Store Index", "Index")

Observação: nesse caso, não precisamos especificar o nome do controlador porque estamos apenas vinculando a outra ação dentro do mesmo controlador que está renderizando a exibição atual.

No entanto, nossos links para a página Procurar precisarão passar um parâmetro, portanto, usaremos outra sobrecarga do método Html.ActionLink que usa três parâmetros:

    1. Texto do link, que exibirá o nome do gênero
    1. Nome da ação do controlador (Procurar)
    1. Valores de parâmetro de rota, especificando o nome (Gênero) e o valor (Nome do gênero)

Juntando tudo isso, veja como escreveremos esses links para a exibição Índice do Repositório:

<ul>
    @foreach (var genre in Model)
    {
        <li>@Html.ActionLink(genre.Name,
"Browse", new { genre = genre.Name })</li>
    }
</ul>

Agora, quando executarmos nosso projeto novamente e acessarmos a URL /Store/, veremos uma lista de gêneros. Cada gênero é um hiperlink – quando clicado, ele nos levará à URL /Store/Browse?genre=[gênero] .

Captura de tela da janela do navegador mostrando o título Procurar Gênero, com a mensagem 'selecionar entre três gêneros' seguida por três seleções de gênero com marcadores.

O HTML para a lista de gêneros tem esta aparência:

<ul>
    <li><a href="/Store/Browse?genre=Disco">Disco</a>
</li>
    <li><a href="/Store/Browse?genre=Jazz">Jazz</a>
</li>
    <li><a href="/Store/Browse?genre=Rock">Rock</a>
</li>
</ul>