7 天玩轉 ASP.NET MVC — 第 2 天

0. 前言

我相信在開始第 2 天的學習時,你已經順利地完成了第 1 天的課程。

我們回顧一下第 1 天的主要關注點:

  • 為什麼選擇 ASP.NET MVC ?

  • ASP.NET Webforms 和 ASP.NET MVC 的對比

  • 理解 ASP.NET MVC 的 Controller 以及 Views

提醒:如果你還沒有完成第 1 天的學習,最好先確保完成它。我們的目標是在最後一天用最佳實踐和最新技術方法來創建一個小的 MVC 項目。每一天的 Lab 訓練中,我們都會比之前一天增加一些實用性的功能,這樣看起來會比之前的程序更趨於完美。

1. Controller 向 View 傳輸數據

在 Lab 2 中,View 的創建都是偏於靜態的。然而在真實的場景中,View 展示的通常是一些動態數據。在下一個 Lab 中,我們將展示 View 中如何動態展示數據。

Advertisements

View 將從 Controller 中獲取以 Model 格式展示的數據。

Model

在 ASP.NET MVC 中,Model 展示的是業務數據。

Lab 3 - 使用 ViewData

ViewData 是一個字典,它存儲了 Controller 傳輸給 View 的數據。Controller 將向 ViewData 字典添加條目,然後 View 從這個字典里讀取。現在我們開始做一個 Demo 吧。

第一步:創建一個 Model 類

在 Model 文件夾下創建一個新的類,命名為 Employee。

public class Employee

{

public string FirstName { get; set; }

Advertisements

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 : @[email protected] <br/>

Employee Salary: @emp.Salary.ToString("C")

</div>

第五步:測試輸出

按下 F5,測試應用。

Lab 3 的 Q&A

寫 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 結構。

Lab 4 - 使用 ViewBag

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 並測試應用程序。

Lab 4 的 Q&A

我們是否可以傳輸 ViewData,然後以 ViewBag 的形式獲取到?

答案是肯定的。反過來也是可以的。就像我之前所提到過的,ViewBag 僅僅是 ViewData 的語法蜜糖。

ViewData 和 ViewBag 的問題

ViewData 和 ViewBag 是 Controller 與 View 之間傳輸數據的很好選擇方式。但是在實際的項目應用中,它們之中的任何一個都不是最佳的實踐方式。現在我們來討論一下運用 ViewData 和 ViewBag 的缺點吧。

性能問題

ViewData 中的數據類型是 Object。所以我們在使用之前需要進行正確的類型轉換。這個操作為性能帶來了額外的負擔。

沒有類型安全,也沒有編譯時的錯誤。

如果我們嘗試將類型轉換為錯誤的類型,或者我們在檢索對象值的時候使用錯誤的 Key 值,我們將會在運行時出錯。但是對於一個好的編程實踐而言,錯誤應該在編譯的時候就被捕獲到。

在數據傳輸和數據接收之間沒有正確的連接

作為一個開發者,我個人認為這是一個很主要的問題。

在 MVC 中, Controller 和 View 彼此之間的連接是弱連接,鬆散的。

Controller 完全不會關心 View 之中發生了什麼,同理,View 也完全不會關心 Controller 之中發生了什麼。

從 Controller 中我們可以傳輸一個或者多個 ViewData 或者 ViewBag 值。現在,當一個開發者要寫一個 View 時,他需要記住 Controller 將要傳輸什麼。如果一個 Controller 開發者與 View 開發者不是同一個人,那麼情況將會變得更困難。因為是完全的不關心,所以這將導致開發過程的低效率,也有可能引起運行錯誤。

Lab 5 - 理解強類型 Views

剛才上述關於 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);

第四步:測試並輸出

Lab 5 的 Q&A

每次在 View 中的類型聲明都需要使用類的全稱嗎,即 Namespace.ClassName ?

答案是否定的。我們可以運用 「using」聲明。

@using WebApplication1.Models

@model Employee

我們必須總是使用強類型視圖嗎,還是我們可以偶爾使用一下 ViewData 或者 ViewBag ?

如果想實踐最佳方式,最好使用強類型視圖。

我們可以為強類型視圖的 View 使用多個 Model 類型嗎 ?

答案是否定的。在實際項目中,當我們想要在一個視圖中展示多個 Model 時,我們經常會結束在這點上。這一需求的解決方案將在下一節中討論。

2. 理解 ASP.NET MVC 中的 View Model

在 Lab 5 中我們已經違反了 MVC 的準則。根據 MVC, V 代表的是純粹的 UI。它應該不包含任何的邏輯。我們已經通過如下的三點違反了 MVC 的結構規則:

  • 附加了 First Name 和 Last Name,並且用它們展示了全名。這屬於邏輯操作。

  • 以貨幣形式展示了 Salary。這屬於邏輯操作。

  • 展示了不同工資的不同顏色。這些基於不同值的簡單的操作改變了 HTML 元素的外觀。這屬於邏輯操作。

除了以上三點,這裡還有一個更值得討論的問題點。

這一種情形是,我們想要在 View 中展示不同類型的數據。比如:顯示當前登錄的用戶名稱和僱員數據。

我們可以使用如下兩種方式實現這個問題:

  1. 向 Employee 類增加一個 UserName 屬性。每一次我們想要在視圖中展示一個新數據,我們就像 Employee 類中增加一個屬性。這似乎是不合理的,這個屬性也許和 Employee 沒有關聯。這也違反了 SOLID 的 SRP 準則。

  2. 運用 ViewBag 或者 ViewData。這個方法我們已經在剛才討論了其弊端。

ViewModel 解決方案

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 來更好地理解它吧。

3. Lab 6 - 實現 View Model

第一步:創建一個文件夾

在項目中命名一個文件夾,命名為 ViewModels。

第二步:創建 EmployeeViewModel

為了做這一步,我們先來理清一下 View 的所有需求。

  1. First Name 和 LastName 需要合併展示,所以在展示前它們應該是合併的。

  2. 使用貨幣形式來顯示 Amount。

  3. 不同的 Salary 展示出不同的顏色。

  4. 當前的 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 中不再包含任何邏輯。

Lab 6 的 Q&A

這是否意味著,每一個 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 是一致的。

4. Lab 7 - View 中運用 Collection

在這一節 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,執行應用。

Lab 7 的 Q&A

我們能將視圖的強制類型為 List 嗎?

答案是肯定的。我們可以。

為什麼我們要創建一個單獨的類,即 EmployeeListViewModel,為什麼我們不使用強類型為 List< EmployeeListViewModel > 的View 呢?

如果我們直接運用 List,而不是使用 EmployeeListViewModel 類,會引起兩個問題。

  1. 未來也許會出現展示邏輯的需求。

  2. UserName 屬性。因為 UserName 和 Employees 是沒有關聯的。它是與一個完整的 View 相關聯。

為什麼我們要從 EmployeeViewModel 中移除 UserName 屬性,然後把它作為EmployeeListViewModel 中的一部分呢?

UserName 對所有僱員都是一樣的,如果將 UserName 的屬性保留在 EmployeeViewModel 中就會增加了冗餘代碼,也會為增加數據的傳輸額外內存空間。

5. 結語

我們已經完成了第 2 天的 MVC 學習。在第 3 天中我們將使得項目進入下一個階段。

讓我一起在學習中盡情徜徉吧!

原文地址:Learn MVC Project in 7 days

本文系 OneAPM 工程師編譯整理。OneAPM 是應用性能管理領域的新興領軍企業,能幫助企業用戶和開發者輕鬆實現:緩慢的程序代碼和 SQL 語句的實時抓取。想閱讀更多技術文章,請訪問 OneAPM 官方博客。

轉自:http://news.oneapm.com/7-days-asp-dotnet-mvc-day2/

Advertisements

你可能會喜歡