我相信在開始第 2 天的學習時,你已經順利地完成了第 1 天的課程。html
咱們回顧一下第 1 天的主要關注點:數據庫
爲何選擇 ASP.NET MVC ?編程
ASP.NET Webforms 和 ASP.NET MVC 的對比安全
理解 ASP.NET MVC 的 Controller 以及 Views數據結構
提醒:若是你尚未完成第 1 天的學習,最好先確保完成它。咱們的目標是在最後一天用最佳實踐和最新技術方法來建立一個小的 MVC 項目。每一天的 Lab 訓練中,咱們都會比以前一天增長一些實用性的功能,這樣看起來會比以前的程序更趨於完美。mvc
在 Lab 2 中,View 的建立都是偏於靜態的。然而在真實的場景中,View 展現的一般是一些動態數據。在下一個 Lab 中,咱們將展現 View 中如何動態展現數據。性能
View 將從 Controller 中獲取以 Model 格式展現的數據。學習
Model測試
在 ASP.NET MVC 中,Model 展現的是業務數據。編碼
ViewData 是一個字典,它存儲了 Controller 傳輸給 View 的數據。Controller 將向 ViewData 字典添加條目,而後 View 從這個字典裏讀取。如今咱們開始作一個 Demo 吧。
第一步:建立一個 Model 類
在 Model 文件夾下建立一個新的類,命名爲 Employee。
public class Employee { public string FirstName { get; set; } public string LastName { get; set; } public int Salary { get; set; } }
第二步:從 Controller 中獲取 Model
在 GetView 方法中建立一個 Employee 對象。
Employee emp = new Employee(); emp.FirstName = "Sukesh"; emp.LastName="Marla"; emp.Salary = 20000;
注意:確保在類中使用 Using 語句將 Model 引入,不然就要在編寫程序時使用 Employee 類的全名。
using WebApplication1.Models;
第三步:建立 ViewData 並返回 View
在 ViewData 中存儲 Employee 對象。
ViewData["Employee"] = emp; return View("MyView");
第四步:在 View 中展現 Employee 數據
打開文件 MyView.cshtml。從 ViewData 中檢索 Employee 數據並展現。
<div> @{ WebApplication1.Models.Employee emp = (WebApplication1.Models.Employee)ViewData["Employee"]; } <b>Employee Details </b><br/> Employee Name : @emp.FirstName@emp.LastName <br/> Employee Salary: @emp.Salary.ToString("C") </div>
第五步:測試輸出
按下 F5,測試應用。
寫 Razor 代碼的過程當中,使用花括號「『{』和『}』」和不使用花括號,有什麼區別?
在 lab 3 中,@emp.FirstName 可使用如下代碼替換。
@{ Response.Write(emp.FirstName); }
若是在 @ 後沒有使用花括號,那麼它僅僅是爲了展現變量或者表達式的值。
爲何須要強制轉換?
ViewData 內部承載了一些對象。每一次增長一個新值,就會把它轉換爲 Object 類型。
因此每一次都須要強制轉換來獲取對象的值。
「@emp.FirstName @emp.LastName」的含義是什麼?
這個意味着 LastName 展現在 FirstName 以後,並經過空格隔開。
若是隻想使用一個 @ 關鍵字,能作到剛纔的效果嗎?
答案是確定的。經過語法 @(emp.FirstName+」」+emp.LastName)。
爲何在 Controller 類中要硬編碼 Employee 類?
這僅僅是爲了展現 demo。實際上,咱們將會在數據庫,WCF ,Web Service 或者其它地方獲取數據。
什麼是數據庫邏輯,數據訪問層以及業務層?
數據訪問層在 ASP.NET MVC 中是一個未顯示的層。實際上,它一直存在,可是在 MVC 的定義中歷來沒包含過它。
業務層像以前所解釋的,它是 Model 的一部分。
完整的 MVC 結構。
ViewBag 就像是 ViewData 的語法蜜糖。ViewBag 運用 C# 4.0 的動態特徵,使得 ViewData 動態化。
ViewBag 內部運用 ViewData。
第一步:建立 View Bag
繼續 Lab 3,而後用以下代碼片斷替換 Lab 3 中的第三步:
ViewBag.Employee = emp;
第二步:在 View 中展現 EmployeeData
用以下的代碼片斷替換 Lab3 中的第四步:
@{ WebApplication1.Models.Employee emp = (WebApplication1.Models.Employee)ViewBag.Employee; } Employee Details Employee Name: @emp.FirstName @emp.LastName Employee Salary: @emp.Salary.ToString("C")
第三步:測試並輸出
按下 F5 並測試應用程序。
咱們是否能夠傳輸 ViewData,而後以 ViewBag 的形式獲取到?
答案是確定的。反過來也是能夠的。就像我以前所提到過的,ViewBag 僅僅是 ViewData 的語法蜜糖。
ViewData 和 ViewBag 是 Controller 與 View 之間傳輸數據的很好選擇方式。可是在實際的項目應用中,它們之中的任何一個都不是最佳的實踐方式。如今咱們來討論一下運用 ViewData 和 ViewBag 的缺點吧。
ViewData 中的數據類型是 Object。因此咱們在使用以前須要進行正確的類型轉換。這個操做爲性能帶來了額外的負擔。
若是咱們嘗試將類型轉換爲錯誤的類型,或者咱們在檢索對象值的時候使用錯誤的 Key 值,咱們將會在運行時出錯。可是對於一個好的編程實踐而言,錯誤應該在編譯的時候就被捕獲到。
做爲一個開發者,我我的認爲這是一個很主要的問題。
在 MVC 中, Controller 和 View 彼此之間的鏈接是弱鏈接,鬆散的。
Controller 徹底不會關心 View 之中發生了什麼,同理,View 也徹底不會關心 Controller 之中發生了什麼。
從 Controller 中咱們能夠傳輸一個或者多個 ViewData 或者 ViewBag 值。如今,當一個開發者要寫一個 View 時,他須要記住 Controller 將要傳輸什麼。若是一個 Controller 開發者與 View 開發者不是同一我的,那麼狀況將會變得更困難。由於是徹底的不關心,因此這將致使開發過程的低效率,也有可能引發運行錯誤。
剛纔上述關於 ViewData 和 ViewBag 的三點問題能夠歸結因而由數據類型所引發的。ViewData 中存儲的數據類型是 「Object」。
若是以某種方式,咱們可以爲傳輸在 Controller 和 View 中的數據設置數據類型,那麼問題將會迎刃而解,而這種方式即是強類型 Views。
如今讓咱們作一個 Demo。此次咱們將會提高 View 的需求到下一個級別層次。若是薪水大於 15000,那麼那麼就展現爲黃顏色,不然爲綠顏色。
第一步:建立強類型的 View
在 View 的頂部加上以下代碼:
@model WebApplication1.Models.Employee
基於這條語句,使得咱們的 View 成爲一個類型爲 Employee 的強類型視圖。
第二步:展現數據
如今,在 View 中,僅僅使用 @Model 和 Dot(.) 操做就能夠智能獲取 Model,即 Empolyee 的全部數據值。
寫下以下代碼來展現數據:
Employee Details Employee Name : @Model.FirstName @Model.LastName @if(Model.Salary>15000) { <span style="background-color:yellow"> Employee Salary: @Model.Salary.ToString("C") </span> } else { <span style="background-color:green"> Employee Salary: @Model.Salary.ToString("C") </span> }
第三步:從 Controller 的 Action 方法傳輸 Model 數據
更改 Action 方法爲以下代碼片斷:
Employee emp = new Employee(); emp.FirstName = "Sukesh"; emp.LastName="Marla"; emp.Salary = 20000; return View("MyView",emp);
第四步:測試並輸出
每次在 View 中的類型聲明都須要使用類的全稱嗎,即 Namespace.ClassName ?
答案是否認的。咱們能夠運用 「using」聲明。
@using WebApplication1.Models @model Employee
咱們必須老是使用強類型視圖嗎,仍是咱們能夠偶爾使用一下 ViewData 或者 ViewBag ?
若是想實踐最佳方式,最好使用強類型視圖。
咱們能夠爲強類型視圖的 View 使用多個 Model 類型嗎 ?
答案是否認的。在實際項目中,當咱們想要在一個視圖中展現多個 Model 時,咱們常常會結束在這點上。這一需求的解決方案將在下一節中討論。
在 Lab 5 中咱們已經違反了 MVC 的準則。根據 MVC, V 表明的是純粹的 UI。它應該不包含任何的邏輯。咱們已經經過以下的三點違反了 MVC 的結構規則:
附加了 First Name 和 Last Name,而且用它們展現了全名。這屬於邏輯操做。
以貨幣形式展現了 Salary。這屬於邏輯操做。
展現了不一樣工資的不一樣顏色。這些基於不一樣值的簡單的操做改變了 HTML 元素的外觀。這屬於邏輯操做。
除了以上三點,這裏還有一個更值得討論的問題點。
這一種情形是,咱們想要在 View 中展現不一樣類型的數據。好比:顯示當前登陸的用戶名稱和僱員數據。
咱們可使用以下兩種方式實現這個問題:
向 Employee 類增長一個 UserName 屬性。每一次咱們想要在視圖中展現一個新數據,咱們就像 Employee 類中增長一個屬性。這彷佛是不合理的,這個屬性也許和 Employee 沒有關聯。這也違反了 SOLID 的 SRP 準則。
運用 ViewBag 或者 ViewData。這個方法咱們已經在剛纔討論了其弊端。
ViewModel 是 ASP.NET MVC 應用中沒有聲明出的層。它適合於 Model 和 View 之間而且爲 View 做爲一個數據容器。
Model 和 ViewModel 的區別是什麼?
Model 特指業務數據。它基於業務和數據結構建立。ViewModel 特指 View 數據。它基於視圖 View 建立。
ViewModel是如何工做的?
工做原理很是簡單。
Controller 處理用戶的交互邏輯,或者簡單來講,處理用戶請求。
Controller 得到一個或多個 Model 數據。
Controller 將決定哪一個 View 爲請求做出正確迴應。
Controller 將會根據視圖的需求從接收的 Model 數據中建立並初始化 ViewModel 對象。
Controller 將會以 ViewData/ViewBag/強類型 View 的方式傳輸 ViewModel 數據給 View。
Controller 將會返回 View。
View 和 ViewModel 將如何關聯?
View 將會是一個以 ViewModel 爲強類型的視圖。
Model 和 ViewModel 將如何關聯?
Model 和 ViewModel 彼此之間應該是獨立的。Controller 將會基於一個或多個 Model 對象來建立並初始化 ViewModel 對象。
讓咱們作一個小的 Lab 來更好地理解它吧。
第一步:建立一個文件夾
在項目中命名一個文件夾,命名爲 ViewModels。
第二步:建立 EmployeeViewModel
爲了作這一步,咱們先來理清一下 View 的全部需求。
First Name 和 LastName 須要合併展現,因此在展現前它們應該是合併的。
使用貨幣形式來顯示 Amount。
不一樣的 Salary 展現出不一樣的顏色。
當前的 User Name 也要展現在視圖中。
在 ViewModels 文件夾下建立一個 EmployeeViewModel 類,以下所示:
public class EmployeeViewModel { public string EmployeeName { get; set; } public string Salary { get; set; } public string SalaryColor { get; set; } public string UserName{get;set;} }
須要注意的是,在這個 ViewModel 類中, FirstName 和 LastName 被一個屬性所替代,即 EmployeeName。而且 Salary 的數據類型是 String,除此以外,又增長了兩個屬性,即 SalaryColor 和 UserName。
第三步:在 View 中運用 ViewModel
在 Lab 5 中,咱們將 View 強類型爲 Employee。如今將其強類型爲 EmployeeViewModel。
@using WebApplication1.ViewModels @model EmployeeViewModel
第四步:在 View 中展現數據。
使用以下的代碼片斷替換 View 中的內容:
Hello @Model.UserName <hr /> <div> <b> Employee Details</b><br /> Employee Name : @Model.EmployeeName <br /> <span style="background-color:@Model.SalaryColor"> Employee Salary: @Model.Salary </span> </div>
第五步:建立而且傳輸 ViewModel
在 GetView 動做方法中,得到 Model 數據,而後將其轉換爲 ViewModel 對象,以下所示:
public ActionResult GetView() { Employee emp = new Employee(); emp.FirstName = "Sukesh"; emp.LastName="Marla"; emp.Salary = 20000; EmployeeViewModel vmEmp = new EmployeeViewModel(); vmEmp.EmployeeName = emp.FirstName + " " + emp.LastName; vmEmp.Salary = emp.Salary.ToString("C"); if(emp.Salary>15000) { vmEmp.SalaryColor="yellow"; } else { vmEmp.SalaryColor = "green"; } vmEmp.UserName = "Admin" return View("MyView", vmEmp); }
第六步:測試並輸出
按下 F5 並測試輸出。
輸出的結果和 Lab 5 的同樣,可是此次 View 中再也不包含任何邏輯。
這是否意味着,每個 Model 都會有一個 ViewModel?
答案是否認的。事實上,是每個 View 都會有一個 ViewModel。
Model 和 ViewModel 之間存在一些關聯是一個好的實踐方式嗎?
答案是否認的。做爲一個最佳實踐,Model 和 ViewModel 彼此之間應該是獨立的,而不是關聯的。
咱們須要老是建立 ViewModel 嗎? 若是 View 不包含任何展現邏輯而且 View 只展現 Model 的數據會怎樣?
咱們應該老是建立 ViewModel。每個 View 都應該擁有它們本身的 ViewModel,即便 ViewModel 的屬性和 Model 的屬性徹底同樣。
假設一種情形,View 不包含展現邏輯,而且使用 Model 數據,而不是 ViewModel。
問題是,若是將來有了向 UI 增長新數據的需求,或者是展現邏輯的需求,那麼咱們就須要從新規劃一個 UI 了。
因此最好是咱們在一開始就建立 ViewModel 以防止需求增長。在這種情形中,ViewModel 的初始階段幾乎和 Model 是一致的。
在這一節 Lab 中,咱們將在 View 中展現 Employees 的列表。
第一步:改變 EmployeeViewModel 類
從 EmployeeViewModel 類中移除 UserName 屬性。
public class EmployeeViewModel { public string EmployeeName { get; set; } public string Salary { get; set; } public string SalaryColor { get; set; } }
第二步:建立集合
在 ViewModel 文件夾下建立一個類,命名爲EmployeeListViewModel。
public class EmployeeListViewModel { public List<EmployeeViewModel> Employees { get; set; } public string UserName { get; set; } }
第三步:更改 View 的強類型
將 MyView.cshtml 的強類型更換爲 EmployeeListViewModel。
@using WebApplication1.ViewModels @model EmployeeListViewModel
第四步:在 View 中展現全部的僱員信息。
<body> Hello @Model.UserName <hr /> <div> <table> <tr> <th>Employee Name</th> <th>Salary</th> </tr> @foreach (EmployeeViewModel item in Model.Employees) { <tr> <td>@item.EmployeeName</td> <td style="background-color:@item.SalaryColor">@item.Salary</td> </tr> } </table> </div> </body>
第五步:爲 Employee 建立 Business Layer
在這個 Lab 中,咱們將會提高咱們的項目到一個新級別。咱們將會向項目中增長 Business Layer。在項目中建立一個新的文件夾,命名爲 BusinessLayer,而後建立一個新的類,命名爲 EmployeeBusinessLayer,該類裏面包含一個方法,命名爲 GetEmployees。
public class EmployeeBusinessLayer { public List<Employee> GetEmployees() { List<Employee> employees = new List<Employee>(); Employee emp = new Employee(); emp.FirstName = "johnson"; emp.LastName = " fernandes"; emp.Salary = 14000; employees.Add(emp); emp = new Employee(); emp.FirstName = "michael"; emp.LastName = "jackson"; emp.Salary = 16000; employees.Add(emp); emp = new Employee(); emp.FirstName = "robert"; emp.LastName = " pattinson"; emp.Salary = 20000; employees.Add(emp); return employees; } }
第六步:從 Controller 中傳數據
public ActionResult GetView() { EmployeeListViewModel employeeListViewModel = new EmployeeListViewModel(); EmployeeBusinessLayer empBal = new EmployeeBusinessLayer(); List<employee> employees = empBal.GetEmployees(); List<EmployeeViewModel> empViewModels = new List<EmployeeViewModel>(); foreach (Employee emp in employees) { EmployeeViewModel empViewModel = new EmployeeViewModel(); empViewModel.EmployeeName = emp.FirstName + " " + emp.LastName; empViewModel.Salary = emp.Salary.ToString("C"); if (emp.Salary > 15000) { empViewModel.SalaryColor = "yellow"; } else { empViewModel.SalaryColor = "green"; } empViewModels.Add(empViewModel); } employeeListViewModel.Employees = empViewModels; employeeListViewModel.UserName = "Admin"; return View("MyView", employeeListViewModel); }
第七步:執行並測試輸出
按下 F5,執行應用。
咱們能將視圖的強制類型爲 List 嗎?
答案是確定的。咱們能夠。
爲何咱們要建立一個單獨的類,即 EmployeeListViewModel,爲何咱們不使用強類型爲 List< EmployeeListViewModel > 的View 呢?
若是咱們直接運用 List,而不是使用 EmployeeListViewModel 類,會引發兩個問題。
將來也許會出現展現邏輯的需求。
UserName 屬性。由於 UserName 和 Employees 是沒有關聯的。它是與一個完整的 View 相關聯。
爲何咱們要從 EmployeeViewModel 中移除 UserName 屬性,而後把它做爲EmployeeListViewModel 中的一部分呢?
UserName 對全部僱員都是同樣的,若是將 UserName 的屬性保留在 EmployeeViewModel 中就會增長了冗餘代碼,也會爲增長數據的傳輸額外內存空間。
咱們已經完成了第 2 天的 MVC 學習。在第 3 天中咱們將使得項目進入下一個階段。
讓我一塊兒在學習中盡情徜徉吧!