七天學會ASP.NET MVC (二)——ASP.NET MVC 資料傳遞
本文參考自:http://www.codeproject.com/Articles/986730/Learn-MVC-Project-in-days-Day
轉載請註明出處:葡萄城官網,葡萄城為開發者提供專業的開發工具、解決方案和服務,賦能開發者。
通過第一天的學習之後,我們相信您已經對MVC有一些基本瞭解。
本節所講的內容是在上節的基礎之上,因此需要確保您是否掌握了上一節的內容。本章的目標是在今天學習結束時利用最佳實踐解決方案建立一個小型的MVC專案,本節的主要目標是瞭解MVC之間的資料傳遞問題。我們會逐步深入講解,並新增新功能,使專案越來越完善。
系列文章
Controller與 View之間的值傳遞
在上一節的實驗二中已經建立了靜態View。然而在實際使用情況下,View常用於顯示動態資料。在實驗三中們將在View中動態顯示資料。
View將從從Controller獲得Model中的資料。
Model是MVC中 表示業務資料的層。
實驗3 ——使用View資料
ViewData相當於資料字典,包含Controlle和View之間傳遞的所有資料。Controller會在該字典中新增新資料項,View從字典中讀取資料。
1. 建立Model 類
在Model資料夾下新建Employee類,如下。
1: public class Employee
2:
3: {
4: public string FirstName { get; set; }
5:
6: public string LastName { get; set; }
7:
8: public int Salary { get; set; }
9:
10: }
2. 在Controller 中獲取Model
在GetView 方法中建立Employee 物件:
1: Employee emp = new Employee();
2: emp.FirstName = "Sukesh";
3: emp.LastName="Marla";
4: emp.Salary = 20000;
注意:請確保使用Using語句包含此類,或者使用類的全稱。
1: using WebApplication1.Models;
3. 建立ViewData 並返回View
在ViewData中儲存Employee 物件。
1: ViewData["Employee"] = emp;
2: return View("MyView");
4. 在View中顯示Employee 資料
開啟MyView.cshtml。
從ViewData中獲取Employee 資料並按照如下程式碼顯示:
1: <div>
2: @{
3: WebApplication1.Models.Employee emp=(WebApplication1.Models.Employee)
4: ViewData["Employee"];
5: }
6:
7: <b>Employee Details </b><br />
8: Employee Name : @[email protected] <br />
9: Employee Salary: @emp.Salary.ToString("C")
10: </div>
5. 測試輸出
按F5執行
關於實驗 3
1. 寫Razor程式碼帶花括號和沒有花括號有什麼區別?
在實驗三中@emp.FirstName能夠使用以下指令碼來代替
1: @{
2: Response.Write(emp.FirstName);
3: }
@符號後沒有花括號只是簡單的顯示變數或表示式的值
2. 為什麼需要強制轉換型別
ViewData可操作內部物件,每次新增新值,會封裝成物件型別,因此每次都需要解壓來提取值。
3. @emp.FirstName @emp.LastName有什麼特殊含義?
意味著LastName顯示在FirstName之後並自動新增空格。
4. 為什麼 Employee中的 硬編碼是由Controller建立的 ?
在本文中只是為了實現實驗目的,因此採用硬編碼,實際使用中,是從資料庫或Web服務中獲取的。
5. 資料庫邏輯,資料訪問層,業務層分別指的是什麼?
- 資料訪問層是ASP.NET MVC中是一直隱式存在的,MVC定義中不包含資料訪問層的定義。
- 業務層是直譯器的先驅,是Model的一部分。
完整的MVC結構
實驗4——ViewBag的使用
ViewBag可以稱為ViewData的一塊關於語法的輔助的糖果,ViewBag使用C# 4.0的動態特徵,使得ViewData也具有動態特性。
ViewData與ViewBag對比:
ViewData |
ViewBag |
它是Key/Value字典集合 |
|
從Asp.net MVC 1 就有了 |
ASP.NET MVC3 才有 |
基於Asp.net 3.5 framework |
基於Asp.net 4.0與.net framework |
ViewData比ViewBag快 |
ViewBag比ViewData慢 |
在ViewPage中查詢資料時需要轉換合適的型別 |
在ViewPage中查詢資料時不需要型別轉換 |
有一些型別轉換程式碼 |
可讀性更好 |
ViewBag內部呼叫ViewData。
1. 建立View Bag
在實驗三的基礎之上,使用以下指令碼代替第三步中的程式碼。
1: ViewBag.Employee = emp;
2. 在View中顯示EmployeeData
使用以下程式碼來替代實驗三中第四步中的程式碼:
1: @{
2: WebApplication1.Models.Employee emp = (WebApplication1.Models.Employee)
3: ViewBag.Employee;
4: }
5: Employee Details
6:
7: Employee Name: @emp.FirstName @emp.LastName
8:
9: Employee Salary: @emp.Salary.ToString("C")
3. 測試輸出
執行結果:
關於實驗4
可以傳遞ViewData,接收時獲取ViewBag嗎?
答案是肯定的,反之亦然。如之前所說的,ViewBag只是ViewData的一塊糖/
ViewData與ViewBag的問題
ViewData和ViewBag 是Contoller與View之間值傳遞的內容。但是在實際使用的過程中,它們並不是最佳選擇,接下來我們來看看使用它們的缺點:
- 效能問題;ViewData中的值都是物件型別,使用之前必須強制轉換為合適的型別。會新增額外的效能負擔。
- 沒有型別安全就沒有編譯時錯誤,如果嘗試將其轉換為錯誤的型別,執行時會報錯。良好的程式設計經驗告訴我們,錯誤必須在編譯時捕獲。
- 資料傳送和資料接收之間沒有正確的連線;MVC中,Controller和View是鬆散的連線的。Controller是無法捕獲View變化,View也無法捕獲到Controller內部發生的變化。從Controller傳遞一個ViewData或ViewBag的值,當開發人員正在View中寫入,就必須記錄從Controller中即將獲得什麼值。如果Controller與View開發人員不是相同的開發人員,開發工作會變得非常困難。會導致許多執行時問題,降低了開發效率。
實驗5——理解強型別View
ViewData和ViewBag引起的所有問題根源都在於資料型別。引數值的資料型別是被封裝在ViewData中的,稱為物件。
如果能夠設定Controller和View之間引數傳遞的資料型別,那麼上述問題就會得到解決,因此從得出強型別View。
接下來,我們看一個簡單的例子,如果工資大於15000則顯示黃色,低於顯示綠色。
1. 建立View的強型別
在View的頂部新增以下程式碼:
@model WebApplication1.Models.Employee
2. 顯示資料
在View內部輸入@Model.就會檢視到Model類的屬性
新增以下程式碼來顯示資料:
1: Employee Details
2:
3: Employee Name : @Model.FirstName @Model.LastName
4:
5: @if(Model.Salary>15000)
6: {
7: <span style="background-color:yellow">
8: Employee Salary: @Model.Salary.ToString("C")
9: </span>
10: }
11: else
12: {
13: <span style="background-color:green">
14:
15: Employee Salary: @Model.Salary.ToString("C")
16: </span>
17: }
3. 從Controller Action方法中傳遞Model資料。
修改action程式碼
1: Employee emp = new Employee();
2: emp.FirstName = "Sukesh";
3: emp.LastName="Marla";
4: emp.Salary = 20000;
5: return View("MyView",emp);
4. 測試輸出
關於實驗5
View中使用類時需要宣告類的全稱嗎 (Namespace.ClassName)?
新增以下語句,就不需要新增全稱。
1: @using WebApplication1.Models
2: @model Employee
是否必須設定強型別檢視或不使用ViewData和ViewBag?
設定強型別檢視是最佳解決方案。
是否能將View設定為多個Model使用的強型別?
不可以,實際專案中在一個View中想要顯示多個Model時以點結束的。該問題的解決方法將在下一節討論。
理解ASP.NET MVC 中的View Model
實驗5中已經違反了MVC的基本準則。根據MVC,V是View純UI,不包含任何邏輯層。而我們在實驗5中以下三點違反了MVC的體系架構規則。
1. 附加姓和名顯示全名——邏輯層
2. 使用貨幣顯示工資——邏輯層
3. 使用不同的顏色表示工資值,使用簡單的邏輯改變了HTML元素的外觀。——邏輯層
ViewModel 解決方法
ViewModel是ASP.NET MVC應用中隱式宣告的層。它是用於維護Model與View之間資料傳遞的,是View的資料容器。
Model 和 ViewModel 的區別
Model是業務相關資料,是根據業務和資料結構建立的。ViewModel是檢視相關的資料。是根據View建立的。
具體的工作原理
- Controller 處理使用者互動邏輯或簡單的判斷。處理使用者需求
- Controller 獲取一個或多個Model資料
- Controller 決策哪個View最符合使用者的請求
- Controller 將根據Model資料和View需求建立並且初始化ViewModel物件。
- Controller 將ViewModel資料以ViewData或ViewBag或強型別View等物件傳遞到View中。
- Controller 返回View。
View 與 ViewModel 之間是如何關聯的?
View將變成ViewModel的強型別View。
Model和 ViewModel 是如何關聯的?
Model和ViewModel 是互相獨立的,Controller將根據Model物件建立並初始化ViewModel物件。
接下來我們來看實驗6:
實驗6—— 實現ViewModel
1. 新建資料夾
在專案中建立新資料夾並命名為ViewModels。
2. 新建EmployeeViewModel
為了達到實驗目的,首先列出我們的實驗需求:
1. 名和姓應該合併顯示。
2. 使用貨幣顯示數量
3. 薪資以不同的顏色來顯示
4. 當前登入使用者也需要在View中顯示。
在ViewModels類中,建立新類並命名為EmployeeViewModel,如下所示:
1: public class EmployeeViewModel
2: {
3: public string EmployeeName { get; set; }
4: public string Salary { get; set; }
5: public string SalaryColor { get; set; }
6: public string UserName{get;set;}
7: }
注意,姓和名應該使用EmployeeName這一個屬性。而Salary屬性的資料型別是字串,且有兩個新的屬性新增稱為SalaryColor和UserName。
3. View中使用ViewModel
實驗五中已經建立了View的強型別Employee。將它改為 EmployeeViewModel
1: @using WebApplication1.ViewModels
2: @model EmployeeViewModel
4. 在View中顯示資料
使用以下指令碼代替View部分的內容
1: Hello @Model.UserName
2: <hr />
3: <div>
4: <b>Employee Details</b><br />
5: Employee Name : @Model.EmployeeName <br />
6: <span style="background-color:@Model.SalaryColor">
7: Employee Salary: @Model.Salary
8: </span>
9: </div>
5. 新建並傳遞ViewModel
在GetView方法中,獲取Model資料並且將強制轉換為ViewModel物件。
1: public ActionResult GetView()
2: {
3: Employee emp = new Employee();
4: emp.FirstName = "Sukesh";
5: emp.LastName="Marla";
6: emp.Salary = 20000;
7:
8: EmployeeViewModel vmEmp = new EmployeeViewModel();
9: vmEmp.EmployeeName = emp.FirstName + " " + emp.LastName;
10: vmEmp.Salary = emp.Salary.ToString("C");
11: if(emp.Salary>15000)
12: {
13: vmEmp.SalaryColor="yellow";
14: }
15: else
16: {
17: vmEmp.SalaryColor = "green";
18: }
19:
20: vmEmp.UserName = "Admin"
21:
22: return View("MyView", vmEmp);
23: }
6. 測試輸出
儘管執行結果類似,但是View中不包含任何業務邏輯。
關於實驗6
是否意味著,每個Model都有一個ViewModel?
每個View有其對應的ViewModel。
Model與ViewModel之間存在關聯是否是好的實現方法?
最好的是Model與ViewModel之間相互獨立。
需要每次都建立ViewModel嗎?假如View不包含任何呈現邏輯只顯示Model資料的情況下還需要建立ViewModel嗎?
建議是每次都建立ViewModel,每個View都應該有對應的ViewModel,儘管ViewModel包含與Model中相同的屬性。
假定一個View不包含任何呈現邏輯,只顯示Model資料,我們不建立ViewModel會發生什麼?
無法滿足未來的需求,如果未來需要新增新資料,我們需要從頭開始建立全新的UI,所以如果我們保持規定,從開始建立ViewModel,就不會發生這種情況。在本例項中,初始階段的ViewModel將與Model幾乎完全相同。
實驗7——帶有集合的View
在本實驗中,在View中顯示Employee列表。
1. 修改EmployeeViewModel 類
刪除UserName屬性
1: public class EmployeeViewModel
2: {
3: public string EmployeeName { get; set; }
4: public string Salary { get; set; }
5: public string SalaryColor { get; set; }
6: }
2. 建立結合ViewModel
在ViewModels 檔案下,建立新類並命名為EmployeeListViewModel
1: public class EmployeeListViewModel
2: {
3: public List<employeeviewmodel> Employees { get; set; }
4: public string UserName { get; set; }
5: }
3. 修改強型別View的型別
1: @using WebApplication1.ViewModels
2: @model EmployeeListViewModel
4. 顯示View中所有的Employee
1: <body>
2: Hello @Model.UserName
3: <hr />
4: <div>
5: <table>
6: <tr>
7: <th>Employee Name</th>
8: <th>Salary</th>
9: </tr>
10: @foreach (EmployeeViewModel item in Model.Employees)
11: {
12: <tr>
13: <td>@item.EmployeeName</td>
14: <td style="background-color:@item.SalaryColor">@item.Salary</td>
15: </tr>
16: }
17: </table>
18: </div>
19: </body>
5. 建立Employee的業務邏輯
新建類並命名為EmployeeBusinessLayer ,並帶有GetEmployees()方法。
1: public class EmployeeBusinessLayer
2: {
3: public List<employee> GetEmployees()
4: {
5: List<employee> employees = new List<employee>();
6: Employee emp = new Employee();
7: emp.FirstName = "johnson";
8: emp.LastName = " fernandes";
9: emp.Salary = 14000;
10: employees.Add(emp);
11:
12: emp = new Employee();
13: emp.FirstName = "michael";
14: emp.LastName = "jackson";
15: emp.Salary = 16000;
16: employees.Add(emp);
17:
18: emp = new Employee();
19: emp.FirstName = "robert";
20: emp.LastName = " pattinson";
21: emp.Salary = 20000;
22: employees.Add(emp);
23:
24: return employees;
25: }
26: }
27: </employee>
6.從控制器中傳參
1: public ActionResult GetView()
2: {
3: EmployeeListViewModel employeeListViewModel = new EmployeeListViewModel();
4:
5: EmployeeBusinessLayer empBal = new EmployeeBusinessLayer();
6: List<employee> employees = empBal.GetEmployees();
7:
8: List<employeeviewmodel> empViewModels = new List<employeeviewmodel>();
9:
10: foreach (Employee emp in employees)
11: {
12: EmployeeViewModel empViewModel = new EmployeeViewModel();
13: empViewModel.EmployeeName = emp.FirstName + " " + emp.LastName;
14: empViewModel.Salary = emp.Salary.ToString("C");
15: if (emp.Salary > 15000)
16: {
17: empViewModel.SalaryColor = "yellow";
18: }
19: else
20: {
21: empViewModel.SalaryColor = "green";
22: }
23: empViewModels.Add(empViewModel);
24: }
25: employeeListViewModel.Employees = empViewModels;
26: employeeListViewModel.UserName = "Admin";
27: return View("MyView", employeeListViewModel);
28: }
29: </employeeviewmodel></employeeviewmodel></employee>
7. 執行
關於實驗7
是否可以制定強型別View列表?
是的 為什麼要新建EmployeeListViewModel單獨的類而不直接使用強型別View的列表?1. 策劃未來會出現的呈現邏輯2. UserName屬性。UserName是與employees無關的屬性,與完整View相關的屬性。為什麼刪除EmployeeViewModel 的UserName屬性,而不是將它作為EmployeeListViewModel的一部分?UserName 是相同的,不需要EmployeeViewModel中新增UserName。
結論
以上就是我們第二天所講的內容,在第三天我們會學習新內容!
資料傳遞是MVC知識的重要組成部分,深入理解了這部分知識,能夠幫助我們更好的進行MVC的開發。同時,請記得藉助開發工具來助力開發過程,使用 這款輕量級控制元件,工作效率大大提高的同時,工作量也會大大減少。
相關閱讀: