O que é o ViewModel no MVC?


429

Eu sou novo no ASP.NET MVC. Estou com um problema para entender o objetivo de um ViewModel.

O que é um ViewModel e por que precisamos de um ViewModel para um aplicativo ASP.NET MVC?

Se eu der um bom exemplo sobre o seu funcionamento e explicação, seria melhor.


4
Esta postagem é o que você procura - "O que é um ASP.NET MVC ViewModel?"
precisa

6
Este artigo parece ótimo: rachelappel.com/…
Andrew

possível duplicata do MVC, o que é um ViewModel?
Rogerdeuce

Respostas:


607

A view modelrepresenta os dados que você deseja exibir em sua exibição / página, seja para texto estático ou para valores de entrada (como caixas de texto e listas suspensas) que podem ser adicionados ao banco de dados (ou editados). É algo diferente do seu domain model. É um modelo para a vista.

Digamos que você tenha uma Employeeclasse que represente o modelo de domínio do funcionário e que contenha as seguintes propriedades (identificador exclusivo, nome, sobrenome e data de criação):

public class Employee : IEntity
{
     public int Id { get; set; }

     public string FirstName { get; set; }

     public string LastName { get; set; }

     public DateTime DateCreated { get; set; }
}

Os modelos de exibição diferem dos modelos de domínio, pois os modelos de exibição contêm apenas os dados (representados pelas propriedades) que você deseja usar na exibição. Por exemplo, digamos que você queira adicionar um novo registro de funcionário, seu modelo de exibição pode ficar assim:

public class CreateEmployeeViewModel
{
     public string FirstName { get; set; }

     public string LastName { get; set; }
}

Como você pode ver, ele contém apenas duas das propriedades. Essas duas propriedades também estão no modelo de domínio do funcionário. Por que isso você pode perguntar? Idpode não ser definido a partir da visualização, pode ser gerado automaticamente pela tabela Employee. E DateCreatedtambém pode ser definido no procedimento armazenado ou na camada de serviço do seu aplicativo. Portanto, Ide DateCreatednão é necessário no modelo de exibição. Você pode exibir essas duas propriedades ao exibir os detalhes de um funcionário (um funcionário que já foi capturado) como texto estático.

Ao carregar a visualização / página, o método de ação de criação no controlador de funcionário criará uma instância desse modelo de visualização, preencherá todos os campos, se necessário, e passará esse modelo de visualização para a visualização / página:

public class EmployeeController : Controller
{
     private readonly IEmployeeService employeeService;

     public EmployeeController(IEmployeeService employeeService)
     {
          this.employeeService = employeeService;
     }

     public ActionResult Create()
     {
          CreateEmployeeViewModel model = new CreateEmployeeViewModel();

          return View(model);
     }

     public ActionResult Create(CreateEmployeeViewModel model)
     {
          // Do what ever needs to be done before adding the employee to the database
     }
}

Sua visualização / página pode ficar assim (supondo que você esteja usando ASP.NET MVCe o Razormecanismo de visualização):

@model MyProject.Web.ViewModels.CreateEmployeeViewModel

<table>
     <tr>
          <td><b>First Name:</b></td>
          <td>@Html.TextBoxFor(m => m.FirstName, new { maxlength = "50", size = "50" })
              @Html.ValidationMessageFor(m => m.FirstName)
          </td>
     </tr>
     <tr>
          <td><b>Last Name:</b></td>
          <td>@Html.TextBoxFor(m => m.LastName, new { maxlength = "50", size = "50" })
              @Html.ValidationMessageFor(m => m.LastName)
          </td>
     </tr>
</table>

A validação seria feita apenas em FirstNamee LastName. Usando o FluentValidation, você pode ter uma validação como esta:

public class CreateEmployeeViewModelValidator : AbstractValidator<CreateEmployeeViewModel>
{
     public CreateEmployeeViewModelValidator()
     {
          RuleFor(m => m.FirstName)
               .NotEmpty()
               .WithMessage("First name required")
               .Length(1, 50)
               .WithMessage("First name must not be greater than 50 characters");

          RuleFor(m => m.LastName)
               .NotEmpty()
               .WithMessage("Last name required")
               .Length(1, 50)
               .WithMessage("Last name must not be greater than 50 characters");
     }
}

E com as Anotações de dados, pode parecer o seguinte:

public class CreateEmployeeViewModel : ViewModelBase
{
    [Display(Name = "First Name")]
    [Required(ErrorMessage = "First name required")]
    public string FirstName { get; set; }

    [Display(Name = "Last Name")]
    [Required(ErrorMessage = "Last name required")]
    public string LastName { get; set; }
}

O principal a lembrar é que o modelo de visualização representa apenas os dados que você deseja usar , nada mais. Você pode imaginar todo o código e validação desnecessários se tiver um modelo de domínio com 30 propriedades e desejar atualizar apenas um único valor. Dado esse cenário, você só teria esse valor / propriedade no modelo de exibição e nem todas as propriedades que estão no objeto de domínio.

Um modelo de visualização pode não ter apenas dados de uma tabela do banco de dados. Pode combinar dados de outra tabela. Veja o meu exemplo acima sobre como adicionar um novo registro de funcionário. Além de adicionar apenas o nome e o sobrenome, você também pode adicionar o departamento do funcionário. Esta lista de departamentos virá da sua Departmentsmesa. Então agora você tem dados das tabelas Employeese Departmentsem um modelo de exibição. Você precisará adicionar as duas propriedades a seguir ao seu modelo de exibição e preenchê-lo com dados:

public int DepartmentId { get; set; }

public IEnumerable<Department> Departments { get; set; }

Ao editar os dados do funcionário (um funcionário que já foi adicionado ao banco de dados), não difere muito do meu exemplo acima. Crie um modelo de vista, chame-o por exemplo EditEmployeeViewModel. Tenha apenas os dados que você deseja editar neste modelo de visualização, como nome e sobrenome. Edite os dados e clique no botão enviar. Eu não me preocuparia muito com o Idcampo, porque o Idvalor provavelmente estará no URL, por exemplo:

http://www.yourwebsite.com/Employee/Edit/3

Pegue isso Ide passe-o para a camada do repositório, juntamente com os valores do seu nome e sobrenome.

Ao excluir um registro, normalmente sigo o mesmo caminho do modelo de visualização de edição. Eu também teria um URL, por exemplo:

http://www.yourwebsite.com/Employee/Delete/3

Quando a visualização é carregada pela primeira vez, eu obtinha os dados do funcionário no banco de dados usando o Id3. Eu mostrava texto estático na minha visualização / página para que o usuário pudesse ver qual funcionário está sendo excluído. Quando o usuário clica no botão Excluir, eu usaria o Idvalor 3 e o passaria para minha camada de repositório. Você só precisa Idexcluir um registro da tabela.

Outro ponto, você realmente não precisa de um modelo de visualização para cada ação. Se forem dados simples, seria bom usar apenas EmployeeViewModel. Se são vistas / páginas complexas e diferem uma da outra, sugiro que você use modelos de vista separados para cada uma.

Espero que isso esclareça qualquer confusão que você tenha sobre os modelos de exibição e domínio.


5
@Kenny: Então mostre isso :) O que eu estava tentando dizer é que digamos que você tenha um modelo de domínio com 50 propriedades e sua visualização precise exibir 5, então não adianta enviar todas as 50 propriedades apenas para exibir 5.
Brendan Vogt

5
@BrendanVogt - você fez um bom trabalho explicando isso, mas não entendo qual é o custo de "enviar todas as 50 propriedades". Outro código já criou um objeto Model, com todas as 50 propriedades, e não parece que vale a pena manter uma outra classe apenas para não enviar mais 45 propriedades - especialmente se você pode querer enviar qualquer uma dessas 45 propriedades no futuro.
21913 Kenny Evitt

5
@BrendanVogt - Acho que talvez a resposta da LukLed me ajude a entender por que essas informações podem ser úteis, principalmente porque um ViewModel (pode) "... combinar valores de diferentes entidades do banco de dados" [onde estou assumindo que a frase seja tão verdadeira quanto " entidades do banco de dados "a serem substituídas por" Objetos de modelo "]. Mas, ainda assim, quais problemas específicos os ViewModels pretendiam solucionar? Você tem algum link? Eu não consegui encontrar nada. [E peço desculpa se eu pareço estar mexendo com você!]
Kenny Evitt

1
Acabei de ouvir alguém dizer que o ViewModels é uma boa maneira de enviar várias coleções (ou propriedades de modelo cruzado) em uma única exibição sem precisar colocá-las no viewBag. Faz sentido para mim.
Ayyash 20/05

3
Sinto muito por ser crítico, mas esta resposta é, infelizmente, incompleta. Definir um modelo de exibição como apenas o que você precisa exibir na sua página é como perguntar "O que é um carro?" e receber uma resposta "Não é um avião". Bem, isso é verdade, mas não é muito útil. A definição mais correta de uma VM é "Tudo o que você precisa para renderizar sua página". Se você ler a parte inferior, identifiquei os componentes necessários para criar suas VMs de maneira correta e fácil, em muitos casos, aproveitando seus modelos de domínio e modelos de apresentação existentes.
Sam

133

O modelo de exibição é uma classe que representa o modelo de dados usado em uma exibição específica. Poderíamos usar esta classe como modelo para uma página de login:

public class LoginPageVM
{
    [Required(ErrorMessage = "Are you really trying to login without entering username?")]
    [DisplayName("Username/e-mail")]
    public string UserName { get; set; }
    [Required(ErrorMessage = "Please enter password:)")]
    [DisplayName("Password")]
    public string Password { get; set; }
    [DisplayName("Stay logged in when browser is closed")]
    public bool RememberMe { get; set; }
}

Usando este modelo de vista, você pode definir a vista (mecanismo de vista Razor):

@model CamelTrap.Models.ViewModels.LoginPageVM

@using (Html.BeginForm()) {
    @Html.EditorFor(m => m);
    <input type="submit" value="Save" class="submit" />
}

E ações:

[HttpGet]
public ActionResult LoginPage()
{
    return View();
}

[HttpPost]
public ActionResult LoginPage(LoginPageVM model)
{
    ...code to login user to application...
    return View(model);
}

O que produz esse resultado (a tela é obtida após o envio do formulário, com mensagens de validação):

Como você pode ver, um modelo de exibição tem muitas funções:

  • Exibir modelos documenta uma vista, consistindo apenas em campos representados na vista.
  • Os modelos de exibição podem conter regras de validação específicas usando anotações de dados ou IDataErrorInfo.
  • Ver modelo define como uma visão deve olhar (para LabelFor, EditorFor, DisplayForajudantes).
  • Os modelos de exibição podem combinar valores de diferentes entidades do banco de dados.
  • Você pode especificar facilmente modelos de exibição para modelos de exibição e reutilizá-los em muitos lugares usando os auxiliares DisplayFor ou EditorFor.

Outro exemplo de um modelo de visualização e sua recuperação: queremos exibir dados básicos do usuário, seus privilégios e nome de usuário. Criamos um modelo de vista especial, que contém apenas os campos obrigatórios. Recuperamos dados de diferentes entidades do banco de dados, mas a visualização apenas reconhece a classe do modelo de visualização:

public class UserVM {
    public int ID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public bool IsAdministrator { get; set; }
    public string MothersName { get; set; }
}

Recuperação:

var user = db.userRepository.GetUser(id);

var model = new UserVM() {
   ID = user.ID,
   FirstName = user.FirstName,
   LastName = user.LastName,
   IsAdministrator = user.Proviledges.IsAdministrator,
   MothersName = user.Mother.FirstName + " " + user.Mother.LastName
} 

Eu uso user.Mother.FirstName + "" + user.Mother.LastName deve ser feito em View Model End. Toda a lógica deve ser feita no final do modelo de exibição.
precisa saber é o seguinte

3
@ Chandhand: Eu acredito que uma concatenação simples pode ser feita no modelo de exibição. Não há razão para expor dois campos, se eles devem ser apresentados juntos.
LukLed

82

Editar: atualizei esta resposta no meu blog:

http://www.samwheat.com/post/The-function-of-ViewModels-in-MVC-web-development

Minha resposta é um pouco longa, mas acho importante comparar modelos de exibição com outros tipos de modelos comumente usados ​​para entender por que eles são diferentes e por que são necessários.

Para resumir e responder diretamente à pergunta que é feita:

De um modo geral, um modelo de vista é um objeto que contém todas as propriedades e métodos necessários para renderizar uma vista. As propriedades do modelo de exibição geralmente estão relacionadas a objetos de dados, como clientes e pedidos, e também contêm propriedades relacionadas à página ou ao próprio aplicativo, como nome de usuário, nome do aplicativo etc. crie uma página html. Uma das muitas razões para usar um modelo de exibição é que os modelos de exibição fornecem uma maneira de testar unidades determinadas tarefas de apresentação, como lidar com a entrada do usuário, validar dados, recuperar dados para exibição etc.

Aqui está uma comparação dos modelos de entidade (modelos a.ka. do DTO), modelos de apresentação e modelos de exibição.

Objetos de transferência de dados, também conhecidos como "Modelo"

Um Data Transfer Object (DTO) é uma classe com propriedades que correspondem a um esquema de tabela em um banco de dados. Os DTOs são nomeados por seu uso comum na transferência de dados de e para um repositório de dados.
Características dos DTOs:

• São objetos de negócios - sua definição depende dos dados do aplicativo.

• Normalmente contêm apenas propriedades - sem código.

• Usado principalmente para transportar dados de e para um banco de dados.

• As propriedades correspondem exatamente ou estreitamente aos campos em uma tabela específica em um armazenamento de dados.

As tabelas do banco de dados geralmente são normalizadas, portanto, os DTOs também são normalmente normalizados. Isso os torna de uso limitado para apresentação de dados. No entanto, para certas estruturas de dados simples, elas costumam se sair muito bem.

Aqui estão dois exemplos de como os DTOs podem se parecer:

public class Customer
{
    public int ID { get; set; }
    public string CustomerName { get; set; }
}


public class Order
{
    public int ID { get; set; }
    public int CustomerID { get; set; }
    public DateTime OrderDate { get; set; }
    public Decimal OrderAmount { get; set; }
}

Modelos de Apresentação

Um modelo de apresentação é uma classe de utilitário usada para renderizar dados em uma tela ou relatório. Os modelos de apresentação geralmente são usados ​​para modelar estruturas de dados complexas compostas de dados de vários DTOs. Os modelos de apresentação geralmente representam uma visão desnormalizada dos dados.

Características dos modelos de apresentação:

• São objetos de negócios - sua definição depende dos dados do aplicativo.

• Contêm principalmente propriedades. O código normalmente está limitado à formatação de dados ou à conversão de ou para um DTO. Os modelos de apresentação não devem conter lógica de negócios.

• Muitas vezes, apresentam uma visão desnormalizada dos dados. Ou seja, eles geralmente combinam propriedades de vários DTOs.

• Muitas vezes, contêm propriedades de um tipo de base diferente de um DTO. Por exemplo, os valores em dólares podem ser representados como cadeias de caracteres, para que possam conter vírgulas e um símbolo de moeda.

• Frequentemente definido por como eles são usados, bem como por suas características de objeto. Em outras palavras, um DTO simples que é usado como modelo de apoio para renderizar uma grade também é de fato um modelo de apresentação no contexto dessa grade.

Os modelos de apresentação são usados ​​"conforme necessário" e "onde necessário" (enquanto os DTOs geralmente estão vinculados ao esquema do banco de dados). Um modelo de apresentação pode ser usado para modelar dados para uma página inteira, uma grade em uma página ou uma lista suspensa em uma grade em uma página. Os modelos de apresentação geralmente contêm propriedades que são outros modelos de apresentação. Os modelos de apresentação são geralmente construídos para uma finalidade de uso único, como para renderizar uma grade específica em uma única página.

Um modelo de apresentação de exemplo:

public class PresentationOrder
{
    public int OrderID { get; set; }
    public DateTime OrderDate { get; set; }
    public string PrettyDate { get { return OrderDate.ToShortDateString(); } }
    public string CustomerName { get; set; }
    public Decimal OrderAmount { get; set; }
    public string PrettyAmount { get { return string.Format("{0:C}", OrderAmount); } }
}

Ver modelos

Um modelo de vista é semelhante a um modelo de apresentação, pois é uma classe de suporte para renderizar uma vista. No entanto, é muito diferente de um modelo de apresentação ou de um DTO na forma como ele é construído. Os modelos de exibição geralmente contêm as mesmas propriedades que os modelos de apresentação e os DTOs e, por esse motivo, geralmente são confundidos um pelo outro.

Características dos modelos de exibição:

• A fonte única de dados é usada para renderizar uma página ou tela. Normalmente, isso significa que um modelo de exibição exporá todas as propriedades que qualquer controle na página precisará para se renderizar corretamente. Tornar o modelo de visualização a única fonte de dados para a visualização melhora muito sua capacidade e valor para testes de unidade.

• São objetos compostos que contêm propriedades que consistem em dados do aplicativo e propriedades usadas pelo código do aplicativo. Essa característica é crucial ao projetar o modelo de vista para reutilização e é discutida nos exemplos abaixo.

• Contenha o código do aplicativo. Os modelos de exibição geralmente contêm métodos chamados durante a renderização e quando o usuário está interagindo com a página. Esse código geralmente se refere à manipulação de eventos, animação, visibilidade de controles, estilo etc.

• Contenha o código que chama os serviços comerciais com a finalidade de recuperar dados ou enviá-los para um servidor de banco de dados. Esse código geralmente é colocado por engano em um controlador. A chamada de serviços de negócios de um controlador geralmente limita a utilidade do modelo de exibição para testes de unidade. Para ser claro, os próprios modelos de exibição não devem conter lógica de negócios, mas devem fazer chamadas para serviços que contenham lógica de negócios.

• Muitas vezes, contêm propriedades que são outros modelos de exibição para outras páginas ou telas.

• São escritos "por página" ou "por tela". Um modelo de exibição exclusivo geralmente é escrito para todas as páginas ou telas de um aplicativo.

• Geralmente, derivam de uma classe base, já que a maioria das páginas e telas compartilha propriedades comuns.

Exibir composição do modelo

Conforme declarado anteriormente, os modelos de exibição são objetos compostos, pois combinam propriedades de aplicativos e dados de negócios em um único objeto. Exemplos de propriedades de aplicativos comumente usadas nos modelos de exibição são:

• Propriedades usadas para exibir o estado do aplicativo, como mensagens de erro, nome de usuário, status etc.

• Propriedades usadas para formatar, exibir, estilizar ou animar controles.

• Propriedades usadas para ligação de dados, como objetos de lista e propriedades que mantêm dados intermediários que são inseridos pelo usuário.

Os exemplos a seguir mostram por que a natureza composta dos modelos de vista é importante e como podemos construir melhor um Modelo de Vista que seja eficiente e reutilizável.

Suponha que estamos escrevendo um aplicativo da web. Um dos requisitos do design do aplicativo é que o título da página, o nome do usuário e o nome do aplicativo sejam exibidos em todas as páginas. Se queremos criar uma página para exibir um objeto de ordem de apresentação, podemos modificar o modelo de apresentação da seguinte maneira:

public class PresentationOrder
{
    public string PageTitle { get; set; }
    public string UserName { get; set; }
    public string ApplicationName { get; set; }
    public int OrderID { get; set; }
    public DateTime OrderDate { get; set; }
    public string PrettyDate { get { return OrderDate.ToShortDateString(); } }
    public string CustomerName { get; set; }
    public Decimal OrderAmount { get; set; }
    public string PrettyAmount { get { return string.Format("{0:C}", OrderAmount); } }
}

Esse design pode funcionar ... mas e se quisermos criar uma página que exibirá uma lista de pedidos? As propriedades PageTitle, UserName e ApplicationName serão repetidas e se tornarão difíceis de trabalhar. Além disso, e se quisermos definir alguma lógica no nível da página no construtor da classe? Não podemos mais fazer isso se criarmos uma instância para cada pedido que será exibido.

Composição sobre herança

Aqui está uma maneira de refazer o modelo de apresentação de pedidos, de forma que ele se torne um modelo de exibição real e seja útil para exibir um único objeto PresentationOrder ou uma coleção de objetos PresentationOrder:

public class PresentationOrderVM
{
    // Application properties
    public string PageTitle { get; set; }
    public string UserName { get; set; }
    public string ApplicationName { get; set; }

    // Business properties
    public PresentationOrder Order { get; set; }
}


public class PresentationOrderVM
{
    // Application properties
    public string PageTitle { get; set; }
    public string UserName { get; set; }
    public string ApplicationName { get; set; }

    // Business properties
    public List<PresentationOrder> Orders { get; set; }
}

Observando as duas classes acima, podemos ver que uma maneira de pensar em um modelo de exibição é que ele é um modelo de apresentação que contém outro modelo de apresentação como uma propriedade. O modelo de apresentação de nível superior (ou seja, modelo de exibição) contém propriedades relevantes para a página ou aplicativo, enquanto o modelo de apresentação (propriedade) contém propriedades relevantes para os dados do aplicativo.

Podemos dar um passo adiante em nosso design e criar uma classe de modelo de vista de base que pode ser usada não apenas para PresentationOrders, mas também para qualquer outra classe:

public class BaseViewModel
{
    // Application properties
    public string PageTitle { get; set; }
    public string UserName { get; set; }
    public string ApplicationName { get; set; }
}

Agora podemos simplificar nosso PresentationOrderVM assim:

public class PresentationOrderVM : BaseViewModel
{
    // Business properties
    public PresentationOrder Order { get; set; }
}

public class PresentationOrderVM : BaseViewModel
{
    // Business properties
    public List<PresentationOrder> Orders { get; set; }
}

Podemos tornar nosso BaseViewModel ainda mais reutilizável, tornando-o genérico:

public class BaseViewModel<T>
{
    // Application properties
    public string PageTitle { get; set; }
    public string UserName { get; set; }
    public string ApplicationName { get; set; }

    // Business property
    public T BusinessObject { get; set; }
}

Agora, nossas implementações são fáceis:

public class PresentationOrderVM : BaseViewModel<PresentationOrder>
{
    // done!
}

public class PresentationOrderVM : BaseViewModel<List<PresentationOrder>>
{
    // done!
}

2
Sam Obrigado !! isso me ajudou a entender completamente a entidade multifacetada que é: View-Model. Eu sou um estudante universitário que acabou de aprender a arquitetura MVC, e isso esclareceu várias funcionalidades capazes expostas ao desenvolvedor. Se eu pudesse, colocaria uma estrela ao lado de sua resposta.
precisa saber é o seguinte

1
@Sam 'Os modelos de exibição geralmente contêm as mesmas propriedades que os modelos de apresentação e DTOs e, por esse motivo, geralmente são confundidos um com o outro.' Isso significa que eles são comumente usados ​​em vez de modelos de apresentação ou devem conter os modelos / dtos de apresentação?
Alexander Derck

2
@AlexanderDerck Eles são usados ​​para diferentes propósitos. Eles estão confusos um com o outro (por engano). Não, você normalmente não usará um modelo pré no lugar de um modelo de vista. Muito mais comum é que a VM "contém" o modelo de apresentação, ou seja, MyViewModel<MyPresModel>
Sam

2
@Sam Supondo que os objetos de modelo sejam objetos ativos, por exemplo, modelos nhibernate .. portanto, ao ter BusinessObject, não estamos expondo objetos modelo / ativos diretamente à exibição? ou seja, o objeto de negócios pode ser usado para modificar diretamente o estado do banco de dados? Além disso, e os modelos de exibição aninhada? Isso exigiria várias propriedades de objetos de negócios, certo?
Muhammad Ali

22

Se você possui propriedades específicas para a exibição e não relacionadas ao armazenamento de banco de dados / serviço / dados, é uma boa prática usar o ViewModels. Digamos, você deseja deixar uma caixa de seleção marcada com base em um campo do banco de dados (ou dois), mas o próprio campo do banco de dados não é um booleano. Embora seja possível criar essas propriedades no próprio Modelo e mantê-las ocultas da ligação aos dados, você pode não querer desorganizar o Modelo, dependendo da quantidade desses campos e transações.

Se houver muito poucos dados e / ou transformações específicas da visualização, você poderá usar o próprio Modelo


19

Não li todas as postagens, mas todas as respostas parecem estar faltando um conceito que realmente me ajudou a "entender" ...

Se um Modelo é semelhante a uma Tabela de banco de dados , um ViewModel é semelhante a uma Visualização de banco de dados - Uma visualização geralmente retorna pequenas quantidades de dados de uma tabela ou conjuntos complexos de dados de várias tabelas (junções).

Encontro-me usando o ViewModels para passar informações para um modo de exibição / formulário e, em seguida, transferindo esses dados para um modelo válido quando o formulário é enviado de volta ao controlador - também muito útil para armazenar Lists (IEnumerable).


11

O MVC não possui um modelo de visualização: possui um modelo, visualização e controlador. Um viewmodel faz parte do MVVM (Model-View-Viewmodel). O MVVM é derivado do Modelo de Apresentação e é popularizado no WPF. Também deve haver um modelo no MVVM, mas a maioria das pessoas perde completamente o ponto desse padrão e elas terão apenas uma visualização e um modelo de visualização. O modelo no MVC é semelhante ao modelo no MVVM.

No MVC, o processo é dividido em três responsabilidades diferentes:

  • View é responsável por apresentar os dados ao usuário
  • Um controlador é responsável pelo fluxo da página
  • Um modelo é responsável pela lógica de negócios

O MVC não é muito adequado para aplicativos da web. É um padrão introduzido pelo Smalltalk para criar aplicativos de desktop. Um ambiente da web se comporta completamente diferente. Não faz muito sentido copiar um conceito de 40 anos do desenvolvimento da área de trabalho e colá-lo em um ambiente da Web. No entanto, muitas pessoas pensam que isso é bom, porque seu aplicativo compila e retorna os valores corretos. Isso é, na minha opinião, insuficiente para declarar uma certa opção de design como ok.

Um exemplo de modelo em um aplicativo da web pode ser:

public class LoginModel
{
    private readonly AuthenticationService authentication;

    public LoginModel(AuthenticationService authentication)
    {
        this.authentication = authentication;
    }

    public bool Login()
    {
        return authentication.Login(Username, Password);
    }

    public string Username { get; set; }
    public string Password { get; set; }
}

O controlador pode usá-lo assim:

public class LoginController
{
    [HttpPost]
    public ActionResult Login(LoginModel model)
    {
        bool success = model.Login();

        if (success)
        {
            return new RedirectResult("/dashboard");
        }
        else
        {
            TempData["message"] = "Invalid username and/or password";
            return new RedirectResult("/login");
        }
    }
}

Seus métodos de controle e seus modelos serão pequenos, facilmente testáveis ​​e diretos.


Obrigado pela compreensão da arquitetura MVVM, mas por que o MVC não está bem? Seu raciocínio é questionável e suspeito de favoritismo. É verdade que não sei nada sobre o MVVM, mas se uma arquitetura como o MVC pode imitar o comportamento sem precisar escrever 50k linhas de código, então qual é o problema?
precisa saber é o seguinte

@ Chef_Code: Não é questionável ou favoritismo: basta ler o artigo original sobre o MVC. Voltar à fonte é muito melhor do que seguir cegamente o rebanho sem questionar (também conhecido como "melhores práticas"). O MVC é destinado a unidades muito menores: por exemplo, um botão na tela é composto por um modelo, visualização e controlador. No Web-MVC, a página inteira possui um controlador, um modelo e uma visualização. O modelo e a vista devem estar conectados, para que as mudanças no modelo sejam imediatamente refletidas na vista e vice-versa. Imitar é um grande negócio. Uma arquitetura não deve mentir para seus desenvolvedores.
Jeroen

1
@jeroen A sigla MVC foi roubada e mutilada. Sim, o MVC não possui uma VM, mas também não possui um repositório ou uma camada de serviço e esses objetos são amplamente utilizados em sites. Eu acredito que o OP está perguntando "como eu introduzo e uso uma VM no MVC". No novo significado do MVC, um modelo não é o local da lógica de negócios. A lógica de negócios pertence a uma camada de serviço para um aplicativo da Web ou de desktop usando MVC ou MVVM. O termo modelo descreve os objetos de negócios que são passados ​​para / da camada de serviço. Essas definições são muito diferentes da descrição original do MVC.
Sam

1
@ Sam Nem tudo o que faz parte de um site pode ser chamado de parte do MVC. Não há novo significado para MVC. Existe o significado correto e o significado "algo completamente não relacionado que as pessoas confundem com o MVC". Dizer que o modelo é responsável pela lógica de negócios não é o mesmo que a lógica de negócios é codificada no modelo. Na maioria das vezes, o modelo atua como uma fachada para o aplicativo.
Jeroen

A principal falha que vejo no MVC da Microsoft é o bloqueio de um modelo com uma visualização. Isso, por si só, derrota todo o propósito de toda essa separação que está acontecendo nos projetos de N-Tier nos últimos 20 anos. Eles desperdiçaram nosso tempo nos forçando a usar o "WebForms" em 2002, que foi outro modelo inspirado no Desktop içado no mundo da Web. Agora eles jogaram isso fora, mas içaram mais uma vez outro modelo de desktop neste novo paradigma para web dev. Enquanto isso, o Google e outros estão construindo modelos gigantes do lado do cliente que separam tudo. Estou pensando que o antigo ASP VBScript de 1998 era o seu verdadeiro sistema de desenvolvimento web.
Stokely

11

O modelo de exibição a é uma classe simples que pode conter mais de uma propriedade de classe. Nós o usamos para herdar todas as propriedades necessárias, por exemplo, eu tenho duas classes Student e Subject

Public class Student
{
public int Id {get; set;}
public string Name {get; set;}
}  
Public class Subject
{
public int SubjectID {get; set;}
public string SubjectName {get; set;}
}

Agora, queremos exibir os registros Nome do aluno e Nome do sujeito na exibição (no MVC), mas não é possível adicionar mais de uma aula, como:

 @model ProjectName.Model.Student  
 @model ProjectName.Model.Subject

o código acima irá gerar um erro ...

Agora criamos uma classe e podemos atribuir qualquer nome a ela, mas esse formato "XyzViewModel" facilitará o entendimento. É um conceito de herança. Agora criamos uma terceira classe com o seguinte nome:

public class StudentViewModel:Subject
{
public int ID {get; set;}
public string Name {get; set;}
}

Agora usamos esse ViewModel no modo de exibição

@model ProjectName.Model.StudentViewModel

Agora podemos acessar todas as propriedades de StudentViewModel e a classe herdada no View.


10

Muitos exemplos grandes, deixe-me explicar de maneira clara e crocante.

ViewModel = Modelo criado para servir a vista.

A exibição do ASP.NET MVC não pode ter mais de um modelo; portanto, se precisarmos exibir propriedades de mais de um modelo na exibição, isso não será possível. O ViewModel serve a esse propósito.

View Model é uma classe de modelo que pode conter apenas as propriedades necessárias para uma visualização. Ele também pode conter propriedades de mais de uma entidade (tabelas) do banco de dados. Como o nome sugere, este modelo é criado específico para os requisitos de exibição.

Alguns exemplos de modelos de exibição estão abaixo

  • Para listar dados de mais de entidades em uma página de exibição - podemos criar um modelo de exibição e ter propriedades de todas as entidades para as quais queremos listar dados. Associe-se a essas entidades do banco de dados e defina as propriedades do modelo View e retorne à View para mostrar dados de diferentes entidades em um formulário tabular
  • O modelo de exibição pode definir apenas campos específicos de uma única entidade necessária para a exibição.

O ViewModel também pode ser usado para inserir e atualizar registros em mais de uma entidade. No entanto, o principal uso do ViewModel é exibir colunas de várias entidades (modelo) em uma única exibição.

A maneira de criar o ViewModel é a mesma que criar o Model, a maneira de criar a visualização para o Viewmodel é a mesma que criar a visualização para o Model.

Aqui está um pequeno exemplo de dados da lista usando o ViewModel .

Espero que isso seja útil.


6

O ViewModel é uma solução alternativa que corrige a falta de jeito conceitual da estrutura MVC. Representa a quarta camada na arquitetura Model-View-Controller de 3 camadas. quando Model (modelo de domínio) não é apropriado, muito grande (maior que 2-3 campos) para a View, criamos um ViewModel menor para passá-lo à View.


1

Um modelo de vista é um modelo conceitual de dados. Seu uso é, por exemplo, obter um subconjunto ou combinar dados de tabelas diferentes.

Você pode querer apenas propriedades específicas, portanto, isso permite carregar apenas essas e não propriedades desnecessárias adicionais


1
  • ViewModel contém campos representados na exibição (para auxiliares LabelFor, EditorFor, DisplayFor)
  • O ViewModel pode ter regras de validação específicas usando anotações de dados ou IDataErrorInfo.
  • O ViewModel pode ter várias entidades ou objetos de diferentes modelos ou fonte de dados.

Projetando o ViewModel

public class UserLoginViewModel 
{ 
[Required(ErrorMessage = "Please enter your username")] 
[Display(Name = "User Name")]
[MaxLength(50)]
public string UserName { get; set; }
 [Required(ErrorMessage = "Please enter your password")]
 [Display(Name = "Password")]
 [MaxLength(50)]
 public string Password { get; set; } 
} 

Apresentando o modelo de exibição na exibição

@model MyModels.UserLoginViewModel 
@{
 ViewBag.Title = "User Login";
 Layout = "~/Views/Shared/_Layout.cshtml";
}
@using (Html.BeginForm())
{
<div class="editor-label">
 @Html.LabelFor(m => m.UserName)
</div>
<div class="editor-field">
 @Html.TextBoxFor(m => m.UserName)
 @Html.ValidationMessageFor(m => m.UserName)
</div>
<div class="editor-label">
 @Html.LabelFor(m => m.Password)
</div>
<div class="editor-field">
 @Html.PasswordFor(m => m.Password)
 @Html.ValidationMessageFor(m => m.Password)
</div>
<p>
 <input type="submit" value="Log In" />
</p>
</div>
}

Trabalhando com ação

public ActionResult Login()
{ 
return View();
}
[HttpPost]
public ActionResult Login(UserLoginViewModel user)
{
// To acces data using LINQ
DataClassesDataContext mobjentity = new DataClassesDataContext();
 if (ModelState.IsValid) 
{ 
try
 {
 var q = mobjentity.tblUsers.Where(m => m.UserName == user.UserName && m.Password == user.Password).ToList(); 
 if (q.Count > 0) 
 { 
 return RedirectToAction("MyAccount");
 }
 else
 {
 ModelState.AddModelError("", "The user name or password provided is incorrect.");
 }
 }
 catch (Exception ex)
 {
 } 
 } 
 return View(user);
} 
  1. No ViewModel, coloque apenas os campos / dados que você deseja exibir na exibição / página.
  2. Uma vez que a visualização repercute as propriedades do ViewModel, é fácil renderizá-lo e mantê-lo.
  3. Use um mapeador quando o ViewModel se tornar mais complexo.

1

View Model é a classe que podemos usar para renderizar dados no View. Suponha que você tenha duas entidades Place e PlaceCategory e deseje acessar os dados de ambas as entidades usando um único modelo; em seguida, usamos o ViewModel.

  public class Place
    {
       public int PlaceId { get; set; }
        public string PlaceName { get; set; }
        public string Latitude { get; set; }
        public string Longitude { get; set; }
        public string BestTime { get; set; }
    }
    public class Category
    {
        public int ID { get; set; }
        public int? PlaceId { get; set; }
        public string PlaceCategoryName { get; set; }
        public string PlaceCategoryType { get; set; }
    }
    public class PlaceCategoryviewModel
    {
        public string PlaceName { get; set; }
        public string BestTime { get; set; }
        public string PlaceCategoryName { get; set; }
        public string PlaceCategoryType { get; set; }
    }

Portanto, no exemplo acima, Place e Category são as duas entidades diferentes e o PlaceCategory viewmodel é o ViewModel que podemos usar no View.


Seus exemplos não são tão claros. O que foi dito acima é que um ViewModel conecta os dados à sua exibição. Se você observar os ViewModels no BlipAjax, verá as classes que são mais adequadas para ele.
Herman Van Der Blom

0

Se você deseja estudar o código de como configurar um aplicativo da Web "Linha de base" com o ViewModels, aconselho o download desse código no GitHub: https://github.com/ajsaulsberry/BlipAjax . Eu desenvolvi grandes aplicativos corporativos. Quando você faz isso, é problemático configurar uma boa arquitetura que lida com toda essa funcionalidade "ViewModel". Eu acho que com o BlipAjax você terá uma "linha de base" muito boa para começar. É apenas um site simples, mas excelente em sua simplicidade. Gosto da maneira como eles usaram o idioma inglês para apontar o que é realmente necessário no aplicativo.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.