深入理解ASP.NET 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運行

clip_image001

關於實驗 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結構

clip_image003

實驗4——ViewBag的使用

ViewBag可以稱爲ViewData的一塊關於語法的輔助的糖果,ViewBag使用C# 4.0的動態特徵,使得ViewData也具有動態特性。

ViewData與ViewBag對比:

ViewData

ViewBag

它是Key/Value字典集合

它是dynamic類型對像

從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. 測試輸出

運行結果:

clip_image001[1]

關於實驗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類的屬性

clip_image004

添加以下代碼來顯示數據:

   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. 測試輸出

clip_image005

關於實驗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創建的。

具體的工作原理

  1. Controller 處理用戶交互邏輯或簡單的判斷。處理用戶需求
  2. Controller 獲取一個或多個Model數據
  3. Controller 決策哪個View最符合用戶的請求
  4. Controller 將根據Model數據和View需求創建並且初始化ViewModel對象。
  5. Controller 將ViewModel數據以ViewData或ViewBag或強類型View等對象傳遞到View中。
  6. 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. 測試輸出

clip_image006

儘管運行結果類似,但是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的開發。同時,請記得藉助開發工具來助力開發過程,使用 ComponentOne Studio ASP.NET MVC 這款輕量級控件,工作效率大大提高的同時,工作量也會大大減少。


發佈了354 篇原創文章 · 獲贊 182 · 訪問量 120萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章