ASP.Net MVC – View Model Pattern – Quando e como utilizar?

Postado em by

 No desenvolvimento em ASP.Net utilizando o framework MVC é muito comum o uso do pattern View Model, esse pattern proporciona uma melhor organização do código e gestão dos dados utilizados na View, confira em quais situações ele é utilizável e algumas maneiras de como aplicá-lo.

A necessidade da utilização do pattern View Model surge na maioria dos projetos ASP.Net MVC, para os iniciantes costuma causar alguma confusão, porém é muito útil e poupa um bom trabalho.

 O conceito de View Model não limita-se apenas para o ASP.Net MVC, você poderá encontrar referências sobre View Model para padrões MVC, MVP e MVVM, que por sua vez é implementado em tecnologias como ASP.Net, Silverlight e WPF.

 Este artigo é dedicado para o entendimento do padrão View Model utilizando ASP.Net MVC.

 O que é um ASP.Net MVC View Model?

 No ASP.Net MVC os View Models nos permitem modelar várias entidades a partir de um ou mais modelos em um único objeto, eu gosto de usar como exemplo a comparação de View Models com uma DTO, pois ambas são soluções que foram projetadas para centralizar um conjunto de dados de diversas fontes assim evitando a necessidade de realizar várias chamadas para se obter todos os dados necessários e evitar a necessidade de alterar um modelo de domínio para realizar o transporte de algum dado específico.

 Resumindo, um View Model representa um conjunto de uma ou mais Models e outros dados que serão representados em uma View que necessita exibir determinado conjunto de informações. A imagem abaixo ilustra o conceito de um View Model:

ASP.Net MVC View Model Pattern

 Utilizando uma View Model dedicada contendo a Model de domínio

Imagine que estamos desenvolvendo uma aplicação web de uma loja virtual onde possuímos a classe Produto:

1 public class Produto
2 {
3     public string Nome { get; set; }
4     public decimal Valor { get; set; }
5 }

 Porém na View de carrinho de compras além das informações contidas na classe Produto é necessário exibir uma mensagem e o valor total do carrinho para vários produtos. O que fazer? Modificar a classe Produtos para conter essas informações?

 Modificar a classe Produto não seria uma boa alternativa, afinal esses dados adicionais não fazem sentido pertencerem a entidade Produto, são dados pertinentes a View de carrinho de compras.

 É nesse momento que o pattern View Model entra em ação para resolver esse problema de design. Criaremos então uma classe que irá prover dados para esta View e essa classe será uma View Model de carrinho de compras.

1 public class CarrinhoComprasViewModel
2 {
3     public IEnumerable Produtos { get; set; }
4     public decimal TotalCarrinho { get; set; }
5     public string Mensagem { get; set; }
6 }

 Podemos observar que esta View Model possui um IEnumerable de Produtos para uma lista de produtos e mais os dados de valor e mensagem que irão ser exibidos na View.
Não é um tipo de classe especial, é uma classe como qualquer outra Model, porém escrita especificamente para atender a uma View.

 Confira o código da Controller de carrinho de compras.

1 public class CarrinhoComprasController : Controller
2 {
3     public ActionResult Index()
4     {
5
6         // Criando uma lista de produtos fake para exibição na View
7         var produtos = new List<Produto>();
8         for (int i = 0; i < 10; i++)
9         {
10             produtos.Add(new Produto
11                             { Nome = "Produto " + i, Valor = 1.13M * i }
12                         );
13         }
14
15         // Populando a model para exibição na View
16         var model = new CarrinhoComprasViewModel
17         {
18             Produtos = produtos,
19             TotalCarrinho = produtos.Sum(p => p.Valor),
20             Mensagem = "Obrigado por comprar conosco!"
21         };
22
23         return View(model);
24     }
25
26 }

E por fim a View de carrinho de compras

1 @model MeuExemploMVC.Models.CarrinhoComprasViewModel
2
3 @{
4     ViewBag.Title = "Carrinho de Compras";
5 }
6
7 <h2>@Model.Mensagem
8 </h2>
9 <fieldset>
10     <legend>Carrinho de Compras</legend>
11
12     <table>
13         <caption>Produtos no Carrinho</caption>
14         <thead>
15         <tr>
16             <th>Produto</th>
17             <th>Valor</th>
18         </tr>
19         </thead>
20         <tbody>
21         @foreach (var produto in Model.Produtos) {
22             <tr>
23                 <td>@produto.Nome</td>
24                 <td>@produto.Valor</td>
25             </tr>
26         }
27         </tbody>
28         <tfoot>
29             <tr>
30                 <td><strong>Total</strong></td>
31                 <td>@Model.TotalCarrinho</td>
32             </tr>
33         </tfoot>
34     </table>
35
36 </fieldset>

O pattern de View Model está aplicado e não será mais necessário modificar a Model de Produto para adequar a View.

O arquivo físico de uma View Model pode estar em diferentes lugares, sendo:

  • Em uma pasta chamada ViewModels na estrutura raiz do projeto MVC (aplicações pequenas)
  • Uma *.dll referenciada no projeto MVC (aplicações de qualquer tamanho)
  • Em projetos separados (como uma camada de serviços) para gerar dados específicos (aplicações grandes)

 Utilizando AutoMapper para realizar o mapeamento de uma Model e suas variantes

Uma outra forma de utilizar View Models seria criando um mapeamento entre a Model entidade de domínio e a View Model que será exibida na View.

Os autores do livro ASP.Net MVC 4 in Action defendem fortemente a utilização de mapeamento entre as Models e suas possíveis variantes.

 Com base no exemplo acima, a classe Produto poderia ter uma variante chamada ProdutoViewModel, qual possuiria os mesmos atributos de Produto entre outros mais.

 O mapeamento entre essas duas Models seria feito através da ferramenta AutoMapper.
Este é um processo mais complexo e será abordado em meu post exclusivo sobre utilização do AutoMapper.

Benefícios de usar uma View Model

  • Não precisar alterar uma classe Model para atender as necessidades de uma View.
  • Poder agrupar informações de uma ou mais Models em uma única classe, poupando a necessidade de realizar N consultas.
  • Um dado não contido em uma Model de domínio pode ser facilmente transportado através de uma View Model.
  • Mudanças são muito mais fáceis de se realizar e sem afetar a Model do domínio.
  • Não é necessário “poluir” as Models de domínio com DataAnnotations de validação de formulário, pois estas podem estar contidas diretamente na View Model.

Resumo

 O uso de View Models é muito recomendado e irá ajudar a organizar e gerenciar os dados a serem transportados e exibidos, proporcionando flexibilidade para montar conjuntos de dados compatíveis com as necessidades da View.

 No MVC existe o conceito de separação de responsabilidades onde “M” (Model) é considerada a menos importante, pois nem sempre a Model estará presente no projeto MVC e sim numa camada de domínio que irá prover estas classes. A Model do MVC está voltada ao uso na View, portanto algumas técnicas são necessárias para separar e mapear Models de entidades de domínio para Models do projeto MVC.

Referências

 

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *