Che cos'è ViewModel in MVC?


429

Sono nuovo di ASP.NET MVC. Ho un problema con la comprensione dello scopo di un ViewModel.

Che cos'è un ViewModel e perché è necessario un ViewModel per un'applicazione MVC ASP.NET?

Se avessi un buon esempio del suo funzionamento e delle sue spiegazioni sarebbe meglio.


4
Questo post è quello che cerchi: "Che cos'è un ASP.NET MVC ViewModel?"
Yusubov,

6
Questo articolo ha un bell'aspetto: rachelappel.com/…
Andrew,

Risposte:


607

A view modelrappresenta i dati che si desidera visualizzare nella vista / pagina, sia che vengano utilizzati per il testo statico o per i valori di input (come caselle di testo ed elenchi a discesa) che possono essere aggiunti al database (o modificati). È qualcosa di diverso dal tuo domain model. È un modello per la vista.

Supponiamo che tu abbia una Employeeclasse che rappresenta il tuo modello di dominio dei dipendenti e contiene le seguenti proprietà (identificativo univoco, nome, cognome e data di creazione):

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

     public string FirstName { get; set; }

     public string LastName { get; set; }

     public DateTime DateCreated { get; set; }
}

I modelli di visualizzazione differiscono dai modelli di dominio in quanto i modelli di visualizzazione contengono solo i dati (rappresentati da proprietà) che si desidera utilizzare nella vista. Ad esempio, supponiamo che tu voglia aggiungere un nuovo record di dipendenti, il tuo modello di vista potrebbe apparire così:

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

     public string LastName { get; set; }
}

Come puoi vedere contiene solo due delle proprietà. Queste due proprietà si trovano anche nel modello di dominio dei dipendenti. Perché potresti chiedere questo? Idpotrebbe non essere impostato dalla vista, potrebbe essere generato automaticamente dalla tabella Employee. E DateCreatedpotrebbe anche essere impostato nella procedura memorizzata o nel livello di servizio dell'applicazione. Quindi Ide DateCreatednon sono necessari nel modello di visualizzazione. È possibile che si desideri visualizzare queste due proprietà quando si visualizzano i dettagli di un dipendente (un dipendente che è già stato acquisito) come testo statico.

Quando si carica la vista / pagina, il metodo di azione di creazione nel controller dei dipendenti creerà un'istanza di questo modello di vista, popolerà eventuali campi se necessario, quindi passerà questo modello di vista alla vista / pagina:

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
     }
}

La tua vista / pagina potrebbe apparire così (supponendo che tu stia utilizzando ASP.NET MVCe il Razormotore di visualizzazione):

@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>

La convalida verrebbe quindi effettuata solo su FirstNamee LastName. Usando FluentValidation potresti avere una validazione come questa:

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 con le annotazioni dei dati potrebbe apparire così:

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; }
}

La cosa fondamentale da ricordare è che il modello di visualizzazione rappresenta solo i dati che si desidera utilizzare , nient'altro. Puoi immaginare tutto il codice e la convalida non necessari se disponi di un modello di dominio con 30 proprietà e desideri aggiornare solo un singolo valore. Dato questo scenario, nel modello della vista si avrebbe solo questo valore / proprietà e non tutte le proprietà che si trovano nell'oggetto dominio.

Un modello di vista potrebbe non avere solo dati da una tabella del database. Può combinare i dati da un'altra tabella. Prendi il mio esempio sopra sull'aggiunta di un nuovo record di dipendenti. Oltre ad aggiungere solo il nome e il cognome, potresti anche voler aggiungere il dipartimento dell'impiegato. Questo elenco di dipartimenti verrà dalla tua Departmentstabella. Quindi ora hai dati dalle tabelle Employeese Departmentsin un modello di vista. Sarà quindi necessario aggiungere le seguenti due proprietà al modello di visualizzazione e popolarlo con i dati:

public int DepartmentId { get; set; }

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

Quando si modificano i dati dei dipendenti (un dipendente che è già stato aggiunto al database) non differirebbero molto dal mio esempio sopra. Crea un modello di vista, chiamalo ad esempio EditEmployeeViewModel. Hanno solo i dati che si desidera modificare in questo modello di vista, come nome e cognome. Modifica i dati e fai clic sul pulsante Invia. Non mi preoccuperei troppo del Idcampo perché il Idvalore sarà probabilmente nell'URL, ad esempio:

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

Prendi questo Ide passalo al livello del tuo repository, insieme ai valori del tuo nome e cognome.

Quando si elimina un record, normalmente seguo lo stesso percorso del modello della vista di modifica. Vorrei anche un URL, ad esempio:

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

Quando la vista viene caricata per la prima volta, ottengo i dati dell'impiegato dal database usando il punto Id3. Vorrei quindi visualizzare solo testo statico sulla mia vista / pagina in modo che l'utente possa vedere quale dipendente viene eliminato. Quando l'utente fa clic sul pulsante Elimina, vorrei semplicemente usare il Idvalore 3 e passarlo al mio livello di repository. Hai solo bisogno Iddi eliminare un record dalla tabella.

Un altro punto, non è davvero necessario un modello di visualizzazione per ogni azione. Se si tratta di dati semplici, andrebbe bene usare solo EmployeeViewModel. Se si tratta di viste / pagine complesse e differiscono l'una dall'altra, suggerirei di utilizzare modelli di vista separati per ciascuna.

Spero che questo chiarisca qualsiasi confusione che hai avuto riguardo a visualizzare modelli e modelli di dominio.


5
@Kenny: Allora mostralo :) Quello che stavo cercando di dire è supponiamo che tu abbia un modello di dominio con 50 proprietà e che la tua vista debba solo visualizzarne 5, quindi non serve a nulla inviare tutte e 50 le proprietà solo per visualizzare 5.
Brendan Vogt,

5
@BrendanVogt - hai fatto un buon lavoro spiegandolo, ma non capisco quale sia il costo di "invio di tutte e 50 le proprietà". Un altro codice ha già creato un oggetto Model, con tutte e 50 le proprietà, e non sembra utile mantenere un'altra classe solo per non inviare 45 proprietà, specialmente se in futuro potresti voler inviare una di queste 45 proprietà.
Kenny Evitt,

5
@BrendanVogt - Penso che forse la risposta di LukLed mi aiuti a capire perché potrebbero essere utili, in particolare che un ViewModel (può) "... combinare valori da entità di database diverse" [dove suppongo che la frase sia altrettanto vera " entità del database "da sostituire con" Oggetti modello "]. Tuttavia, quali problemi specifici avrebbero dovuto affrontare ViewModels? Hai qualche link? Non sono riuscito a trovare nulla da solo. [E mi scuso se sembra che ti stia prendendo in
giro

1
Ho appena sentito qualcuno dire che ViewModels è un buon modo per inviare più raccolte (o proprietà incrociate del modello) in una singola vista senza doverle inserire in viewBag. È sensato per me.
Ayyash,

3
Mi dispiace per essere critico, ma questa risposta è purtroppo incompleta. Definire un modello di visualizzazione come solo ciò che è necessario visualizzare sulla tua pagina è come chiedere "Cos'è un'auto?" e ricevendo una risposta "Non è un aeroplano". Bene, questo è vero ma non molto utile. La definizione più corretta di una macchina virtuale è "Tutto il necessario per rendere la tua pagina". Se leggete fino in fondo, ho identificato i componenti necessari per creare correttamente e facilmente le VM, sfruttando in molti casi i modelli di dominio e i modelli di presentazione esistenti.
Sam,

133

Il modello di visualizzazione è una classe che rappresenta il modello di dati utilizzato in una vista specifica. Potremmo usare questa classe come modello per una pagina di accesso:

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; }
}

Utilizzando questo modello di visualizzazione è possibile definire la vista (motore di visualizzazione Razor):

@model CamelTrap.Models.ViewModels.LoginPageVM

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

E azioni:

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

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

Che produce questo risultato (la schermata viene visualizzata dopo l'invio del modulo, con messaggi di convalida):

Come puoi vedere, un modello di vista ha molti ruoli:

  • Visualizza modelli documenta una vista composta solo da campi, che sono rappresentati in vista.
  • I modelli di visualizzazione possono contenere regole di convalida specifiche utilizzando annotazioni di dati o IDataErrorInfo.
  • Visualizza il modello definisce come una vista dovrebbe apparire (per LabelFor, EditorFor, DisplayForaiutanti).
  • Visualizza i modelli possono combinare i valori di diverse entità del database.
  • È possibile specificare facilmente modelli di visualizzazione per i modelli di visualizzazione e riutilizzarli in molti punti utilizzando gli helper DisplayFor o EditorFor.

Un altro esempio di modello di visualizzazione e relativo recupero: vogliamo visualizzare i dati di base dell'utente, i suoi privilegi e il nome dell'utente. Creiamo un modello di vista speciale, che contiene solo i campi richiesti. Recuperiamo i dati da entità diverse dal database, ma la vista è a conoscenza solo della classe del modello di vista:

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; }
}

Recupero:

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
} 

I thin user.Mother.FirstName + "" + user.Mother.LastName dovrebbe essere eseguito in Visualizza modello fine. Tutta la logica deve essere eseguita alla fine di Visualizza modello.
Kurkula,

3
@Chandana: credo che una semplice concatenazione possa essere fatta nel modello di visualizzazione. Non c'è motivo di esporre due campi, se si intende che vengano presentati insieme.
LukLed,

82

Modifica: ho aggiornato questa risposta sul mio blog:

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

La mia risposta è un po 'lunga, ma penso che sia importante confrontare i modelli di vista con altri tipi di modelli comunemente usati per capire perché sono diversi e perché sono necessari.

Riassumendo e rispondere direttamente alla domanda che viene posta:

In generale, un modello di vista è un oggetto che contiene tutte le proprietà e i metodi necessari per eseguire il rendering di una vista. Le proprietà del modello di visualizzazione sono spesso correlate a oggetti dati come clienti e ordini e inoltre contengono anche proprietà correlate alla pagina o all'applicazione stessa come nome utente, nome dell'applicazione, ecc. I modelli di visualizzazione forniscono un oggetto conveniente da passare a un motore di rendering a crea una pagina html. Uno dei molti motivi per utilizzare un modello di visualizzazione è che i modelli di visualizzazione forniscono un modo per testare l'unità di determinate attività di presentazione come la gestione dell'input dell'utente, la convalida dei dati, il recupero dei dati per la visualizzazione, ecc.

Ecco un confronto tra i modelli Entity (a.ka. a.ka. a.ka. models), Presentation Models e View Models.

Oggetti di trasferimento dati noti anche come "Modello"

Un Data Transfer Object (DTO) è una classe con proprietà che corrispondono a uno schema di tabella in un database. I DTO sono nominati per il loro uso comune per il trasferimento di dati da e verso un archivio dati.
Caratteristiche dei DTO:

• Sono oggetti business: la loro definizione dipende dai dati dell'applicazione.

• Solitamente contengono solo proprietà - nessun codice.

• Utilizzato principalmente per il trasporto di dati da e verso un database.

• Le proprietà corrispondono esattamente o strettamente ai campi su una tabella specifica in un archivio dati.

Le tabelle del database sono normalmente normalizzate, pertanto anche i DTO sono normalmente normalizzati. Ciò li rende di scarsa utilità per la presentazione dei dati. Tuttavia, per alcune semplici strutture dati spesso fanno abbastanza bene.

Ecco due esempi di come potrebbero apparire i DTO:

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; }
}

Modelli di presentazione

Un modello di presentazione è una classe di utilità utilizzata per il rendering dei dati su una schermata o un report. I modelli di presentazione sono in genere utilizzati per modellare strutture dati complesse composte da dati provenienti da più DTO. I modelli di presentazione spesso rappresentano una vista denormalizzata dei dati.

Caratteristiche dei modelli di presentazione:

• Sono oggetti business: la loro definizione dipende dai dati dell'applicazione.

• Contengono principalmente proprietà. Il codice è in genere limitato alla formattazione dei dati o alla conversione in o da un DTO. I modelli di presentazione non devono contenere la logica aziendale.

• Spesso presentano una vista denormalizzata dei dati. Cioè, spesso combinano proprietà di più DTO.

• Spesso contengono proprietà di un tipo di base diverso rispetto a un DTO. Ad esempio, gli importi in dollari possono essere rappresentati come stringhe in modo che possano contenere virgole e un simbolo di valuta.

• Spesso definito dal modo in cui vengono utilizzati e dalle loro caratteristiche dell'oggetto. In altre parole, un semplice DTO utilizzato come modello di supporto per il rendering di una griglia è in realtà anche un modello di presentazione nel contesto di quella griglia.

I modelli di presentazione vengono utilizzati “secondo necessità” e “dove necessario” (mentre i DTO sono generalmente legati allo schema del database). Un modello di presentazione può essere utilizzato per modellare i dati di un'intera pagina, una griglia su una pagina o un menu a discesa su una griglia su una pagina. I modelli di presentazione contengono spesso proprietà che sono altri modelli di presentazione. I modelli di presentazione sono spesso costruiti per uno scopo monouso, come il rendering di una griglia specifica su una singola pagina.

Un modello di presentazione di esempio:

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); } }
}

Visualizza i modelli

Un modello di vista è simile a un modello di presentazione in quanto è una classe di supporto per il rendering di una vista. Tuttavia è molto diverso da un modello di presentazione o da un DTO nel modo in cui è costruito. I modelli di visualizzazione contengono spesso le stesse proprietà dei modelli di presentazione e dei DTO e per questo motivo sono spesso confusi l'uno per l'altro.

Caratteristiche dei modelli di visualizzazione:

• Sono la singola fonte di dati utilizzata per il rendering di una pagina o di una schermata. Di solito ciò significa che un modello di vista esporrà tutte le proprietà necessarie per il rendering corretto di qualsiasi controllo sulla pagina. Rendere il modello della vista come unica fonte di dati per la vista migliora notevolmente la sua capacità e il suo valore per i test unitari.

• Sono oggetti compositi che contengono proprietà costituite da dati dell'applicazione e proprietà utilizzate dal codice dell'applicazione. Questa caratteristica è cruciale quando si progetta il modello di visualizzazione per la riusabilità ed è discussa negli esempi seguenti.

• Contiene il codice dell'applicazione. I modelli di visualizzazione in genere contengono metodi chiamati durante il rendering e quando l'utente interagisce con la pagina. Questo codice si riferisce in genere alla gestione degli eventi, all'animazione, alla visibilità dei controlli, allo stile, ecc.

• Contiene codice che chiama i servizi aziendali allo scopo di recuperare dati o inviarli a un server di database. Questo codice viene spesso erroneamente inserito in un controller. La chiamata ai servizi aziendali da un controller di solito limita l'utilità del modello di visualizzazione per i test unitari. Per essere chiari, gli stessi modelli di visualizzazione non dovrebbero contenere la logica aziendale ma dovrebbero effettuare chiamate ai servizi che contengono la logica aziendale.

• Spesso contengono proprietà che sono altri modelli di visualizzazione per altre pagine o schermate.

• Sono scritti "per pagina" o "per schermo". Un modello di visualizzazione univoco viene in genere scritto per ogni pagina o schermata in un'applicazione.

• Di solito derivano da una classe di base poiché la maggior parte delle pagine e schermate condividono proprietà comuni.

Visualizza la composizione del modello

Come affermato in precedenza, i modelli di visualizzazione sono oggetti compositi in quanto combinano le proprietà dell'applicazione e le proprietà dei dati aziendali su un singolo oggetto. Esempi di proprietà dell'applicazione comunemente utilizzate che vengono utilizzate nei modelli di visualizzazione sono:

• Proprietà utilizzate per visualizzare lo stato dell'applicazione come messaggi di errore, nome utente, stato, ecc.

• Proprietà utilizzate per formattare, visualizzare, stilizzare o animare i controlli.

• Proprietà utilizzate per l'associazione di dati come oggetti elenco e proprietà che contengono dati intermedi immessi dall'utente.

Gli esempi seguenti mostrano perché la natura composita dei modelli di vista è importante e come possiamo costruire al meglio un modello di vista così efficiente e riutilizzabile.

Supponiamo che stiamo scrivendo un'applicazione web. Uno dei requisiti del design dell'applicazione è che il titolo della pagina, il nome utente e il nome dell'applicazione devono essere visualizzati su ogni pagina. Se vogliamo creare una pagina per visualizzare un oggetto ordine di presentazione, possiamo modificare il modello di presentazione come segue:

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); } }
}

Questo design potrebbe funzionare ... ma se vogliamo creare una pagina che visualizzerà un elenco di ordini? Le proprietà PageTitle, UserName e ApplicationName verranno ripetute e diventeranno poco maneggevoli. Inoltre, se vogliamo definire una logica a livello di pagina nel costruttore della classe? Non possiamo più farlo se creiamo un'istanza per ogni ordine che verrà visualizzato.

Composizione su eredità

Ecco un modo in cui potremmo ricodificare il modello di presentazione dell'ordine in modo che diventi un vero modello di visualizzazione e sarà utile per visualizzare un singolo oggetto PresentationOrder o una raccolta di oggetti 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; }
}

Osservando le due classi precedenti possiamo vedere che un modo di pensare a un modello di vista è che è un modello di presentazione che contiene un altro modello di presentazione come proprietà. Il modello di presentazione di livello superiore (ad es. Modello di visualizzazione) contiene proprietà rilevanti per la pagina o l'applicazione mentre il modello di presentazione (proprietà) contiene proprietà rilevanti per i dati dell'applicazione.

Possiamo fare un ulteriore passo avanti nel nostro design e creare una classe del modello di vista di base che può essere utilizzata non solo per PresentationOrders, ma anche per qualsiasi altra classe:

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

Ora possiamo semplificare il nostro PresentationOrderVM in questo modo:

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

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

Possiamo rendere il nostro BaseViewModel ancora più riutilizzabile rendendolo generico:

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; }
}

Ora le nostre implementazioni sono semplici:

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

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

2
Sam Grazie !! questo mi ha aiutato a cogliere appieno l'entità sfaccettata che è: View-Model. Sono uno studente universitario che sta imparando l'architettura MVC e questo ha chiarito un sacco di funzionalità capaci che sono esposte allo sviluppatore. Se potessi, metterei una stella accanto alla tua risposta.
Chef_Code

1
@Sam 'I modelli di visualizzazione contengono spesso le stesse proprietà dei modelli di presentazione e dei DTO e per questo motivo sono spesso confusi l'uno per l'altro.' Significa che sono comunemente usati al posto dei modelli di presentazione o sono destinati a contenere i modelli di presentazione / dtos?
Alexander Derck,

2
@AlexanderDerck Sono utilizzati per scopi diversi. Sono confusi l'uno per l'altro (per errore). No, in genere non si utilizzerà un modello pres al posto di un modello di visualizzazione. Molto più comune è che la VM "contiene" il modello di presentazione, cioè MyViewModel<MyPresModel>
Sam,

2
@Sam Supponendo che gli oggetti modello siano oggetti vivi, ad esempio modelli negligenti .. quindi avendo BusinessObject non stiamo esponendo oggetti modello / live direttamente alla vista? cioè l'oggetto business può essere usato per modificare direttamente lo stato del database? Inoltre, che dire dei modelli di vista nidificati? Ciò richiederebbe più proprietà dell'oggetto business, giusto?
Muhammad Ali,

22

Se si dispone di proprietà specifiche della vista e non correlate all'archivio DB / servizi / dati, è consigliabile utilizzare ViewModels. Supponiamo che tu voglia lasciare una casella selezionata in base a un campo DB (o due) ma il campo DB stesso non è un valore booleano. Sebbene sia possibile creare queste proprietà nel Modello stesso e tenerlo nascosto dall'associazione ai dati, potrebbe non essere necessario ingombrare il Modello a seconda della quantità di tali campi e transazioni.

Se i dati e / o le trasformazioni specifici della vista sono troppo pochi, è possibile utilizzare il modello stesso


19

Non ho letto tutti i post, ma a ogni risposta sembra mancare un concetto che mi ha davvero aiutato a "capirlo" ...

Se un modello è simile a una tabella del database , un ViewModel è simile a una vista del database - Una vista in genere restituisce piccole quantità di dati da una tabella o serie complesse di dati da più tabelle (join).

Mi ritrovo a utilizzare ViewModels per passare le informazioni in una vista / modulo e quindi a trasferire quei dati in un modello valido quando il modulo torna al controller - anche molto utile per l'archiviazione di elenchi (IEnumerable).


11

MVC non ha un modello di visualizzazione: ha un modello, una vista e un controller. Un viewmodel fa parte di MVVM (Model-View-Viewmodel). MVVM è derivato dal modello di presentazione ed è reso popolare in WPF. Dovrebbe esserci anche un modello in MVVM, ma la maggior parte delle persone perde completamente il punto di quel modello e avranno solo una vista e un modello di visualizzazione. Il modello in MVC è simile al modello in MVVM.

In MVC il processo è suddiviso in 3 diverse responsabilità:

  • View è responsabile della presentazione dei dati all'utente
  • Un controller è responsabile del flusso di pagine
  • Un modello è responsabile della logica aziendale

MVC non è molto adatto per applicazioni web. È un modello introdotto da Smalltalk per la creazione di applicazioni desktop. Un ambiente Web si comporta in modo completamente diverso. Non ha molto senso copiare un concetto di 40 anni dallo sviluppo desktop e incollarlo in un ambiente web. Tuttavia, molte persone pensano che sia ok, perché la loro applicazione compila e restituisce i valori corretti. Questo, secondo me, non è abbastanza per dichiarare una certa scelta progettuale come ok.

Un esempio di un modello in un'applicazione Web potrebbe essere:

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; }
}

Il controller può usarlo in questo modo:

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");
        }
    }
}

I tuoi metodi controller e i tuoi modelli saranno piccoli, facilmente testabili e mirati.


Grazie per la comprensione dell'architettura MVVM, ma perché MVC non è OK? Il tuo ragionamento è discutibile e sospetto di favoritismo. Certo, non so nulla di MVVM, ma se un'architettura come MVC può imitare il comportamento senza dover scrivere 50k righe di codice, qual è il grosso problema?
Chef_Code

@Chef_Code: non è discutibile o favoritismo: basta leggere l'articolo originale su MVC. Tornare alla fonte è molto meglio che seguire ciecamente la mandria senza dubbio (alias "best practice"). MVC è pensato per unità molto più piccole: ad es. Un pulsante su uno schermo è composto da un modello, una vista e un controller. In Web-MVC l'intera pagina ha un controller, un modello e una vista. Si suppone che il modello e la vista siano collegati, in modo che i cambiamenti nel modello si riflettano immediatamente nella vista e viceversa. Imitare è un grosso problema. Un'architettura non dovrebbe mentire ai suoi sviluppatori.
Jeroen,

1
@jeroen L'acronimo MVC è stato rubato e mutilato. Sì, MVC non ha una VM ma non ha nemmeno un repository o un livello di servizio e tali oggetti sono ampiamente utilizzati nei siti Web. Credo che l'OP chieda "come posso introdurre e utilizzare una VM in MVC". Nel nuovo significato di MVC un modello non è il luogo in cui appartiene la logica aziendale. La logica aziendale appartiene a un livello di servizio per un'app Web o desktop che utilizza MVC o MVVM. Il termine modello descrive gli oggetti business passati al / dal livello di servizio. Queste definizioni sono molto diverse dalla descrizione originale di MVC.
Sam,

1
@Sam Non tutto ciò che fa parte di un sito Web può essere chiamato parte di MVC. Non c'è un nuovo significato di MVC. C'è il significato corretto e il significato di "qualcosa di completamente non correlato che le persone confondono con MVC". Dire che il modello è responsabile della logica aziendale, non è lo stesso della logica aziendale codificata nel modello. Il più delle volte il modello funge da facciata per l'applicazione.
Jeroen,

Il principale difetto che vedo nell'MVC di Microsoft è il blocco di un modello con vista. Questo stesso sconfigge l'intero scopo di tutta questa separazione che è avvenuta nei progetti di livello N negli ultimi 20 anni. Hanno sprecato il nostro tempo costringendoci a utilizzare "WebForms" nel 2002, che era un altro modello ispirato al desktop montato sul Web World. Ora l'hanno buttato fuori ma hanno sollevato ancora una volta un altro modello desktop su questo nuovo paradigma per gli sviluppatori web. Nel frattempo, Google e altri stanno costruendo modelli lato client giganti che lo separano. Sto pensando che il vecchio ASP VBScript del 1998 fosse il loro più vero sistema di sviluppo web.
Stokely,

11

Visualizza il modello a è una classe semplice che può contenere più di una proprietà di classe. Lo usiamo per ereditare tutte le proprietà richieste, ad esempio ho due classi 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;}
}

Ora vogliamo visualizzare i record Nome dello studente e Nome del soggetto nella vista (in MVC), ma non è possibile aggiungere più di una classe come:

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

il codice sopra genererà un errore ...

Ora creiamo una classe e possiamo darle qualsiasi nome, ma questo formato "XyzViewModel" renderà più facile la comprensione. È il concetto di eredità. Ora creiamo una terza classe con il seguente nome:

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

Ora usiamo questo ViewModel in View

@model ProjectName.Model.StudentViewModel

Ora siamo in grado di accedere a tutte le proprietà di StudentViewModel e della classe ereditata in View.


10

Molti grandi esempi, lasciami spiegare in modo chiaro e croccante.

ViewModel = Modello creato per servire la vista.

La vista ASP.NET MVC non può avere più di un modello, quindi se è necessario visualizzare le proprietà di più di un modello nella vista, non è possibile. ViewModel serve a questo scopo.

Visualizza modello è una classe di modello che può contenere solo quelle proprietà richieste per una vista. Può anche contenere proprietà di più di una entità (tabelle) del database. Come suggerisce il nome, questo modello è stato creato appositamente per i requisiti di visualizzazione.

Di seguito sono riportati alcuni esempi di modelli di visualizzazione

  • Per elencare i dati da più di entità in una pagina di visualizzazione, possiamo creare un modello di visualizzazione e avere proprietà di tutte le entità per cui vogliamo elencare i dati. Unire le entità del database e impostare Visualizza le proprietà del modello e tornare alla Vista per mostrare i dati di entità diverse in una forma tabulare
  • Il modello di vista può definire solo campi specifici di una singola entità richiesti per la vista.

ViewModel può anche essere utilizzato per inserire, aggiornare i record in più di una entità, tuttavia l'uso principale di ViewModel è quello di visualizzare colonne di più entità (modello) in una singola vista.

Il modo di creare ViewModel è lo stesso della creazione di Model, il modo di creare view per Viewmodel è lo stesso di creare view per Model.

Ecco un piccolo esempio di dati elenco usando ViewModel .

Spero che questo sia utile.


6

ViewModel è una soluzione alternativa che corregge la goffaggine concettuale del framework MVC. Rappresenta il 4 ° livello nell'architettura Model-View-Controller a 3 livelli. quando Model (modello di dominio) non è appropriato, troppo grande (più grande di 2-3 campi) per la vista, creiamo ViewModel più piccolo per passarlo alla vista.


1

Un modello di vista è un modello concettuale di dati. Il suo utilizzo è ad esempio quello di ottenere un sottoinsieme o combinare i dati da diverse tabelle.

Potresti volere solo proprietà specifiche, quindi questo ti consente di caricare solo quelle e non ulteriori proprietà non obbligatorie


1
  • ViewModel contiene campi rappresentati nella vista (per gli helper LabelFor, EditorFor, DisplayFor)
  • ViewModel può avere regole di convalida specifiche utilizzando annotazioni di dati o IDataErrorInfo.
  • ViewModel può avere più entità o oggetti da diversi modelli di dati o origine dati.

Progettazione di 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; } 
} 

Presentazione del modello di visualizzazione nella vista

@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>
}

Lavorare con l'azione

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. In ViewModel inserisci solo i campi / dati che desideri visualizzare nella vista / pagina.
  2. Dato che view ripropone le proprietà di ViewModel, è quindi facile per il rendering e la manutenzione.
  3. Utilizzare un mapper quando ViewModel diventa più complesso.

1

View Model è una classe che possiamo usare per il rendering dei dati su View. Supponiamo che tu abbia due entità Place e PlaceCategory e desideri accedere ai dati di entrambe le entità utilizzando un singolo modello, quindi usiamo 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; }
    }

Quindi, nell'esempio sopra, Luogo e Categoria sono le due diverse entità e PlaceCategory viewmodel è ViewModel che possiamo usare su View.


I tuoi esempi non sono così chiari. Ciò che è stato detto sopra è che un ViewModel collega i dati alla sua vista. Se guardi i ViewModels in BlipAjax vedi delle classi che si adattano perfettamente a questo.
Herman Van Der Blom,

0

Se vuoi studiare il codice su come configurare un'applicazione web "Baseline" con ViewModels, posso consigliare di scaricare questo codice su GitHub: https://github.com/ajsaulsberry/BlipAjax . Ho sviluppato applicazioni di grandi dimensioni. Quando lo fai è problematico impostare una buona architettura che gestisca tutte queste funzionalità di "ViewModel". Penso che con BlipAjax avrai una "base" molto buona per cominciare. È solo un sito Web semplice, ma eccezionale nella sua semplicità. Mi piace il modo in cui hanno usato la lingua inglese per indicare ciò che è veramente necessario nell'applicazione.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.