標籤:des style blog http color io os 使用 ar
對於一個線上商店,領域模型可能由表現產品、訂單、客戶等的類所組成,它對定義這些實體的資料和商務規則都進行了封閉,這種模型用作建立使用者介面以及定義商務規則的基礎。儘管這種辦法可能適合某些應用程式(通常是有簡單域的小型應用程式),但經常會帶來麻煩,特別是當應用程式增長,且要求UI偏離商務邏輯需求時,一個利害衝突可能會導致過於複雜和不可維護的軟體。
這個問題的解決方案是引入視圖模型(View Model),以簡化渲染使用者介面所需的邏輯。我們將考擦如何定義視圖模型,以及用來將使用者介面的資料回傳給控制器層的輸入模型。
一、什麼是視圖模型
視圖模型的目的十分簡單,它是一個專門為用於視圖而設計的模型,它提供了一個建立在領域模型之上的簡化介面,以保持視圖決策最小化。
1.留言本例子中添加視圖模型
在留言本這個例子中,GuestbookEntry類既作為領域模型,也作為視圖模型。它既表現了資料庫中儲存的資料,也表現了使用者介面中的欄位。
對於像留言簿這樣的小型應用程式,這是足夠的。但是,隨著應用程式複雜性的提升,當複雜的使用者介面結構必須不直接映射模型的結構時,即視圖資料與模型結構不同,往往需要將兩者分開。比如,讓我們對Guestbook應用程式添加一個新的頁面,以顯示每個使用者已遞交了多少評論的摘要,。
為了建立這一螢幕,首先需要建立一個視圖模型,它每一列含有一個屬性——使用者名稱和已遞交的評論數:
public class CommentSummary { public string UserName { get; set; } public string NumberOfComments { get; set; } }
現在需要建立一個控制器動作,查詢資料庫以擷取顯示所必需的資料,然後將其注入CommentSummary類執行個體。
public ActionResult CommentSummary() { var entries = from entry in _db.Entries group entry by entry.Name into groupedByName orderby groupedByName.Count() descending select new CommentSummary { NumberOfComments = groupedByName.Count(), UserName = groupedByName.Key }; return View(entries.ToList()); }
這裡使用了LINQ來查詢留言簿資料,並按使用者名稱對遞交的評論進行分組。接著將資料投影成視圖模型執行個體,然後便可以將其傳遞給視圖。
@model IEnumerable<Guestbook.Models.CommentSummary><table> <tr> <th>Number of comments</th> <th>User name</th> </tr> @foreach(var summaryRow in Model) { <tr> <td>@summaryRow.NumberOfComments</td> <td>@summaryRow.UserName</td> </tr> }</table>
2.線上商店樣本
讓我們從一個簡單的線上商店樣本開始。它可能包含Customer、Order和Product類,這些類對應於關聯式資料庫中的表,並使用對象關係映射器進行映射。
public class Customer { public int Number { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public bool Active { get; set; } public ServiceLevel ServiceLevel { get; set; } public IEnumerable<Order> Orders { get; set; } } public enum ServiceLevel { Standard, Premier } public class Order { public DateTime Date { get; set; } public IEnumerable<Product> Product { get; set; } public decimal TotalAmount { get; set; } } public class Product { public string Name { get; set; } public decimal Cost { get; set; } }
商店的管理區可能包含一個Customer Summary(客戶摘要)頁面,該頁面列出每個客戶及其訂單數。
建立這個UI的一個可選辦法是可以直接通過領域模型來建立該螢幕。我們可以從資料庫取回客戶列表,然後將其傳遞給視圖,視圖迴圈遍曆客戶列表並構建表格。當到達最後一列Most Recent Order Date(最近的訂單日期)時,視圖不得不迴圈遍曆客戶的Orders集合,以得出最近的一份訂單。
這種方法的一個問題,是它使視圖十分複雜。為了使視圖儘可能是可維護的,它應該儘可能簡化,將複雜的迴圈和計算邏輯放在更高層執行,視圖唯一應該做的只是顯示這種計算的結果。通過實現明確表示該表格的視圖模型,可以做到這一點。
(1)建立視圖模型
public class CustomerSummary { public string Name { get; set; } public string Active { get; set; } public string ServiceLevel { get; set; } public string OrderCount { get; set; } public string MostRecentOrderDate { get; set; } }
(2)交付表現模型
public class CustomerSummaryController : Controller { private CustomerSummaries _customerSummaries = new CustomerSummaries(); public ActionResult Index() { IEnumerable<CustomerSummary> summaries = _customerSummaries.GetAll(); return View(summaries); } }
public class CustomerSummaries { public IEnumerable<CustomerSummary> GetAll() { return new[] { new CustomerSummary { Active = "Yes", Name = "John Smith", MostRecentOrderDate = "02/07/10", OrderCount = "42", ServiceLevel = "Standard" }, new CustomerSummary { Active = "Yes", Name = "Susan Power", MostRecentOrderDate = "02/02/10", OrderCount = "1", ServiceLevel = "Standard" }, new CustomerSummary { Active = "Yes", Name = "Jim Doe", MostRecentOrderDate = "02/09/10", OrderCount = "7", ServiceLevel = "Premier" }, }; } }
(3)ViewData.Model
控制器與視圖共用了一個ViewDataictionary類型的對象,其名稱為ViewData。它有一個頗具特色的Model屬性。當我們在清單5.3中調用return View(summaries)時,ViewData.Model會自動以CustomerSummary對象列表進行填充,這便做好了在視圖中顯示的準備。Model屬性也是強型別的,因此視圖確切地知道所期望的類型,也使開發人員能夠利用IDE智能感應之類的特性,以及對變數重新命名的支援。Razor視圖引擎遮蓋了其中大部分內部機制,這使得定義模型類型變得簡單。視圖可以用@model指示符來描述它的模型類型:
@model IEnumerable<StoreCh05.Models.CustomerSummary>
<table> <tr> <th>Name</th> <th>Active?</th> <th>Service Level</th> <th>Order Count</th> <th>Most Recent Order Date</th> </tr> @foreach (var summary in Model) { <tr> <td>@summary.Name</td> <td>@summary.Active</td> <td>@summary.ServiceLevel</td> <td>@summary.OrderCount</td> <td>@summary.MostRecentOrderDate</td> </tr> } </table>
二、表現使用者輸入
一個強大的表現模型能夠使視圖便於使用資料,一個強大的輸入模型也能夠使應用程式便於使用使用者輸入。代替那種使用易於出錯的字串鍵和檢測希望與輸入元素名匹配的請求值,我們可以利用ASP.NET MVC的特性來使用強大的輸入模型。
1.設計輸入模型
圖中的簡單表單有兩個文字框和一個複選框。作為一種應用程式的特徵,該表單也值得作為一個正式化的表現:一個類。
public class NewCustomerInput { public string FirstName { get; set; } public string LastName { get; set; } public bool Active { get; set; } }
2.在視圖中表示輸入模型
public class CustomerController : Controller { public ViewResult New() { return View(); } public ViewResult Save(NewCustomerInput input) { return View(input); } }
@model StoreCh052.Models.NewCustomerInput<div> <form action="@Url.Action("Save")" method="post"> <fieldset> <div> @Html.LabelFor(x => x.FirstName) @Html.TextBoxFor(x => x.FirstName) </div> <div> @Html.LabelFor(x => x.LastName) @Html.TextBoxFor(x => x.LastName) </div> <div> @Html.LabelFor(x => x.Active) @Html.CheckBoxFor(x => x.Active) </div> <div> <button name="save"> Save</button> </div> </fieldset> </form></div>
三、用於顯示和輸入的複雜模型
知識點5-1:視圖模型