Apa itu ViewModel di MVC?

429

Saya baru mengenal ASP.NET MVC. Saya memiliki masalah dengan memahami tujuan Model View.

Apa itu ViewModel dan mengapa kita membutuhkan ViewModel untuk Aplikasi ASP.NET MVC?

Jika saya mendapatkan contoh yang bagus tentang cara kerjanya dan penjelasannya, itu akan lebih baik.

unik
sumber
4
Posting ini adalah apa yang Anda cari - "Apa itu ViewModel ASP.NET MVC?"
Yusubov
6
Artikel ini terlihat hebat: rachelappel.com/...
Andrew
kemungkinan duplikat Dalam MVC, apa itu ViewModel?
rogerdeuce

Jawaban:

607

A view modelmewakili data yang ingin Anda tampilkan pada tampilan / halaman Anda, apakah itu digunakan untuk teks statis atau untuk nilai input (seperti kotak teks dan daftar dropdown) yang dapat ditambahkan ke database (atau diedit). Itu adalah sesuatu yang berbeda dari Anda domain model. Ini adalah model untuk tampilan.

Katakanlah Anda memiliki Employeekelas yang mewakili model domain karyawan Anda dan berisi properti berikut (pengidentifikasi unik, nama depan, nama belakang, dan tanggal dibuat):

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

     public string FirstName { get; set; }

     public string LastName { get; set; }

     public DateTime DateCreated { get; set; }
}

Model tampilan berbeda dari model domain karena model tampilan hanya berisi data (diwakili oleh properti) yang ingin Anda gunakan pada tampilan Anda. Misalnya, katakanlah Anda ingin menambahkan catatan karyawan baru, model tampilan Anda mungkin terlihat seperti ini:

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

     public string LastName { get; set; }
}

Seperti yang Anda lihat, hanya berisi dua properti. Kedua properti ini juga ada dalam model domain karyawan. Mengapa ini yang Anda tanyakan? Idmungkin tidak diatur dari tampilan, mungkin dibuat secara otomatis oleh tabel Karyawan. Dan DateCreatedmungkin juga diatur dalam prosedur tersimpan atau di lapisan layanan aplikasi Anda. Jadi Iddan DateCreatedtidak diperlukan dalam model tampilan. Anda mungkin ingin menampilkan dua properti ini ketika Anda melihat detail karyawan (karyawan yang sudah ditangkap) sebagai teks statis.

Saat memuat tampilan / halaman, metode buat tindakan di pengontrol karyawan Anda akan membuat instance dari model tampilan ini, mengisi setiap bidang jika diperlukan, dan kemudian meneruskan model tampilan ini ke tampilan / halaman:

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

Tampilan / halaman Anda mungkin terlihat seperti ini (dengan asumsi Anda menggunakan ASP.NET MVCdan Razormesin tampilan):

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

Validasi akan dilakukan hanya pada FirstNamedan LastName. Menggunakan FluentValidation Anda mungkin memiliki validasi seperti ini:

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

Dan dengan Anotasi Data, tampilannya mungkin seperti ini:

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

Hal utama yang perlu diingat adalah bahwa model tampilan hanya mewakili data yang ingin Anda gunakan , tidak ada yang lain. Anda dapat membayangkan semua kode dan validasi yang tidak perlu jika Anda memiliki model domain dengan 30 properti dan Anda hanya ingin memperbarui nilai tunggal. Dengan skenario ini, Anda hanya akan memiliki satu nilai / properti ini dalam model tampilan dan tidak semua properti yang ada di objek domain.

Model tampilan mungkin tidak hanya memiliki data dari satu tabel database. Itu dapat menggabungkan data dari tabel lain. Ambil contoh saya di atas tentang menambahkan catatan karyawan baru. Selain menambahkan hanya nama depan dan belakang Anda mungkin juga ingin menambahkan departemen karyawan. Daftar departemen ini akan datang dari Departmentsmeja Anda . Jadi sekarang Anda memiliki data dari Employeesdan Departmentstabel dalam satu model tampilan. Anda hanya perlu menambahkan dua properti berikut ke model tampilan Anda dan mengisinya dengan data:

public int DepartmentId { get; set; }

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

Saat mengedit data karyawan (karyawan yang telah ditambahkan ke database) itu tidak akan jauh berbeda dari contoh saya di atas. Buat model tampilan, sebut saja misalnya EditEmployeeViewModel. Hanya memiliki data yang ingin Anda edit dalam model tampilan ini, seperti nama depan dan nama belakang. Edit data dan klik tombol kirim. Saya tidak akan terlalu khawatir tentang Idbidang ini karena Idnilainya mungkin ada di URL, misalnya:

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

Ambil ini Iddan meneruskannya ke lapisan repositori Anda, bersama dengan nama depan dan nilai nama belakang Anda.

Saat menghapus catatan, saya biasanya mengikuti jalur yang sama seperti dengan model tampilan edit. Saya juga akan memiliki URL, misalnya:

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

Ketika tampilan memuat untuk pertama kalinya saya akan mendapatkan data karyawan dari database menggunakan Iddari 3. Saya kemudian hanya akan menampilkan teks statis pada tampilan / halaman saya sehingga pengguna dapat melihat karyawan apa yang sedang dihapus. Ketika pengguna mengklik tombol Delete, saya hanya akan menggunakan Idnilai 3 dan meneruskannya ke lapisan repositori saya. Anda hanya perlu Idmenghapus catatan dari tabel.

Poin lain, Anda tidak benar-benar membutuhkan model tampilan untuk setiap tindakan. Jika ini adalah data sederhana maka tidak apa-apa hanya digunakan EmployeeViewModel. Jika tampilan / halaman rumit dan berbeda satu sama lain maka saya sarankan Anda menggunakan model tampilan terpisah untuk masing-masing.

Saya harap ini menghapus semua kebingungan yang Anda miliki tentang model tampilan dan model domain.

Brendan Vogt
sumber
5
@ Kenny: Lalu perlihatkan :) Apa yang saya coba katakan adalah katakanlah Anda memiliki model domain dengan 50 properti dan tampilan Anda hanya perlu menampilkan 5 maka tidak ada gunanya mengirimkan semua 50 properti hanya untuk menampilkan 5.
Brendan Vogt
5
@ BrendanVogt - Anda melakukan pekerjaan dengan baik menjelaskan hal itu, tapi saya tidak mengerti berapa biayanya untuk "mengirim semua 50 properti". Kode lain telah membuat objek Model, dengan semua 50 properti, dan sepertinya tidak ada gunanya mempertahankan kelas lain hanya dengan tidak mengirim 45 properti - terutama jika Anda mungkin ingin mengirim salah satu dari 45 properti itu di masa mendatang.
Kenny Evitt
5
@ BrendanVogt - Saya pikir mungkin jawaban LukLed membantu saya memahami mengapa ini mungkin berguna, terutama bahwa ViewModel (bisa) "... menggabungkan nilai dari entitas basis data yang berbeda" [di mana saya mengasumsikan bahwa frasa sama benarnya adalah " entitas basis data "akan diganti dengan" Model object "]. Tapi tetap saja, masalah apa yang dimaksudkan ViewModels untuk atasi? Apakah Anda memiliki tautan? Saya sendiri tidak dapat menemukan apa pun. [Dan saya minta maaf jika saya tampaknya memilih Anda!]
Kenny Evitt
1
Saya baru saja mendengar seseorang mengatakan bahwa ViewModels adalah cara yang baik untuk mengirim banyak koleksi (atau lintas model properti) ke dalam satu tampilan tanpa harus memasukkannya ke dalam viewBag. Masuk akal bagi saya.
Ayyash
3
Maaf karena kritis tetapi jawaban ini, sayangnya, tidak lengkap. Menentukan model tampilan hanya sebagai apa yang perlu Anda tampilkan di halaman Anda seperti bertanya "Apa itu mobil?" dan menerima jawaban "Ini bukan pesawat terbang". Yah, itu benar tetapi tidak terlalu membantu. Definisi VM yang lebih tepat adalah "Semua yang Anda butuhkan untuk merender halaman Anda." Jika Anda membaca sampai ke bawah saya telah mengidentifikasi komponen yang Anda butuhkan untuk membangun VM Anda dengan benar dan mudah, dalam banyak kasus meningkatkan model domain dan model presentasi yang ada.
Sam
133

Lihat model adalah kelas yang mewakili model data yang digunakan dalam tampilan tertentu. Kita bisa menggunakan kelas ini sebagai model untuk halaman 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; }
}

Menggunakan model tampilan ini, Anda dapat menentukan tampilan (Razor view engine):

@model CamelTrap.Models.ViewModels.LoginPageVM

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

Dan tindakan:

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

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

Yang menghasilkan hasil ini (layar diambil setelah mengirimkan formulir, dengan pesan validasi):

Seperti yang Anda lihat, model tampilan memiliki banyak peran:

  • Lihat model mendokumentasikan tampilan dengan hanya terdiri bidang, yang diwakili dalam tampilan.
  • Lihat model dapat berisi aturan validasi spesifik menggunakan anotasi data atau IDataErrorInfo.
  • Model tampilan mendefinisikan bagaimana tampilan harus melihat (untuk LabelFor, EditorFor, DisplayForpembantu).
  • Lihat model dapat menggabungkan nilai dari entitas basis data yang berbeda.
  • Anda dapat menentukan template tampilan dengan mudah untuk model tampilan dan menggunakannya kembali di banyak tempat menggunakan bantuan DisplayFor atau EditorFor.

Contoh lain dari model tampilan dan pengambilannya: Kami ingin menampilkan data pengguna dasar, hak-hak istimewanya, dan nama pengguna. Kami membuat model tampilan khusus, yang hanya berisi bidang yang diperlukan. Kami mengambil data dari entitas yang berbeda dari basis data, tetapi tampilan hanya mengetahui kelas model tampilan:

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

Pengambilan:

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
} 
LukLed
sumber
Saya menipis user.Mother.FirstName + "" + user.Mother.LastName harus dilakukan di View Model End. Semua Logika harus dilakukan pada Lihat Model akhir.
Kurkula
3
@ Chandana: Saya percaya rangkaian sederhana dapat dilakukan dalam model tampilan. Tidak ada alasan untuk mengekspos dua bidang, jika mereka dimaksudkan untuk disajikan bersama.
LukLed
82

Sunting: Saya memperbarui jawaban ini di Blog saya:

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

Jawaban saya agak panjang tapi saya pikir penting untuk membandingkan model tampilan dengan tipe lain dari model yang umum digunakan untuk memahami mengapa mereka berbeda dan mengapa mereka diperlukan.

Untuk meringkas, dan untuk langsung menjawab pertanyaan yang ditanyakan:

Secara umum, model tampilan adalah objek yang berisi semua properti dan metode yang diperlukan untuk membuat tampilan. Lihat model properti sering terkait dengan objek data seperti pelanggan dan pesanan dan di samping itu mereka juga berisi properti yang terkait dengan halaman atau aplikasi itu sendiri seperti nama pengguna, nama aplikasi dll. Lihat model menyediakan objek yang nyaman untuk diteruskan ke mesin rendering untuk buat halaman html. Salah satu dari banyak alasan untuk menggunakan model tampilan adalah bahwa model tampilan menyediakan cara untuk menguji unit tugas presentasi tertentu seperti menangani input pengguna, memvalidasi data, mengambil data untuk ditampilkan, dll.

Berikut adalah perbandingan model Entity (model a.ka. DTO), Model Presentasi, dan Model Tampilan.

Objek Transfer Data alias “Model”

Objek Transfer Data (DTO) adalah kelas dengan properti yang cocok dengan skema tabel dalam database. DTO dinamai untuk penggunaan umum mereka untuk bolak-balik data ke dan dari penyimpanan data.
Karakteristik DTO:

• Apakah objek bisnis - definisi mereka bergantung pada data aplikasi.

• Biasanya hanya berisi properti - tanpa kode.

• Terutama digunakan untuk mengangkut data ke dan dari database.

• Properti persis atau sangat cocok dengan bidang pada tabel tertentu di penyimpanan data.

Tabel database biasanya dinormalisasi oleh karena itu DTO biasanya dinormalisasi juga. Ini membuat mereka terbatas digunakan untuk menyajikan data. Namun, untuk struktur data sederhana tertentu mereka sering melakukannya dengan cukup baik.

Berikut adalah dua contoh bagaimana DTO akan terlihat:

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

Model Presentasi

Model presentasi adalah kelas utilitas yang digunakan untuk menyajikan data di layar atau laporan. Model presentasi biasanya digunakan untuk memodelkan struktur data kompleks yang terdiri dari data dari beberapa DTO. Model presentasi sering mewakili tampilan data yang didenormalisasi.

Karakteristik Model Presentasi:

• Apakah objek bisnis - definisi mereka bergantung pada data aplikasi.

• Mengandung sebagian besar properti. Kode biasanya terbatas pada memformat data atau mengonversi ke atau dari DTO. Model Presentasi tidak boleh mengandung logika bisnis.

• Sering menyajikan tampilan data yang didenormalisasi. Artinya, mereka sering menggabungkan properti dari beberapa DTO.

• Sering berisi properti dengan tipe dasar berbeda dari DTO. Misalnya jumlah dolar dapat direpresentasikan sebagai string sehingga mereka dapat mengandung koma dan simbol mata uang.

• Sering didefinisikan oleh bagaimana mereka digunakan serta karakteristik objek mereka. Dengan kata lain, DTO sederhana yang digunakan sebagai model pendukung untuk membuat kisi sebenarnya juga merupakan model presentasi dalam konteks kisi itu.

Model presentasi digunakan "sesuai kebutuhan" dan "di mana diperlukan" (sedangkan DTO biasanya terkait dengan skema database). Model presentasi dapat digunakan untuk memodelkan data untuk seluruh halaman, kisi pada halaman, atau dropdown pada kisi pada halaman. Model presentasi sering berisi properti yang merupakan model presentasi lainnya. Model presentasi sering dibangun untuk tujuan penggunaan tunggal seperti untuk membuat grid tertentu pada satu halaman.

Contoh model presentasi:

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

Lihat Model

Model tampilan mirip dengan model presentasi di yang merupakan kelas dukungan untuk rendering tampilan. Namun sangat berbeda dari Model Presentasi atau DTO dalam hal bagaimana itu dibangun. Lihat model sering mengandung sifat yang sama seperti model presentasi dan DTO dan karena alasan ini mereka sering bingung satu sama lain.

Karakteristik Model Tampilan:

• Apakah satu-satunya sumber data yang digunakan untuk membuat halaman atau layar. Biasanya ini berarti bahwa model tampilan akan mengekspos setiap properti yang setiap kontrol pada halaman perlu render dengan benar. Menjadikan model tampilan sumber tunggal data untuk tampilan sangat meningkatkan kemampuan dan nilainya untuk pengujian unit.

• Apakah objek komposit yang berisi properti yang terdiri dari data aplikasi serta properti yang digunakan oleh kode aplikasi. Karakteristik ini sangat penting ketika merancang model tampilan untuk dapat digunakan kembali dan dibahas dalam contoh di bawah ini.

• Berisi kode aplikasi. Lihat Model biasanya berisi metode yang dipanggil saat rendering dan ketika pengguna berinteraksi dengan halaman. Kode ini biasanya terkait dengan penanganan acara, animasi, visibilitas kontrol, gaya, dll.

• Berisi kode yang memanggil layanan bisnis untuk tujuan mengambil data atau mengirimkannya ke server database. Kode ini sering keliru ditempatkan di sebuah pengontrol. Memanggil layanan bisnis dari pengontrol biasanya membatasi kegunaan model tampilan untuk pengujian unit. Agar jelas, lihat model itu sendiri tidak boleh mengandung logika bisnis tetapi harus membuat panggilan ke layanan yang memang mengandung logika bisnis.

• Sering berisi properti yang merupakan model tampilan lain untuk halaman atau layar lain.

• Ditulis "per halaman" atau "per layar". Model Tampilan yang unik biasanya ditulis untuk setiap halaman atau layar dalam suatu aplikasi.

• Biasanya berasal dari kelas dasar karena sebagian besar halaman dan layar berbagi properti umum.

Lihat Komposisi Model

Seperti yang dinyatakan sebelumnya, model tampilan adalah objek komposit yang menggabungkan properti aplikasi dan properti data bisnis pada objek tunggal. Contoh properti aplikasi yang umum digunakan yang digunakan pada model tampilan adalah:

• Properti yang digunakan untuk menampilkan status aplikasi seperti pesan kesalahan, nama pengguna, status, dll.

• Properti yang digunakan untuk memformat, menampilkan, menyesuaikan dgn mode, atau menghidupkan animasi.

• Properti yang digunakan untuk pengikatan data seperti objek daftar dan properti yang menyimpan data antara yang diinput oleh pengguna.

Contoh berikut menunjukkan mengapa sifat komposit dari model tampilan adalah penting dan bagaimana kita dapat membangun Model Tampilan yang paling efisien dan dapat digunakan kembali.

Asumsikan kita sedang menulis aplikasi web. Salah satu persyaratan desain aplikasi adalah bahwa judul halaman, nama pengguna, dan nama aplikasi harus ditampilkan pada setiap halaman. Jika kami ingin membuat halaman untuk menampilkan objek urutan presentasi, kami dapat memodifikasi model presentasi sebagai berikut:

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

Desain ini mungkin berfungsi ... tetapi bagaimana jika kita ingin membuat halaman yang akan menampilkan daftar pesanan? Properti PageTitle, UserName, dan ApplicationName akan diulang dan menjadi sulit untuk digunakan. Juga, bagaimana jika kita ingin mendefinisikan beberapa logika level-halaman dalam konstruktor kelas? Kami tidak dapat lagi melakukannya jika kami membuat instance untuk setiap pesanan yang akan ditampilkan.

Komposisi atas warisan

Berikut adalah cara kami mem-ulang faktor model presentasi urutan sehingga menjadi model tampilan sebenarnya dan akan berguna untuk menampilkan objek PresentationOrder tunggal atau koleksi objek 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; }
}

Melihat dua kelas di atas kita dapat melihat bahwa salah satu cara untuk berpikir tentang model tampilan adalah bahwa itu adalah model presentasi yang berisi model presentasi lain sebagai properti. Model presentasi tingkat atas (yaitu model tampilan) berisi properti yang relevan dengan halaman atau aplikasi sementara model presentasi (properti) berisi properti yang relevan dengan data aplikasi.

Kami dapat mengambil desain kami selangkah lebih maju dan membuat kelas model tampilan dasar yang dapat digunakan tidak hanya untuk PresentationOrders, tetapi untuk kelas lainnya juga:

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

Sekarang kita dapat menyederhanakan PresentationOrderVM kita seperti ini:

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

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

Kita dapat membuat BaseViewModel kita bahkan lebih dapat digunakan kembali dengan membuatnya generik:

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

Sekarang implementasi kami sangat mudah:

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

public class PresentationOrderVM : BaseViewModel<List<PresentationOrder>>
{
    // done!
}
Sam
sumber
2
Sam, terima kasih !! ini membantu saya memahami sepenuhnya entitas multi-faceted yaitu: View-Model. Saya seorang mahasiswa baru belajar arsitektur MVC, dan ini menjelaskan banyak fungsi yang mampu yang terkena pengembang. Jika saya bisa, saya akan meletakkan bintang di sebelah jawaban Anda.
Chef_Code
1
@ Sam 'Lihat model sering mengandung properti yang sama dengan model presentasi dan DTO dan karena alasan ini mereka sering bingung satu sama lain.' Apakah itu berarti mereka lebih umum digunakan daripada model presentasi, atau mereka dimaksudkan untuk mengandung model presentasi / dtos?
Alexander Derck
2
@AlexanderDerck Mereka digunakan untuk tujuan yang berbeda. Mereka bingung satu sama lain (salah). Tidak, Anda biasanya tidak akan menggunakan model pres sebagai pengganti model tampilan. Jauh lebih umum adalah bahwa VM "berisi" model presentasi yaitu MyViewModel<MyPresModel>
Sam
2
@ Sam Menganggap objek model adalah objek hidup misalnya model nhibernate .. jadi dengan memiliki BusinessObject bukankah kita mengekspos model / objek langsung ke tampilan? yaitu objek bisnis dapat digunakan untuk mengubah keadaan basis data secara langsung? Juga, bagaimana dengan model tampilan bersarang? Itu akan membutuhkan beberapa properti objek bisnis, bukan?
Muhammad Ali
22

Jika Anda memiliki properti khusus untuk tampilan, dan tidak terkait dengan toko DB / Layanan / Data, itu adalah praktik yang baik untuk menggunakan ViewModels. Katakanlah, Anda ingin meninggalkan kotak centang yang dipilih berdasarkan bidang DB (atau dua) tetapi bidang DB itu sendiri bukan boolean. Meskipun dimungkinkan untuk membuat properti ini dalam Model itu sendiri dan tetap menyembunyikannya dari pengikatan data, Anda mungkin tidak ingin mengacaukan Model tergantung pada jumlah bidang dan transaksi tersebut.

Jika ada terlalu sedikit data khusus tampilan dan / atau transformasi, Anda dapat menggunakan Model itu sendiri

fozylet
sumber
19

Saya tidak membaca semua posting tetapi setiap jawaban sepertinya tidak ada satu konsep yang benar-benar membantu saya "mengerti" ...

Jika Model mirip dengan Tabel database , maka Model View serupa dengan tampilan database - Tampilan biasanya mengembalikan sejumlah kecil data dari satu tabel, atau, kumpulan data yang kompleks dari beberapa tabel (bergabung).

Saya menemukan diri saya menggunakan ViewModels untuk mengirimkan info ke tampilan / formulir, dan kemudian mentransfer data itu ke dalam Model yang valid ketika formulir posting kembali ke controller - juga sangat berguna untuk menyimpan Daftar (IEnumerable).

halfacreSal
sumber
11

MVC tidak memiliki viewmodel: ia memiliki model, tampilan dan pengontrol. Model tampilan adalah bagian dari MVVM (Model-View-Viewmodel). MVVM berasal dari Model Presentasi dan dipopulerkan di WPF. Seharusnya juga ada model dalam MVVM, tetapi kebanyakan orang kehilangan titik dari pola itu sepenuhnya dan mereka hanya akan memiliki pandangan dan model tampilan. Model dalam MVC mirip dengan model dalam MVVM.

Dalam MVC proses ini dibagi menjadi 3 tanggung jawab yang berbeda:

  • Lihat bertanggung jawab untuk menyajikan data kepada pengguna
  • Kontroler bertanggung jawab atas aliran halaman
  • Model bertanggung jawab atas logika bisnis

MVC tidak terlalu cocok untuk aplikasi web. Ini adalah pola yang diperkenalkan oleh Smalltalk untuk membuat aplikasi desktop. Lingkungan web berperilaku sangat berbeda. Tidak masuk akal untuk menyalin konsep 40 tahun dari pengembangan desktop dan menempelkannya ke lingkungan web. Namun banyak orang berpikir ini ok, karena aplikasi mereka mengkompilasi dan mengembalikan nilai yang benar. Itu, menurut pendapat saya, tidak cukup untuk menyatakan pilihan desain tertentu sebagai ok.

Contoh model dalam aplikasi web dapat:

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

Pengontrol dapat menggunakannya seperti ini:

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

Metode pengontrol dan model Anda akan kecil, mudah diuji dan to the point.

Jeroen
sumber
Terima kasih atas wawasan arsitektur MVVM, tetapi mengapa MVC tidak baik-baik saja? Alasan Anda dipertanyakan dan mencurigai favoritisme. Memang saya tidak tahu apa-apa tentang MVVM, tetapi jika arsitektur seperti MVC dapat meniru perilaku tanpa harus menulis 50k baris kode, lalu apa masalahnya?
Chef_Code
@Chef_Code: Tidak perlu dipertanyakan atau favoritisme: baca saja tulisan asli tentang MVC. Kembali ke sumbernya jauh lebih baik daripada membabi buta mengikuti kawanan tanpa pertanyaan (alias "praktik terbaik"). MVC dimaksudkan untuk unit yang jauh lebih kecil: misalnya tombol pada layar terdiri dari model, tampilan, dan pengontrol. Di Web-MVC seluruh halaman memiliki pengontrol, model dan tampilan. Model dan tampilan seharusnya terhubung, sehingga perubahan dalam model segera tercermin dalam tampilan dan sebaliknya. Meniru adalah masalah yang sangat besar. Arsitektur seharusnya tidak berbohong kepada pengembangnya.
Jeroen
1
@ Joeroen Akronim MVC telah dicuri dan dihancurkan. Ya MVC tidak memiliki VM tetapi juga tidak memiliki Repositori atau lapisan layanan dan objek-objek tersebut banyak digunakan di situs web. Saya percaya OP bertanya "bagaimana cara memperkenalkan dan menggunakan VM di MVC". Dalam arti baru MVC model bukanlah tempat logika bisnis berada. Logika bisnis termasuk dalam lapisan layanan untuk web atau aplikasi desktop menggunakan MVC atau MVVM. Model jangka menjelaskan objek bisnis yang diteruskan ke / dari lapisan layanan. Definisi-definisi ini sangat berbeda dari deskripsi asli MVC.
Sam
1
@ Sam Tidak semua yang merupakan bagian dari situs web, dapat disebut sebagai bagian dari MVC. Tidak ada arti baru dari MVC. Ada makna yang benar dan "sesuatu yang sama sekali tidak berhubungan yang orang bingung dengan MVC" - artinya. Mengatakan bahwa model bertanggung jawab atas logika bisnis, tidak sama dengan logika bisnis yang dikodekan dalam model. Sebagian besar waktu model bertindak sebagai fasad ke aplikasi.
Jeroen
Kelemahan utama yang saya lihat di MVC Microsoft adalah penguncian Model dengan Tampilan. Itu sendiri mengalahkan seluruh tujuan dari semua pemisahan yang telah terjadi dalam desain N-Tier selama 20 tahun terakhir. Mereka membuang-buang waktu kami memaksa kami untuk menggunakan "WebForms" pada tahun 2002 yang merupakan model lain yang terinspirasi Desktop mengangkat ke Dunia Web. Sekarang mereka sudah membuang itu tetapi mengangkat model desktop lain pada paradigma baru ini untuk web dev. Sementara itu Google dan lainnya sedang membangun model sisi klien raksasa yang memisahkan semuanya. Saya berpikir ASP VBScript lama dari tahun 1998 adalah sistem web dev yang paling benar.
Stokely
11

Lihat model a adalah kelas sederhana yang dapat berisi lebih dari satu properti kelas. Kami menggunakannya untuk mewarisi semua properti yang diperlukan, misalnya saya punya dua kelas Siswa dan Subjek

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

Sekarang kami ingin menampilkan catatan Nama siswa dan Nama Subjek dalam Tampilan (Dalam MVC), tetapi tidak mungkin menambahkan lebih dari satu kelas seperti:

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

kode di atas akan menimbulkan kesalahan ...

Sekarang kita membuat satu kelas dan dapat memberikannya nama apa pun, tetapi format ini "XyzViewModel" akan membuatnya lebih mudah untuk dipahami. Itu adalah konsep warisan. Sekarang kita membuat kelas ketiga dengan nama berikut:

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

Sekarang kita menggunakan ViewModel ini dalam Tampilan

@model ProjectName.Model.StudentViewModel

Sekarang kita dapat mengakses semua properti StudentViewModel dan kelas bawaan di View.

Mayank
sumber
10

Banyak contoh besar, izinkan saya menjelaskan dengan cara yang jelas dan renyah.

ViewModel = Model yang dibuat untuk melayani tampilan.

Tampilan ASP.NET MVC tidak dapat memiliki lebih dari satu model sehingga jika kita perlu menampilkan properti dari lebih dari satu model ke tampilan, itu tidak mungkin. ViewModel melayani tujuan ini.

View Model adalah kelas model yang hanya bisa menampung properti-properti yang diperlukan untuk tampilan. Itu juga dapat berisi properti dari lebih dari satu entitas (tabel) dari database. Seperti namanya, model ini dibuat khusus untuk persyaratan Lihat.

Beberapa contoh Model Tampilan ada di bawah ini

  • Untuk membuat daftar data dari lebih dari entitas di halaman tampilan - kita dapat membuat model Lihat dan memiliki properti dari semua entitas yang ingin kita daftarkan data. Bergabunglah dengan entitas basis data tersebut dan atur properti model View dan kembali ke View untuk menampilkan data entitas yang berbeda dalam satu bentuk tabel
  • Model tampilan hanya dapat mendefinisikan bidang spesifik dari satu entitas yang diperlukan untuk tampilan.

ViewModel juga dapat digunakan untuk menyisipkan, memperbarui catatan ke lebih dari satu entitas namun penggunaan utama ViewModel adalah untuk menampilkan kolom dari banyak entitas (model) ke dalam satu tampilan.

Cara membuat ViewModel sama dengan membuat Model, cara membuat tampilan untuk Viewmodel sama dengan membuat tampilan untuk Model.

Berikut adalah contoh kecil dari data Daftar menggunakan ViewModel .

Semoga ini bermanfaat.

Sheo Narayan
sumber
6

ViewModel adalah solusi yang menambal kecanggungan konseptual kerangka kerja MVC. Ini mewakili lapisan ke-4 dalam arsitektur Model-View-Controller 3-lapisan. ketika Model (model domain) tidak sesuai, terlalu besar (lebih besar dari 2-3 bidang) untuk Tampilan, kami membuat Model View yang lebih kecil untuk meneruskannya ke Tampilan.

gsivanov
sumber
1

Model tampilan adalah model data konseptual. Penggunaannya adalah misalnya mendapatkan subset atau menggabungkan data dari tabel yang berbeda.

Anda mungkin hanya menginginkan properti tertentu, jadi ini memungkinkan Anda untuk hanya memuatnya dan bukan properti yang tidak perlu tambahan


sumber
1
  • ViewModel berisi bidang yang diwakili dalam tampilan (untuk pembantu LabelFor, EditorFor, DisplayFor)
  • ViewModel dapat memiliki aturan validasi spesifik menggunakan anotasi data atau IDataErrorInfo.
  • ViewModel dapat memiliki banyak entitas atau objek dari berbagai model data atau sumber data.

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

Menampilkan model tampilan dalam tampilan

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

Bekerja dengan Aksi

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. Di ViewModel, taruh hanya bidang / data yang ingin Anda tampilkan pada tampilan / halaman.
  2. Karena view merupakan properti dari ViewModel, maka mudah untuk rendering dan pemeliharaan.
  3. Gunakan mapper ketika ViewModel menjadi lebih kompleks.
pembuat kode liar
sumber
1

View Model adalah kelas yang bisa kita gunakan untuk merender data pada View. Misalkan Anda memiliki dua entitas Place dan PlaceCategory dan Anda ingin mengakses data dari kedua entitas menggunakan model tunggal maka kami menggunakan 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; }
    }

Jadi pada Contoh Tempat dan Kategori di atas adalah dua entitas yang berbeda dan viewModel PlaceCategory adalah ViewModel yang dapat kita gunakan pada View.

Sagar Shinde
sumber
Contoh Anda tidak begitu jelas. Apa yang dinyatakan di atas adalah bahwa ViewModel menghubungkan data ke pandangannya. Jika Anda melihat ViewModels di BlipAjax Anda melihat kelas yang sangat cocok untuk itu.
Herman Van Der Blom
0

Jika Anda ingin mempelajari kode cara mengatur aplikasi web "Baseline" dengan ViewModels, saya dapat menyarankan untuk mengunduh kode ini di GitHub: https://github.com/ajsaulsberry/BlipAjax . Saya mengembangkan aplikasi perusahaan besar. Ketika Anda melakukan ini bermasalah untuk mengatur arsitektur yang baik yang menangani semua fungsi "ViewModel" ini. Saya pikir dengan BlipAjax Anda akan memiliki "baseline" yang sangat bagus untuk memulai. Ini hanya situs web sederhana, tetapi bagus dalam kesederhanaannya. Saya suka cara mereka menggunakan bahasa Inggris untuk menunjukkan apa yang benar-benar dibutuhkan dalam aplikasi.

Herman Van Der Blom
sumber