ViewModel ใน MVC คืออะไร


429

ฉันใหม่กับ ASP.NET MVC ฉันมีปัญหาในการทำความเข้าใจกับวัตถุประสงค์ของ ViewModel

ViewModel คืออะไรและทำไมเราต้องใช้ ViewModel สำหรับแอพพลิเคชั่น ASP.NET MVC

ถ้าฉันได้รับตัวอย่างที่ดีเกี่ยวกับการทำงานและคำอธิบายที่จะดีกว่า


4
โพสต์นี้คือสิ่งที่คุณมองหา - "ASP.NET MVC ViewModel คืออะไร"
Yusubov

6
บทความนี้ดูดีมาก: rachelappel.com/ ...
Andrew

ความเป็นไปได้ที่ซ้ำกันของใน 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

เมื่อมุมมองโหลดขึ้นเป็นครั้งแรกฉันจะได้รับข้อมูลของพนักงานจากฐานข้อมูลโดยใช้Id3 ฉันจะแสดงข้อความคงที่ในมุมมอง / หน้าของฉันเพื่อให้ผู้ใช้สามารถเห็นพนักงานที่ถูกลบ เมื่อผู้ใช้คลิกปุ่มลบฉันจะใช้Idค่า 3 แล้วส่งไปยังที่เก็บเลเยอร์ของฉัน คุณต้องการเพียงIdจะลบบันทึกจากตาราง

อีกจุดหนึ่งคุณไม่จำเป็นต้องใช้โมเดลการดูสำหรับทุกการกระทำ ถ้ามันเป็นข้อมูลที่เรียบง่ายมันก็น่าจะใช้ได้ดีEmployeeViewModelถ้ามันเป็นข้อมูลง่ายแล้วมันจะดีกับการใช้งานเท่านั้นหากเป็นมุมมอง / หน้าเว็บที่ซับซ้อนและแตกต่างจากกันฉันแนะนำให้คุณใช้โมเดลมุมมองแยกต่างหากสำหรับแต่ละมุมมอง

ฉันหวังว่าสิ่งนี้จะเป็นการขจัดความสับสนที่คุณมีเกี่ยวกับแบบจำลองการดูและแบบจำลองโดเมน


5
@ เคนนี่: แสดงให้ฉันดู :) สิ่งที่ฉันพยายามจะบอกคือให้คุณบอกว่าคุณมีโมเดลโดเมนที่มีคุณสมบัติ 50 รายการและมุมมองของคุณจะต้องแสดง 5 เท่านั้นจึงไม่ใช้ในการส่งคุณสมบัติทั้งหมด 50 รายการเพื่อแสดง 5
เบรนแดน Vogt

5
@BrendanVogt - คุณอธิบายได้ดี แต่ฉันไม่เข้าใจว่าค่าใช้จ่ายในการ "ส่งคุณสมบัติทั้งหมด 50 รายการ" เป็นอย่างไร รหัสอื่นได้สร้างวัตถุแบบจำลองแล้วด้วยคุณสมบัติ 50 ทั้งหมดและดูเหมือนว่าจะไม่คุ้มค่าที่จะรักษาคลาสอื่นเพียงเพื่อไม่ส่ง 45 คุณสมบัติ - โดยเฉพาะถ้าคุณอาจต้องการส่งหนึ่งใน 45 คุณสมบัติเหล่านี้ในอนาคต
Kenny Evitt

5
@BrendanVogt - ฉันคิดว่าคำตอบของ LukLed อาจช่วยให้ฉันเข้าใจว่าทำไมสิ่งเหล่านี้อาจเป็นประโยชน์โดยเฉพาะอย่างยิ่งที่ ViewModel (สามารถ) "... รวมค่าจากเอนทิตีฐานข้อมูลต่าง ๆ " [ที่ฉันสมมติว่าวลีเป็นจริงเหมือน " เอนทิตีฐานข้อมูล "ที่จะถูกแทนที่ด้วย" โมเดลวัตถุ "] แต่ยังคงมีปัญหาใดที่เฉพาะเจาะจงที่ ViewModels ตั้งใจจะแก้ไข คุณมีลิงค์ใด ๆ หรือไม่? ฉันไม่พบอะไรเลย [และฉันขอโทษถ้าฉันดูเหมือนจะเลือกคุณ!]
Kenny Evitt

1
ฉันเพิ่งได้ยินว่ามีคนพูดว่า ViewModels เป็นวิธีที่ดีในการส่งคอลเล็กชันหลาย ๆ แบบ (หรือข้ามคุณสมบัติของโมเดล) ไปยังมุมมองเดียวโดยไม่ต้องเก็บไว้ใน viewBag ทำให้รู้สึกถึงฉัน
Ayyash

3
ฉันขอโทษที่สำคัญ แต่คำตอบนี้ไม่สมบูรณ์ การกำหนด viewmodel เป็นเพียงสิ่งที่คุณต้องการแสดงบนหน้าของคุณก็เหมือนกับการถามว่า "รถยนต์คืออะไร" และได้รับคำตอบ "มันไม่ใช่เครื่องบิน" เป็นเรื่องจริง แต่ก็ไม่ค่อยเป็นประโยชน์ คำจำกัดความที่ถูกต้องของ VM คือ "ทุกสิ่งที่คุณต้องการในการแสดงผลหน้าเว็บของคุณ" หากคุณอ่านลงไปด้านล่างฉันได้ระบุส่วนประกอบที่คุณต้องการสร้าง VM ของคุณอย่างถูกต้องและง่ายดายในหลายกรณีการใช้ประโยชน์จากรูปแบบโดเมนที่มีอยู่และรูปแบบการนำเสนอของคุณ
Sam

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

การใช้โมเดลมุมมองนี้คุณสามารถกำหนดมุมมอง (Razor view engine):

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

อีกตัวอย่างของโมเดลการดูและการดึงข้อมูล: เราต้องการแสดงข้อมูลผู้ใช้พื้นฐานสิทธิ์ของเขาและชื่อผู้ใช้ เราสร้างโมเดลมุมมองพิเศษซึ่งมีเฉพาะฟิลด์ที่จำเป็น เราดึงข้อมูลจากเอนทิตีต่าง ๆ จากฐานข้อมูล แต่มุมมองนั้นรับรู้เฉพาะคลาสโมเดลมุมมอง:

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
} 

ฉันชื่อผู้ใช้ thin.FirstName + "" + user.Mother.LastName ควรทำใน View Model End ลอจิกทั้งหมดควรทำที่ส่วนท้ายของมุมมองโมเดล
Kurkula

3
@Chandana: ฉันเชื่อว่าการต่อข้อมูลแบบง่ายสามารถทำได้ในรูปแบบการดู ไม่มีเหตุผลที่จะเปิดเผยสองช่องถ้าพวกเขาตั้งใจจะนำเสนอด้วยกัน
LukLed

82

แก้ไข: ฉันอัปเดตคำตอบนี้ในบล็อกของฉัน:

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

คำตอบของฉันค่อนข้างยาว แต่ฉันคิดว่ามันสำคัญที่จะต้องเปรียบเทียบมุมมองแบบจำลองกับรุ่นที่ใช้กันทั่วไปประเภทอื่นเพื่อเข้าใจว่าทำไมถึงแตกต่างกันและทำไมจึงจำเป็น

เพื่อสรุปและตอบคำถามที่ถูกถามโดยตรง:

โดยทั่วไปแล้วโมเดลการดูเป็นวัตถุที่มีคุณสมบัติและวิธีการทั้งหมดที่จำเป็นในการแสดงผลมุมมอง ดูคุณสมบัติของโมเดลมักจะเกี่ยวข้องกับวัตถุข้อมูลเช่นลูกค้าและคำสั่งซื้อและนอกจากนี้ยังมีคุณสมบัติที่เกี่ยวข้องกับหน้าหรือแอปพลิเคชันของตัวเองเช่นชื่อผู้ใช้ชื่อแอปพลิเคชันเป็นต้นดูรุ่นให้วัตถุที่สะดวกในการส่ง สร้างหน้า html หนึ่งในหลาย ๆ เหตุผลในการใช้โมเดลมุมมองคือโมเดลวิวจัดให้มีวิธีทดสอบหน่วยงานการนำเสนอบางอย่างเช่นการจัดการอินพุตผู้ใช้การตรวจสอบข้อมูลการดึงข้อมูลเพื่อแสดงผลเป็นต้น

นี่คือการเปรียบเทียบโมเดล Entity (โมเดล a.ka. a.ka. ของ DTO), โมเดลการนำเสนอและดูโมเดล

การถ่ายโอนข้อมูลวัตถุ aka“ แบบจำลอง”

Data Transfer Object (DTO) เป็นคลาสที่มีคุณสมบัติที่ตรงกับ schema ของตารางในฐานข้อมูล 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); } }
}

ดูแบบจำลอง

โมเดลมุมมองนั้นคล้ายคลึงกับโมเดลการนำเสนอซึ่งเป็นคลาสสำรองสำหรับการเรนเดอร์มุมมอง อย่างไรก็ตามมันแตกต่างจาก Presentation Model หรือ 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, ชื่อผู้ใช้และชื่อแอปพลิเคชันจะถูกทำซ้ำและไม่สะดวกในการใช้งาน นอกจากนี้ถ้าเราต้องการกำหนดตรรกะระดับหน้าบางส่วนในนวกรรมิกของคลาส? เราไม่สามารถทำเช่นนั้นได้อีกต่อไปหากเราสร้างอินสแตนซ์สำหรับทุกคำสั่งซื้อที่จะแสดง

องค์ประกอบมากกว่ามรดก

นี่คือวิธีที่เราอาจพิจารณาปัจจัยรูปแบบการนำเสนอเพื่อให้มันกลายเป็นรูปแบบมุมมองที่แท้จริงและจะเป็นประโยชน์สำหรับการแสดงวัตถุ 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?
Alexander Derck

2
@AlexanderDerck พวกเขาจะใช้เพื่อวัตถุประสงค์ที่แตกต่างกัน พวกเขาจะสับสนหนึ่งสำหรับอื่น ๆ (ในข้อผิดพลาด) ไม่ปกติคุณจะไม่ใช้โมเดลจำลองแทนโมเดลการดู ร่วมกันมากขึ้นคือการที่ VM "มี" เช่นรูปแบบการนำเสนอ MyViewModel<MyPresModel>
แซม

2
@Sam สมมติว่าแบบจำลองวัตถุเป็นวัตถุแบบสดเช่นแบบจำลอง nhibernate .. ดังนั้นโดยการมี BusinessObject เราไม่ได้เปิดเผยแบบจำลอง / วัตถุสดไปยังมุมมองโดยตรงหรือไม่ เช่นวัตถุธุรกิจสามารถใช้ในการปรับเปลี่ยนสถานะฐานข้อมูลโดยตรงหรือไม่ นอกจากนี้โมเดลการดูแบบซ้อนยังมีอะไรบ้าง ที่จะต้องมีคุณสมบัติวัตถุทางธุรกิจหลายอย่างใช่มั้ย
มูฮัมหมัดอาลี

22

หากคุณมีคุณสมบัติที่เฉพาะเจาะจงสำหรับมุมมองและไม่เกี่ยวข้องกับที่เก็บ DB / Service / Data มันเป็นแนวปฏิบัติที่ดีในการใช้ ViewModels สมมติว่าคุณต้องการปล่อยให้ช่องทำเครื่องหมายถูกเลือกโดยยึดตามเขตข้อมูล DB (หรือสอง) แต่เขตข้อมูล DB นั้นไม่ใช่บูลีน ในขณะที่มันเป็นไปได้ที่จะสร้างคุณสมบัติเหล่านี้ในรูปแบบของตัวเองและทำให้มันถูกซ่อนไว้จากการผูกกับข้อมูลคุณอาจไม่ต้องการถ่วงรูปแบบขึ้นอยู่กับจำนวนของเขตข้อมูลและการทำธุรกรรมดังกล่าว

หากมีข้อมูลและ / หรือการแปลงเฉพาะของมุมมองที่เฉพาะเจาะจงน้อยเกินไปคุณสามารถใช้โมเดลได้


19

ฉันไม่ได้อ่านโพสต์ทั้งหมด แต่ทุกคำตอบดูเหมือนจะหายไปหนึ่งแนวคิดที่ช่วยให้ฉัน "รับ" ...

หาก Model เป็นแบบเดียวกับตารางฐานข้อมูลดังนั้น ViewModel จะคล้ายกับมุมมองฐานข้อมูล- โดยทั่วไปมุมมองจะส่งคืนข้อมูลจำนวนเล็กน้อยจากตารางเดียวหรือชุดข้อมูลที่ซับซ้อนจากหลายตาราง (รวม)

ฉันพบว่าตัวเองใช้ ViewModels เพื่อส่งผ่านข้อมูลไปยังมุมมอง / แบบฟอร์มจากนั้นถ่ายโอนข้อมูลนั้นไปยังรุ่นที่ถูกต้องเมื่อแบบฟอร์มโพสต์กลับไปที่ตัวควบคุม - ยังมีประโยชน์มากสำหรับการจัดเก็บรายการ (IEnumerable)


11

MVC ไม่มี viewmodel: มันมี model, view และ controller viewmodel เป็นส่วนหนึ่งของ MVVM (Model-View-Viewmodel) MVVM ได้มาจากรูปแบบการนำเสนอและได้รับความนิยมใน WPF ควรมีแบบจำลองใน MVVM แต่คนส่วนใหญ่พลาดจุดของรูปแบบนั้นอย่างสมบูรณ์และพวกเขาจะมีเพียงมุมมองและโมเดล โมเดลใน MVC คล้ายกับโมเดลใน MVVM

ใน MVC กระบวนการแบ่งออกเป็น 3 ความรับผิดชอบที่แตกต่างกัน:

  • มุมมองมีหน้าที่รับผิดชอบในการนำเสนอข้อมูลให้กับผู้ใช้
  • ตัวควบคุมรับผิดชอบการไหลของหน้า
  • แบบจำลองมีหน้าที่รับผิดชอบในตรรกะทางธุรกิจ

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 การกลับไปที่แหล่งข้อมูลนั้นดีกว่าการติดตามฝูงโดยไม่มีคำถาม (aka "วิธีปฏิบัติที่ดีที่สุด") MVC มีความหมายสำหรับหน่วยที่เล็กกว่ามากเช่นปุ่มบนหน้าจอประกอบด้วยโมเดลมุมมองและตัวควบคุม ใน Web-MVC หน้าทั้งหมดมีตัวควบคุมรุ่นและมุมมอง โมเดลและมุมมองควรเชื่อมต่อกันดังนั้นการเปลี่ยนแปลงในโมเดลจะสะท้อนให้เห็นทันทีในมุมมองและในทางกลับกัน การลอกเลียนแบบเป็นเรื่องใหญ่มาก สถาปัตยกรรมไม่ควรโกหกกับนักพัฒนาซอฟต์แวร์
Jeroen

1
@ jeroen ตัวย่อ MVC ถูกขโมยและถูกทำให้ยุ่งเหยิง ใช่ MVC ไม่มี VM แต่ยังไม่มี Repository หรือเลเยอร์บริการและวัตถุเหล่านั้นถูกใช้อย่างกว้างขวางในเว็บไซต์ ฉันเชื่อว่า OP ขอให้ "ฉันจะแนะนำและใช้ VM ใน MVC ได้อย่างไร" ในความหมายใหม่ของ MVC แบบจำลองไม่ใช่ที่ซึ่งตรรกะทางธุรกิจอยู่ ตรรกะทางธุรกิจอยู่ในเลเยอร์บริการสำหรับเว็บหรือแอปเดสก์ท็อปที่ใช้ MVC หรือ MVVM ตัวแบบคำอธิบายวัตถุธุรกิจที่ส่งผ่านไปยัง / จากชั้นบริการ คำจำกัดความเหล่านี้แตกต่างอย่างมากจากคำอธิบายดั้งเดิมของ MVC
Sam

1
@Sam ไม่ใช่ทุกสิ่งที่เป็นส่วนหนึ่งของเว็บไซต์ แต่สามารถเรียกได้ว่าเป็นส่วนหนึ่งของ MVC ไม่มีความหมายใหม่ของ MVC มีความหมายที่ถูกต้องและ "สิ่งที่ไม่เกี่ยวข้องอย่างสมบูรณ์ที่ผู้คนสับสนกับ MVC" หมายถึง บอกว่าแบบจำลองมีความรับผิดชอบในตรรกะทางธุรกิจไม่เหมือนกับตรรกะทางธุรกิจที่ถูกเข้ารหัสในรูปแบบ ส่วนใหญ่แล้วโมเดลทำหน้าที่เป็นส่วนหน้าของแอปพลิเคชัน
Jeroen

ข้อบกพร่องหลักที่ฉันเห็นใน MVC ของ Microsoft คือการล็อคของรุ่นที่มีมุมมอง นั่นเอาชนะจุดประสงค์ทั้งหมดของการแยกทั้งหมดที่เกิดขึ้นใน N-Tier การออกแบบในช่วง 20 ปีที่ผ่านมา พวกเขาเสียเวลาทำให้เราต้องใช้ "WebForms" ในปี 2545 ซึ่งเป็นโมเดลที่ได้รับแรงบันดาลใจจากเดสก์ท็อปอีกตัวหนึ่งที่ถูกนำไปไว้บนเว็บ ตอนนี้พวกเขาได้โยนออก แต่ยกอีกรุ่นเดสก์ท็อปอีกครั้งในกระบวนทัศน์ใหม่นี้สำหรับการพัฒนาเว็บ ในขณะที่ Google และคนอื่น ๆ กำลังสร้างโมเดลฝั่งไคลเอ็นต์ขนาดใหญ่ที่แยกมันทั้งหมด ฉันคิดว่า ASP VBScript แบบเก่าตั้งแต่ปี 1998 เป็นระบบพัฒนาเว็บที่แท้จริงที่สุด
Stokely

11

ดูโมเดล a เป็นคลาสแบบง่ายซึ่งสามารถมีคุณสมบัติคลาสได้มากกว่าหนึ่งคลาส เราใช้มันเพื่อสืบทอดคุณสมบัติที่ต้องการทั้งหมดเช่นฉันมีนักเรียนสองวิชาและวิชา

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 นี้ในมุมมอง

@model ProjectName.Model.StudentViewModel

ตอนนี้เราสามารถเข้าถึงคุณสมบัติทั้งหมดของ StudentViewModel และคลาสที่สืบทอดในมุมมอง


10

มีตัวอย่างมากมายให้ฉันอธิบายอย่างชัดเจนและกรอบ

ViewModel = รุ่นที่สร้างขึ้นเพื่อให้บริการมุมมอง

มุมมอง ASP.NET MVC ไม่สามารถมีโมเดลได้มากกว่าหนึ่งโมเดลดังนั้นหากเราต้องการแสดงคุณสมบัติจากโมเดลมากกว่าหนึ่งโมเดลในมุมมองมันเป็นไปไม่ได้ ViewModel ทำหน้าที่จุดประสงค์นี้

ดูโมเดลเป็นคลาสโมเดลที่สามารถเก็บเฉพาะคุณสมบัติเหล่านั้นที่จำเป็นสำหรับมุมมอง นอกจากนี้ยังสามารถมีคุณสมบัติจากมากกว่าหนึ่งเอนทิตี (ตาราง) ของฐานข้อมูล ตามชื่อที่แนะนำโมเดลนี้ถูกสร้างขึ้นเฉพาะกับข้อกำหนดมุมมอง

ดูตัวอย่างน้อยรุ่นอยู่ด้านล่าง

  • ในการแสดงข้อมูลจากเอนทิตีมากกว่าหนึ่งในหน้ามุมมอง - เราสามารถสร้างโมเดลมุมมองและมีคุณสมบัติของเอนทิตีทั้งหมดที่เราต้องการแสดงรายการข้อมูล เข้าร่วมเอนทิตีฐานข้อมูลเหล่านั้นและตั้งค่าดูคุณสมบัติของโมเดลและกลับไปที่มุมมองเพื่อแสดงข้อมูลของเอนทิตีต่าง ๆ ในรูปแบบตารางเดียว
  • มุมมองโมเดลอาจกำหนดเฉพาะฟิลด์เฉพาะของเอนทิตีเดียวที่จำเป็นสำหรับมุมมอง

ViewModel ยังสามารถใช้ในการแทรกอัปเดตบันทึกลงในเอนทิตีมากกว่าหนึ่งรายการได้อย่างไรก็ตามการใช้งานหลักของ ViewModel คือการแสดงคอลัมน์จากเอนทิตีหลาย (โมเดล) ลงในมุมมองเดียว

วิธีการสร้าง ViewModel เหมือนกับการสร้าง Model วิธีการสร้างมุมมองสำหรับ Viewmodel นั้นเหมือนกับการสร้างมุมมองสำหรับ Model

นี่เป็นตัวอย่างเล็ก ๆ ของข้อมูลโดยใช้รายการ ViewModel

หวังว่านี่จะเป็นประโยชน์


6

ViewModel เป็นวิธีการแก้ปัญหาที่แก้ไขความซุ่มซ่ามแนวคิดของกรอบ MVC เพราะมันหมายถึงชั้นที่ 4 ในสถาปัตยกรรม Model-View-Controller แบบ 3 ชั้น เมื่อ Model (โมเดลโดเมน) ไม่เหมาะสมใหญ่เกินไป (ใหญ่กว่า 2-3 ฟิลด์) สำหรับมุมมองเราสร้าง ViewModel ที่มีขนาดเล็กกว่าเพื่อส่งต่อไปยัง View


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

ทำงานกับ Action

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. ใช้ mapper เมื่อ ViewModel ซับซ้อนมากขึ้น

1

View Model เป็นคลาสที่เราสามารถใช้สำหรับการแสดงผลข้อมูลบน View สมมติว่าคุณมีสถานที่สองรายการและประเภทสถานที่และคุณต้องการเข้าถึงข้อมูลจากทั้งสองหน่วยงานโดยใช้รูปแบบเดียวจากนั้นเราจะใช้ 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; }
    }

ดังนั้นในตัวอย่างข้างต้น Place และ Category คือเอนทิตีที่แตกต่างกันสองรายการและ PlaceCategory viewmodel คือ ViewModel ซึ่งเราสามารถใช้บน View


ตัวอย่างของคุณไม่ชัดเจนนัก สิ่งที่ระบุไว้ข้างต้นคือ ViewModel เชื่อมต่อข้อมูลกับมุมมอง ถ้าคุณดูที่ ViewModels ใน BlipAjax คุณจะเห็นคลาสที่เหมาะกับมันมากที่สุด
Herman Van Der Blom

0

หากคุณต้องการที่จะศึกษารหัสวิธีการตั้งค่าเป็น "พื้นฐาน" แอพลิเคชันเว็บที่มี ViewModels ฉันสามารถให้คำแนะนำในการดาวน์โหลดโค้ดนี้บน GitHub: https://github.com/ajsaulsberry/BlipAjax ฉันพัฒนาแอปพลิเคชันองค์กรขนาดใหญ่ เมื่อคุณทำเช่นนี้มันมีปัญหาในการตั้งค่าสถาปัตยกรรมที่ดีที่จัดการฟังก์ชัน "ViewModel" ทั้งหมดนี้ ฉันคิดว่า BlipAjax คุณจะมี "baseline" ที่ดีมากในการเริ่มต้น มันเป็นเพียงเว็บไซต์ที่เรียบง่าย แต่ยอดเยี่ยมในความเรียบง่าย ฉันชอบวิธีที่พวกเขาใช้ภาษาอังกฤษเพื่อชี้สิ่งที่จำเป็นจริงๆในแอปพลิเคชัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.