Що таке ViewModel в MVC?


429

Я новачок у ASP.NET MVC. У мене проблеми з розумінням мети ViewModel.

Що таке ViewModel і навіщо нам потрібен ViewModel для програми ASP.NET MVC?

Якщо я отримаю хороший приклад щодо його роботи та пояснення, що було б краще.


4
Ця публікація - те, що ви шукаєте - "Що таке ASP.NET MVC ViewModel?"
Юсубов

6
Ця стаття виглядає чудово: rachelappel.com/…
Ендрю,

можливий дублікат In MVC, що таке ViewModel?
rogerdeuce

Відповіді:


607

A view modelявляє собою дані, які ви хочете відобразити на вашому перегляді / сторінці, незалежно від того, використовуються вони для статичного тексту або для вхідних значень (наприклад, текстові поля та спадні списки), які можна додати до бази даних (або відредагувати). Це щось інше, ніж ваше domain model. Це модель для виду.

Скажімо, у вас є Employeeклас, який представляє модель домену вашого співробітника, і він містить такі властивості (унікальний ідентифікатор, ім'я, прізвище та дата створення):

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

     public string FirstName { get; set; }

     public string LastName { get; set; }

     public DateTime DateCreated { get; set; }
}

Моделі перегляду відрізняються від моделей домену тим, що моделі перегляду містять лише ті дані (представлені властивостями), які ви хочете використовувати у своєму представленні. Наприклад, скажімо, що ви хочете додати нову запис працівника, ваша модель перегляду може виглядати так:

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

     public string LastName { get; set; }
}

Як бачите, він містить лише два властивості. Ці два властивості також є в моделі домену працівника. Чому це ви можете запитати? Idможе не бути встановлено з подання, воно може бути автоматично створене таблицею працівника. А DateCreatedтакож може бути встановлено у збереженій процедурі або на рівні обслуговування вашої програми. Так Idі DateCreatedне потрібні у переглянутій моделі. Можливо, ви захочете відобразити ці дві властивості, коли ви бачите деталі працівника (працівника, який уже був захоплений) як статичний текст.

Під час завантаження перегляду / сторінки метод створення дії у контролері працівника створить екземпляр цієї моделі подання, при необхідності заповнить будь-які поля, а потім передасть цю модель подання на перегляд / сторінку:

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

Ваш погляд / сторінка може виглядати приблизно так (якщо ви користуєтесь ASP.NET MVCі механізмом Razorперегляду):

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

Таким чином, валідація проводиться лише на FirstNameта LastName. Використання FluentValidation у вас може бути перевірка, така як:

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

І з анотаціями даних це може виглядати так:

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

Ключовим, що слід пам’ятати, є те, що модель перегляду представляє лише ті дані, які ви хочете використовувати , нічого іншого. Ви можете уявити весь непотрібний код та перевірку, якщо у вас є модель домену з 30 властивостями, і ви хочете оновити лише одне значення. Враховуючи цей сценарій, у моделі перегляду ви мали б мати лише це одне значення / властивість, а не всі властивості, що знаходяться в об’єкті домену.

Модель перегляду може мати не лише дані з однієї таблиці бази даних. Він може поєднувати дані з іншої таблиці. Візьміть мій приклад вище щодо додавання нового запису працівника. Крім додавання лише імен та прізвищ, ви також можете додати відділ працівника. Цей список відділів буде надходити з вашого Departmentsстолу. Отже, тепер у вас є дані з таблиць Employeesта Departmentsтаблиць в одній моделі перегляду. Тоді вам потрібно буде додати наступні два властивості до вашої моделі перегляду та заповнити її даними:

public int DepartmentId { get; set; }

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

Під час редагування даних працівника (працівника, який уже додано до бази даних) він не сильно відрізнятиметься від мого прикладу вище. Створіть модель перегляду, назвіть її, наприклад EditEmployeeViewModel. У цій моделі перегляду є лише ті дані, які ви бажаєте редагувати, як-от ім’я та прізвище. Відредагуйте дані та натисніть кнопку подання. Я б не надто хвилювався про Idполе, оскільки Idзначення, ймовірно, було в URL-адресі, наприклад:

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

Візьміть це Idі перенесіть його до шару вашого сховища разом із значеннями вашого імені та прізвища.

Під час видалення запису я зазвичай дотримуюся того самого шляху, що і в моделі перегляду редагування. Я також мав би URL-адресу, наприклад:

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

Коли перегляд завантажується вперше, я отримаю дані працівника з бази даних за допомогою Idпункту 3. Я б просто відображав статичний текст на моєму перегляді / сторінці, щоб користувач міг бачити, якого співробітника видаляють. Коли користувач натискає кнопку «Видалити», я просто використовую Idзначення 3 і передаю його моєму шару сховища. Вам потрібно лише Idвидалити запис із таблиці.

Ще один момент: вам не дуже потрібна модель перегляду для кожної дії. Якщо це прості дані, то було б добре використовувати лише їх EmployeeViewModel. Якщо це складні перегляди / сторінки і вони відрізняються один від одного, то я б запропонував використовувати окремі моделі перегляду для кожного.

Я сподіваюся, що це очистить будь-яке непорозуміння, яке ви мали щодо перегляду моделей та моделей доменів.


5
@Kenny: Тоді покажіть це :) Що я намагався сказати, скажімо, у вас є модель домену з 50 властивостями, і ваш погляд повинен відображати лише 5, то це не має сенсу надсилати всі 50 властивостей просто на дисплей 5.
Brendan Фогт

5
@BrendanVogt - ви добре зробили це, пояснивши це, але я не розумію, яка вартість "відправлення всіх 50 об'єктів". Інший код вже створив об'єкт моделі, з усіма 50 властивостями, і це , здається , не варто підтримувати інший клас просто НЕ послати 45 властивостей - особливо , якщо ви , можливо , хочете відправити будь-яку з цих 45 об'єктів в майбутньому.
Кенні Евітт

5
@BrendanVogt - я думаю, можливо відповідь LukLed допомагає мені зрозуміти, чому вони можуть бути корисними, особливо, що ViewModel (може) "... поєднувати значення з різних об'єктів бази даних" [де я припускаю, що ця фраза є такою ж правдивою " Суб'єкти бази даних "замінити на" Модельні об'єкти "]. Але все ж, які конкретні проблеми планували вирішити ViewModels? Чи є у вас посилання? Я нічого не міг знайти. [І я прошу вибачення, якщо мені здається, що я тебе збираю!]
Кенні Евітт

1
Я щойно чув, як хтось каже, що ViewModels - це хороший спосіб надсилання декількох колекцій (або перехресних властивостей моделі) в єдиний вигляд, не вкладаючи їх у viewBag. Має сенс для мене.
Айяш

3
Вибачте за критичність, але ця відповідь, на жаль, неповна. Визначати модель перегляду як лише те, що вам потрібно відображати на своїй сторінці, це як запитання "Що таке машина?" та отримання відповіді "Це не літак". Ну це правда, але не дуже корисно. Більш правильне визначення VM - це "Все, що потрібно для візуалізації вашої сторінки". Якщо ви читаєте донизу, я виявив необхідні компоненти, щоб правильно та легко створити свій VM, у багатьох випадках використовуючи існуючі моделі домену та моделі презентації.
Сем

133

Модель перегляду - клас, який представляє модель даних, що використовується в конкретному представленні даних. Ми могли б використовувати цей клас як модель для сторінки входу:

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

За допомогою цієї моделі подання ви можете визначити вигляд (двигун перегляду Бритви):

@model CamelTrap.Models.ViewModels.LoginPageVM

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

І дії:

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

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

Що дає цей результат (екран знімається після надсилання форми, із повідомленнями про підтвердження):

Як бачите, модель перегляду має багато ролей:

  • Перегляд моделей документує подання, складаючи лише поля, які представлені у перегляді.
  • Переглянуті моделі можуть містити конкретні правила перевірки з використанням анотацій даних або IDataErrorInfo.
  • Подивитися модель визначає як вид повинен виглядати (для LabelFor, EditorFor, DisplayForхелперів).
  • Переглянуті моделі можуть комбінувати значення різних об'єктів бази даних.
  • Ви можете легко вказати шаблони відображення для моделей перегляду та повторно використовувати їх у багатьох місцях, використовуючи помічники DisplayFor або EditorFor.

Ще один приклад моделі перегляду та її пошуку: Ми хочемо відобразити основні дані користувача, його привілеї та ім’я користувачів. Ми створюємо спеціальну модель перегляду, яка містить лише необхідні поля. Ми отримуємо дані різних об'єктів із бази даних, але представлення відомо лише про клас моделі перегляду:

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

Отримання:

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
} 

Я тонкий user.Mother.FirstName + "" + user.Mother.LastName слід робити в View Model End. Вся логіка повинна бути виконана на кінці View Model.
Куркула

3
@Chandana: Я вважаю, що просте конкатенація може бути зроблено у моделі перегляду. Немає підстав виставляти два поля, якщо вони мають бути представлені разом.
LukLed

82

Редагувати: я оновив цю відповідь у своєму блозі:

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

Моя відповідь трохи тривала, але я думаю, що важливо порівняти переглянуті моделі з іншими типами часто використовуваних моделей, щоб зрозуміти, чому вони різні і чому вони потрібні.

Підбити підсумки та безпосередньо відповісти на поставлене питання:

Взагалі модель перегляду - це об'єкт, який містить усі властивості та методи, необхідні для надання представлення. Властивості перегляду моделі часто пов'язані з об'єктами даних, такими як клієнти та замовлення, а крім того, вони також містять властивості, пов’язані зі сторінкою або самою програмою, такі як ім'я користувача, ім'я програми тощо. створити сторінку HTML. Однією з багатьох причин використання моделі перегляду є те, що моделі перегляду надають спосіб тестування певних завдань презентації, таких як обробка вводу користувача, перевірка даних, отримання даних для відображення тощо.

Ось порівняння моделей Entity (а.ка. а.к. а.к. моделей), моделей презентації та моделей перегляду.

Об'єкти передачі даних, також "Модель"

Об'єкт передачі даних (DTO) - клас із властивостями, які відповідають схемі таблиці в базі даних. DTO називаються за їх загальне використання для передачі даних до та із сховища даних.
Характеристика DTO:

• чи є бізнес-об'єктами - їх визначення залежить від даних програми.

• Зазвичай містять лише властивості - немає коду.

• В основному використовується для транспортування даних до бази даних та з неї.

• Властивості точно або близько відповідають полям певної таблиці в сховищі даних.

Таблиці баз даних зазвичай нормалізуються, тому зазвичай також нормалізуються і DTO. Це робить їх обмеженим для представлення даних. Однак для певних простих структур даних вони часто роблять досить добре.

Ось два приклади того, як може виглядати 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; }
}

Презентаційні моделі

Модель презентації - клас утиліти, який використовується для візуалізації даних на екрані чи звіту. Моделі презентації зазвичай використовуються для моделювання складних структур даних, які складаються з даних з безлічі DTO. Моделі презентації часто представляють денормалізований вигляд даних.

Характеристика моделей презентації:

• чи є бізнес-об'єктами - їх визначення залежить від даних програми.

• В основному містять властивості. Код, як правило, обмежується форматуванням даних або перетворенням до DTO або з нього. Моделі презентації не повинні містити бізнес-логіки.

• Часто присутній денормалізований вигляд даних. Тобто вони часто поєднують властивості з декількох DTO.

• Часто містять властивості базового типу, ніж DTO. Наприклад, суми в доларах можуть бути представлені у вигляді рядків, щоб вони містили коми і символ валюти.

• Часто визначається способом їх використання, а також їх характеристиками об'єкта. Іншими словами, простий DTO, який використовується в якості резервної моделі для надання сітки, насправді є також презентаційною моделлю в контексті цієї сітки.

Моделі презентації використовуються "за потребою" та "там, де потрібно" (тоді як DTO зазвичай прив'язуються до схеми бази даних). Модель презентації може використовуватися для моделювання даних для всієї сторінки, сітки на сторінці або спадної сітки на сторінці. Моделі презентації часто містять властивості, що є іншими моделями презентації. Моделі презентацій часто будуються для цілей одноразового використання, таких як надання певної сітки на одній сторінці.

Приклад моделі презентації:

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

Перегляд моделей

Модель перегляду схожа на модель презентації в тому, що є резервним класом для надання подання. Однак вона дуже відрізняється від презентаційної моделі або DTO за способом її побудови. Переглянуті моделі часто містять ті самі властивості, що і презентаційні моделі та DTO, і тому їх часто плутають одна за іншою.

Характеристика моделей перегляду:

• Є єдиним джерелом даних, що використовуються для візуалізації сторінки чи екрана. Зазвичай це означає, що модель перегляду відкриє кожну властивість, яку потребує будь-який елемент керування на сторінці, щоб відобразити себе правильно. Перетворення моделі перегляду в єдине джерело даних для подання значно покращує її можливості та значення для тестування одиниць.

• являють собою складені об'єкти, що містять властивості, що складаються з даних програми, а також властивості, які використовуються кодом програми. Ця характеристика є визначальною при розробці моделі подання для повторного використання та обговорюється в прикладах нижче.

• Містить код програми. Моделі перегляду зазвичай містять методи, які викликаються під час надання та коли користувач взаємодіє зі сторінкою. Цей код зазвичай стосується обробки подій, анімації, видимості елементів управління, стилів тощо.

• Містить код, який викликає бізнес-послуги з метою отримання даних або надсилання їх на сервер бази даних. Цей код часто помилково розміщується в контролері. Виклик службових служб від контролера зазвичай обмежує корисність моделі перегляду для тестування одиниць. Щоб було зрозуміло, самі моделі перегляду не повинні містити ділової логіки, а повинні здійснювати дзвінки до служб, які містять бізнес-логіку.

• Часто містять властивості, які є іншими моделями перегляду для інших сторінок або екранів.

• Пишуться "на сторінку" або "на екран". Унікальна модель перегляду зазвичай пишеться для кожної сторінки чи екрана програми.

• Зазвичай походять із базового класу, оскільки більшість сторінок і екранів мають загальні властивості.

Переглянути склад моделі

Як було сказано раніше, моделі перегляду є складовими об'єктами, оскільки вони поєднують у собі властивості програми та властивості бізнес-даних на одному об’єкті. Прикладами часто використовуваних властивостей додатків, які використовуються на моделях перегляду, є:

• Властивості, які використовуються для відображення стану програми, такі як повідомлення про помилки, ім'я користувача, статус тощо.

• Властивості, які використовуються для форматування, відображення, стилізації чи анімації елементів керування.

• Властивості, використовувані для прив'язки даних, такі як об'єкти списку та властивості, що містять проміжні дані, які вводяться користувачем.

Наведені нижче приклади показують, чому складна природа моделей перегляду важлива і як ми можемо найкраще побудувати модель перегляду, яка є ефективною та багаторазовою.

Припустимо, ми пишемо веб-додаток. Однією з вимог дизайну програми є те, що на кожній сторінці повинні відображатися заголовок сторінки, ім’я користувача та ім'я програми. Якщо ми хочемо створити сторінку для відображення об’єкта замовлення презентації, ми можемо змінити модель презентації наступним чином:

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

Цей дизайн може працювати ... але що робити, якщо ми хочемо створити сторінку, на якій буде відображатися список замовлень? Властивості PageTitle, UserName та ApplicationName будуть повторені та стануть непростими для роботи. Крім того, що робити, якщо ми хочемо визначити певну логіку на рівні сторінки в конструкторі класу? Ми більше не можемо цього зробити, якщо створимо екземпляр для кожного замовлення, яке відображатиметься.

Склад над спадщиною

Ось спосіб ми можемо перекомпонувати модель презентації замовлення таким чином, щоб вона стала справжньою моделлю перегляду та була корисною для відображення одного об’єкта PresentationOrder або колекції об’єктів 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; }
}

Дивлячись на два вищевказані класи, ми бачимо, що один із способів думати про модель перегляду полягає в тому, що це модель презентації, яка містить іншу модель презентації як властивість. Модель презентації верхнього рівня (тобто модель перегляду) містить властивості, що мають відношення до сторінки чи програми, тоді як модель (властивість) презентації містить властивості, релевантні даним програми.

Ми можемо зробити наш крок на крок далі і створити базовий клас модельного виду, який можна використовувати не тільки для PresentationOrders, але і для будь-якого іншого класу:

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

Тепер ми можемо спростити наш PresentationOrderVM так:

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

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

Ми можемо зробити наш BaseViewModel ще більше використаним, зробивши його загальним:

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

Тепер наші впровадження не потребують:

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

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

2
Сам дякую !! це допомогло мені повністю зрозуміти багатогранну сутність, яка є: View-Model. Я студент коледжу, який просто вивчає архітектуру MVC, і це прояснило купу функціональних можливостей, які піддаються розробнику. Якби я міг, я поставив би зірку поруч з вашою відповіддю.
Chef_Code

1
@Sam "Моделі перегляду часто містять ті самі властивості, що і презентаційні моделі та DTO, і тому їх часто плутають одна за іншу." Це означає, що вони зазвичай використовуються замість моделей презентації, або вони містять моделі презентації / dtos?
Олександр Дерк

2
@AlexanderDerck Вони використовуються для різних цілей. Вони плутають одне за одним (помилково). Ні, зазвичай ви не будете використовувати модель преси замість моделі перегляду. Набагато більш поширеним є те, що VM "містить" модель презентації, тобто MyViewModel<MyPresModel>
Сем

2
@Sam Припустимо, що об'єкти моделі - це живі об'єкти, наприклад, нібернатні моделі .. тож маючи BusinessObject, чи не піддаємо ми модель / живі об’єкти безпосередньо перегляду? тобто бізнес-об’єкт можна використовувати для прямого зміни стану бази даних? Крім того, що з вкладеними моделями перегляду? Це вимагало б декількох властивостей бізнес-об’єкта, правда?
Мухаммед Алі

22

Якщо у вас є властивості, характерні для представлення даних, не пов’язані із сховищем даних DB / Service / Data, хорошою практикою є використання ViewModels. Скажімо, ви хочете залишити прапорець вибраний на основі поля DB (або двох), але саме поле DB не є булевим. Хоча ці властивості можна створити в самій Моделі та зберегти її прихованою від прив’язки до даних, можливо, ви не хочете захаращувати модель залежно від кількості таких полів та транзакцій.

Якщо даних та / або перетворень недостатньо мало, ви можете використовувати саму модель


19

Я не читав усіх публікацій, але, мабуть, у кожній відповіді відсутня одна концепція, яка справді допомогла мені "зрозуміти" ...

Якщо модель є спорідненою до бази даних таблиці , то ViewModel те саме бази даних View - Перегляд зазвичай або повертає невеликі обсяги даних з однієї таблиці, або складні набори даних з декількох таблиць (приєднується).

Я можу використовувати ViewModels для передачі інформації у представлення / форму, а потім передачу цих даних у дійсну модель, коли форма надсилається назад до контролера - також дуже зручно для зберігання списків (IEnumerable).


11

MVC не має моделі перегляду: вона має модель, перегляд та контролер. Модель перегляду є частиною MVVM (Model-View-Viewmodel). MVVM походить із презентаційної моделі та популяризується у WPF. У MVVM також повинна бути модель, але більшість людей повністю пропускають точку цього шаблону, і вони матимуть лише вигляд та модель перегляду. Модель у MVC схожа на модель у MVVM.

У MVC процес розділений на 3 різні обов'язки:

  • View несе відповідальність за представлення даних користувачеві
  • Контролер відповідає за потік сторінки
  • Модель відповідає за логіку бізнесу

MVC не дуже підходить для веб-додатків. Це шаблон, представлений Smalltalk для створення настільних додатків. Веб-середовище поводиться зовсім інакше. Немає сенсу копіювати 40-річну концепцію з розробки робочого столу та вставляти її у веб-середовище. Однак багато людей вважають, що це нормально, оскільки їх додаток збирає та повертає правильні значення. Тобто, на мою думку, недостатньо, щоб визначити певний вибір дизайну як нормальний.

Прикладом моделі у веб-додатку можуть бути:

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

Контролер може використовувати його так:

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

Ваші методи контролера та ваші моделі будуть невеликими, легко перевірятими і суттєвими.


Дякую за розуміння архітектури MVVM, але чому MVC не в порядку? Ваші міркування сумнівні та підозрювані у фаворитизмі. Зрозуміло, я нічого не знаю про MVVM, але якщо така архітектура, як MVC, може імітувати поведінку, не маючи писати 50k рядків коду, то яка велика справа?
Chef_Code

@Chef_Code: Це не сумнівно чи фаворитизм: просто прочитайте оригінальний документ про MVC. Повернутися до джерела набагато краще, ніж сліпо слідкувати за стадом без питань (він же "кращі практики"). MVC призначений для набагато менших одиниць: наприклад, кнопка на екрані складається з моделі, перегляду та контролера. У Web-MVC вся сторінка має контролер, модель та вигляд. Передбачається, що модель і погляд повинні бути пов'язані між собою, так що зміни в моделі негайно відображаються в погляді і навпаки. Імітація - дуже велика справа. Архітектура не повинна брехати розробникам.
Jeroen

1
@jeroen Акронім MVC був викрадений та розбещений. Так, MVC не має VM, але він також не має сховища або сервісного рівня, і ці об'єкти широко використовуються на веб-сайтах. Я вважаю, що ОП запитує "як мені ввести та використовувати VM в MVC". У новому значенні MVC модель не там, де належить бізнес-логіка. Бізнес-логіка належить до рівня обслуговування для Інтернету або настільного додатка, використовуючи MVC або MVVM. Термінова модель описує бізнес-об’єкти, які передаються в / із сервісного рівня. Ці визначення значно відрізняються від оригінального опису MVC.
Сем

1
@Sam Не все, що є частиною веб-сайту, можна назвати частиною MVC. Нового значення MVC немає. Є правильне значення і значення "щось абсолютно не пов'язане з тим, що люди плутають з MVC". Скажімо, що модель відповідає за логіку бізнесу, це не те саме, що ділова логіка закодована в моделі. Більшу частину часу модель виступає фасадом програми.
Jeroen

Основна вада, яку я бачу в MVC Microsoft - це блокування моделі з видом. Це саме перемагає цілі всього цього розмежування, що відбувалося в дизайні N-Tier за останні 20 років. Вони втратили наш час, змусивши нас використовувати "WebForms" у 2002 році, що було ще однією моделлю, натхненною Настільним ПК, піднятою на веб-світ. Тепер вони викинули це, але знову підняли ще одну настільну модель цієї нової парадигми для веб-розробників. Тим часом Google та інші створюють гігантські моделі на стороні клієнта, які все це розділяють. Я думаю, що старий ASP VBScript з 1998 року був їхньою справжньою системою веб-розробників.
Стоклей

11

Переглянути модель a - простий клас, який може містити більше одного властивості класу. Ми використовуємо його для успадкування всіх необхідних властивостей, наприклад, у мене є два класи Student і 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;}
}

Тепер ми хочемо відобразити Ім'я та Ім'я учня у Перегляді (В MVC), але додати більше одного класу, наприклад:

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

наведений вище код призведе до помилки ...

Тепер ми створюємо один клас і можемо давати йому будь-яке ім’я, але цей формат "XyzViewModel" полегшить розуміння. Це поняття спадкування. Тепер ми створюємо третій клас із такою назвою:

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

Тепер ми використовуємо цей ViewModel у View

@model ProjectName.Model.StudentViewModel

Тепер ми маємо доступ до всіх властивостей StudentViewModel та успадкованого класу у View.


10

Багато великих прикладів, дозвольте мені пояснити чітко і чітко.

ViewModel = Модель, створена для обслуговування представлення даних.

Перегляд ASP.NET MVC не може мати більше однієї моделі, тому якщо нам потрібно відобразити властивості з декількох моделей у вигляді, це неможливо. ViewModel служить цій цілі.

View Model - клас моделі, який може містити лише ті властивості, які необхідні для перегляду. Він також може містити властивості більш ніж однієї сутності (таблиці) бази даних. Як випливає з назви, ця модель створена специфічно для вимог View.

Нижче наведено кілька прикладів моделей перегляду

  • Для того, щоб перераховувати дані більш ніж сутностей на сторінці перегляду - ми можемо створити модель View і мати властивості всіх об'єктів, для яких ми хочемо перерахувати дані. Приєднайтеся до цих об'єктів бази даних та встановіть властивості Переглянути модель та поверніться до Перегляду, щоб відобразити дані різних сутностей в одній табличній формі
  • Модель перегляду може визначати лише конкретні поля однієї сутності, необхідні для представлення даних.

ViewModel також може використовуватися для вставки, оновлення записів у більш ніж одне ціле, однак основним використанням ViewModel є відображення стовпців з декількох об'єктів (модель) в одному представленні.

Спосіб створення ViewModel такий же, як і створення моделі, спосіб створення представлення для Viewmodel такий же, як створення подання для Model.

Ось невеликий приклад даних списку за допомогою ViewModel .

Сподіваюся, це стане в нагоді.


6

ViewModel - це вирішення проблеми, яке виправляє концептуальну незграбність рамки MVC. Він представляє 4-й шар в 3-шаровій архітектурі Model-View-Controller. коли Модель (модель домену) не підходить, занадто велика (більша, ніж 2-3 поля) для Перегляду, ми створюємо менший ViewModel, щоб передати його Перегляду.


1

Модель перегляду - це концептуальна модель даних. Його використання полягає в тому, щоб, наприклад, отримати підмножину або об'єднати дані з різних таблиць.

Можливо, вам потрібні лише певні властивості, тому це дозволяє завантажувати лише ті, а не додаткові непотрібні властивості


1
  • ViewModel містить поля, представлені у поданні (для помічників LabelFor, EditorFor, DisplayFor)
  • ViewModel може мати конкретні правила перевірки, використовуючи анотації даних або IDataErrorInfo.
  • ViewModel може мати кілька об'єктів або об'єктів з різних моделей даних або джерела даних.

Проектування 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; } 
} 

Представлення моделі перегляду у поданні

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

Робота з дією

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. У ViewModel помістіть лише ті поля / дані, які ви хочете відобразити на перегляді / сторінці.
  2. Оскільки перегляд репрезентує властивості ViewModel, отже, це легко для візуалізації та обслуговування.
  3. Використовуйте картограф, коли ViewModel стає складнішим.

1

Модель View - це клас, який ми можемо використовувати для візуалізації даних у View. Припустимо, у вас є дві сутності Place і PlaceCategory, і ви хочете отримати доступ до даних обох об'єктів за допомогою однієї моделі, тоді ми використовуємо 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; }
    }

Отже, вище Приклад Місце і Категорія - це два різних об'єкти, а Модель перегляду PlaceCategory - це ViewModel, який ми можемо використовувати у View.


Ваші приклади не так зрозумілі. Що було сказано вище, це те, що ViewModel з'єднує дані з його представленням. Якщо ви подивитеся на ViewModels в BlipAjax, ви побачите класи, які ідеально підходять для цього.
Герман Ван дер Блом

0

Якщо ви хочете вивчити код, як налаштувати веб-додаток "Baseline" за допомогою ViewModels, я можу порадити завантажити цей код на GitHub: https://github.com/ajsaulsberry/BlipAjax . Я розробив великі додатки для підприємств. Після цього проблематично налаштувати хорошу архітектуру, яка б обробляла всю цю функцію "ViewModel". Я думаю, що з BlipAjax у вас буде дуже хороша «базова лінія» для початку. Це просто простий веб-сайт, але чудовий своєю простотою. Мені подобається те, як вони використовували англійську мову, щоб вказати на те, що дійсно потрібно в додатку.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.