ASP.NET MVC第006天_ViewData,ViewBag,TempData用法與差異比較

在前幾篇有用到從Controller傳遞一些變數值給View的技巧
事實上在.net mvc中不只這一種方法

頁面間和Controller與View之間傳遞引數有幾種方式?
Ans:共有4種ViewData,ViewBag,Session,TempData



基本上在ViewPage終究有明確定義如下幾種
能將資料Pass到View的屬性

Gets or sets a dictionary that contains data to pass between the controller and the view.
public System.Web.Mvc.ViewDataDictionary ViewData { get; set; }

解釋:
自早期的asp.net MVC版本(1和2)就存在的一個ViewPage屬性,
屬於 Dictionary Object,衍生自 ViewDataDictionary ,能放入任何資料,
使用 Key / Value 的概念存取。

生命週期:僅存於當前的連線請求若發生網頁Redirect就會變Null。
(只有在從Controller到View中)

缺點:
1.值不能在多個請求中共享,不能跨Action傳遞資料,只能在一個Action有效。
(在重redirection後,ViewData中儲存的變數值將變為null。)
2.取出ViewData中的變數值後,必須進行合適的型別轉換(隱式或顯式)和null檢查。
3.沒有IntelliSense

用法:
ViewData["KeyName"]=XXX


Gets the view bag.
public dynamic ViewBag { get; }

解釋:
比較後期才添加的新屬性
跟ViewData有異曲同工之妙,屬於ViewData的封裝集合(把一堆ViewData打包裝放在一個包包)。
本質也是使用 Key / Value 存取,並能放入任何的資料,
而差異在於,它能產生「動態屬性」(.net 4.0 dynamic)
也就是在runtime時候再判斷真正型別 (C# reflection)


生命週期:僅存於當前的連線請求若發生網頁Redirect就會變Null。
(只有在從Controller到View中)

缺點:
1.值不能在多個請求中共享,不能跨Action傳遞資料,只能在一個Action有效。
(在重redirection後,ViewData中儲存的變數值將變為null。)
2.動態的屬性沒有IntelliSense ,需額外先強制轉型才有。

用法:
ViewBag.KeyName = XXX


提醒:
1.ViewBag 和 ViewData 的Key是共用的。
所以若使用 ViewData["Country"] = "Japan" 而後面又寫 ViewBag.Country= "Korea" ,
則最後使用到 key 值為 Country的資料就會變成 Korea。

2.要注意 key 值是唯一的不能重複,如果重複使用就會被覆蓋掉。
3.Key值不區分大小寫(例如: Address 會等同於 address)


程式碼的案例
HomeController.cs

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Data;
  4. using System.Linq;
  5. using System.Web;
  6. using System.Web.Mvc;
  7.  
  8. namespace MyEmptyMVC1.Controllers
  9. {
  10. public class HomeController : Controller
  11. {
  12. // GET: Home
  13. public ActionResult Index()
  14. {
  15. #region 用ViewData來Pass值
  16. ViewData["DatetimeNow"] = DateTime.Now;
  17. ViewData["Address"] = "臺北市信義區市府路1號";
  18. ViewData["Years"] = 28;
  19. ViewData["Percent"] = 0.85;
  20.  
  21. ViewData["UnitPrice"] = 80;
  22. ViewData["CountOfOneWeek"] = 5;
  23.  
  24. List<string> lsFruit = new List<string>();
  25. lsFruit.Add("Orange");
  26. lsFruit.Add("Banana");
  27. lsFruit.Add("Peach");
  28.  
  29. ViewData["FruitList"] = lsFruit;
  30.  
  31. DataTable dt = new DataTable();
  32. dt.Columns.Add("Name");
  33. dt.Columns.Add("Title");
  34. dt.Columns.Add("Years");
  35.  
  36. DataRow row1 = dt.NewRow();
  37. row1["Name"] = "Amy";
  38. row1["Title"] = "會計";
  39. row1["Years"] = 5;
  40. dt.Rows.Add(row1);
  41. DataRow row2 = dt.NewRow();
  42. row2["Name"] = "Jack";
  43. row2["Title"] = "工程師";
  44. row2["Years"] = 8;
  45. dt.Rows.Add(row2);
  46. ViewData["EmployeeInfo"] = dt;
  47. #endregion
  48.  
  49. #region 用ViewBag來Pass值
  50. ViewBag.NowDate = DateTime.Now.Date;
  51. ViewBag.address = "台北市萬華";
  52. ViewBag.Num = 7;
  53. ViewBag.PI = 3.1415;
  54.  
  55. List<string> lsWeek = new List<string>();
  56. lsWeek.Add("Monday");
  57. lsWeek.Add("Tuesday");
  58. lsWeek.Add("Wednesday");
  59. lsWeek.Add("Thursday");
  60. lsWeek.Add("Friday");
  61. lsWeek.Add("Saturday");
  62. lsWeek.Add("Sunday");
  63. ViewBag.WeekDay = lsWeek;
  64.  
  65. DataTable dtScore = new DataTable();
  66. dtScore.Columns.Add("Name");
  67. dtScore.Columns.Add("Grade");
  68. dtScore.Columns.Add("Score");
  69.  
  70. DataRow dr1 = dtScore.NewRow();
  71. dr1["Name"] = "Tom";
  72. dr1["Grade"] = "一年級";
  73. dr1["Score"] = 82;
  74. dtScore.Rows.Add(dr1);
  75.  
  76. DataRow dr2 = dtScore.NewRow();
  77. dr2["Name"] = "Jason";
  78. dr2["Grade"] = "一年級";
  79. dr2["Score"] = 89;
  80. dtScore.Rows.Add(dr2);
  81.  
  82. DataRow dr3 = dtScore.NewRow();
  83. dr3["Name"] = "Mike";
  84. dr3["Grade"] = "二年級";
  85. dr3["Score"] = 93;
  86. dtScore.Rows.Add(dr3);
  87.  
  88. DataRow dr4 = dtScore.NewRow();
  89. dr4["Name"] = "Jason";
  90. dr4["Grade"] = "二年級";
  91. dr4["Score"] = 98;
  92. dtScore.Rows.Add(dr4);
  93.  
  94.  
  95.  
  96. ViewBag.ScoreTable = dtScore;
  97.  
  98.  
  99. #endregion
  100.  
  101.  
  102. return View();
  103. }
  104. }
  105. }


Index.cshtml

  1. @{
  2. Layout = null;
  3. }
  4. @using System.Data; @*for DataTable,DataRow,DataSet用*@
  5.  
  6.  
  7. <!DOCTYPE html>
  8.  
  9. <html>
  10. <head>
  11. <meta name="viewport" content="width=device-width" />
  12. <title>Index</title>
  13. </head>
  14. <body>
  15. <div>
  16. 用ViewData來Pass值<br />
  17.  
  18. 現在時間:@ViewData["DatetimeNow"]<br />
  19. 住址:@ViewData["Address"]<br />
  20. 年齡:@ViewData["Years"]<br />
  21. 百分比:@ViewData["Percent"]<br />
  22.  
  23. 一週上班午餐餐費(週一至周五)_不會印出計算結果: @ViewData["UnitPrice"] * @ViewData["CountOfOneWeek"] <br />
  24.  
  25. @*Razor中直接返回運算結果要用@(....) 包覆,ViewData記得做Cast轉型*@
  26. 一週上班午餐餐費(週一至周五)_會印出計算結果: @( (int)@ViewData["UnitPrice"] * (int)@ViewData["CountOfOneWeek"] ) <br />
  27.  
  28. 水果清單:<br />
  29. <ul>
  30. @foreach (string item in (List<string>)ViewData["FruitList"])
  31. {
  32. <li>@item</li>
  33. }
  34. </ul>
  35.  
  36. <table>
  37. <tr>
  38. <th>職員姓名</th>
  39. <th>職稱</th>
  40. <th>年資</th>
  41. </tr>
  42. @*在一開始記得引入@using System.Data;*@
  43. @foreach (DataRow item in (ViewData["EmployeeInfo"] as DataTable).Rows)
  44. {
  45. <tr>
  46. <td>@item["Name"]</td>
  47. <td>@item["Title"]</td>
  48. <td>@item["Years"]</td>
  49. </tr>
  50. }
  51. </table>
  52.  
  53.  
  54. 用ViewBag來Pass值<br />
  55. 今天日期:@ViewBag.NowDate<br />
  56. 住址(用小寫):@ViewBag.address<br />
  57. 住址(用大寫第一個開頭)_觀察Key大小寫有無差別:@ViewData["Address"]<br />
  58. 住址(用大寫第一個開頭)_觀察ViewBag跟ViewData是否Key共用:@ViewBag.Address<br />
  59.  
  60. 一週有 @ViewBag.Num<br />
  61. 圓周率:@ViewBag.PI <br />
  62.  
  63. <ol>
  64. @foreach (string item in (List<string>)ViewBag.WeekDay)
  65. {
  66. <li>@item</li>
  67. }
  68. </ol>
  69.  
  70. <h3>學生成績清單</h3>
  71. <dl>
  72. @foreach(DataRow item in ((DataTable)ViewBag.ScoreTable).Rows)
  73. {
  74. <dt>@item["Grade"] </dt>
  75. <dd>@item["Name"]</dd>
  76. <dd>@item["Score"]</dd>
  77. }
  78. </dl>
  79.  
  80.  
  81. </div>
  82. </body>
  83. </html>
  84.  
運行結果



會發現第17行Address
ViewData["Address"] = "臺北市信義區市府路1號";

已經被第51行的用小寫開頭的ViewBag給覆蓋掉了
ViewBag.address = "台北市萬華";



驗證了
1.ViewBag 和 ViewData 的Key是共用的。
3.Key值不區分大小寫(例如: Address 會等同於 address)


此外印出一週餐費的View中調用的寫法
Razor中直接返回運算結果要用@(....) 包覆,ViewData記得做Cast轉型。



Gets the temporary data to pass to the view.
TempData is used to pass data from current request to subsequent request (means redirecting from one page to another).
public System.Web.Mvc.TempDataDictionary TempData { get; }

TempData也是 Dictionary 類別, 衍生自 TempDataDictionary 纇, 要注意字典資料轉型跟Null問題。
有別於ViewData與ViewBag,差異點在於所儲存的資料物件的生命週期。
如果頁面發生了跳轉(Redirection),ViewBag和ViewData中的值將不復存在, 
但是TempData中的值依然還在。

當你希望僅在一個HTTP 請求和下一個 HTTP 請求之間保留資料時,可以使用 TempData 。


換言之, ViewBag和ViewData儲存的值的生命週期只有在從Controller到View中,
而TempData中的資料不僅在從Controller到View中有效,
在不同的Action之間或者從一個頁面跳轉到另一頁面(Controller to Controller)後依然有效。



生命週期:除了當下請求, 導頁後仍可續存 (如action to action, controller to action),但如果在View中一被讀取(或顯示出來)就會被刪除。
(TempData中資料只要一被讀取過就會被標記為已用過要被刪除。)

優點:
可跨controller,跨action,不僅僅只是單向的從Controller到View。

缺點:
1.取出TempData中的變數值後,必須進行合適的型別轉換(隱式或顯式)和null檢查。
2.沒有IntelliSense

程式碼的案例
在HomeController新增兩動作(Page1,  Page2)和相應的View
下中斷點執行測試

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Data;
  4. using System.Linq;
  5. using System.Web;
  6. using System.Web.Mvc;
  7.  
  8. namespace MyEmptyMVC1.Controllers
  9. {
  10. public class HomeController : Controller
  11. {
  12. // GET: Home
  13. public ActionResult Index()
  14. {
  15. return View();
  16. }
  17.  
  18.  
  19. public ActionResult Page1()
  20. {
  21. TempData["datetime"] = DateTime.Now;
  22. TempData["TmpData"] = "Tmp Data A";
  23.  
  24. ViewData["vd_data"] = "test viewdata A";
  25. ViewBag.vb_data = "test viewbagdata A";
  26.  
  27. return RedirectToAction("Page2");
  28. }
  29.  
  30. public ActionResult Page2()
  31. {
  32. string str = TempData["datetime"].ToString();
  33. string str1 = TempData["TmpData"].ToString();
  34.  
  35. string str_view_data = ViewData["vd_data"]?.ToString();
  36. string str_view_bag = ViewBag.vb_data?.ToString();
  37.  
  38. return View("Page1");
  39. }
  40.  
  41.  
  42. }
  43. }

運行結果測試
一開始進到Page1 的Action



隨後又Redirect到另一Action時候,就會發現只剩下TempData仍保存上一次Request的值。


TempData還有一個重點就在於之所以被稱作為TempData的原因在於
被寫入的資料在第一次讀取的時候就會被刪除了。
(儲存到 TempData 的資料會存放在Session中,並將在訪問資料的第一個請求結束時自動刪除。
如果從未讀過,它將一直保留到最後一次讀取或session timeout。)

ASP.NET MVC 系列4 - ViewData與TempData


這次針對TempData修改一下例子觀察
若是於Page1, Page2都直接讀取TempData會有捨麼情況

測試Page1 -> Page2的導向過程中TempData的生命週期

Page1.cshtml

  1.  
  2. @{
  3. Layout = null;
  4. }
  5.  
  6. <!DOCTYPE html>
  7.  
  8. <html>
  9. <head>
  10. <meta name="viewport" content="width=device-width" />
  11. <title>Page1</title>
  12. </head>
  13. <body>
  14. <div>
  15. <h1>Page1</h1>
  16. Now Time:@TempData["datetime"]
  17. <br />
  18. TmpData:@TempData["TmpData"]
  19. <br />
  20.  
  21. @Html.ActionLink("連結到Page2","Page2","Home")
  22.  
  23. </div>
  24. </body>
  25. </html>
  26.  


Page2.cshtml

  1.  
  2. @{
  3. Layout = null;
  4. }
  5.  
  6. <!DOCTYPE html>
  7.  
  8. <html>
  9. <head>
  10. <meta name="viewport" content="width=device-width" />
  11. <title>Page2</title>
  12. </head>
  13. <body>
  14. <div>
  15. <h1>Page2</h1>
  16. Now Time:@TempData["datetime"]
  17. <br />
  18. TmpData:@TempData["TmpData"]
  19. </div>
  20. </body>
  21. </html>
  22.  
HomeController.cs

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Data;
  4. using System.Linq;
  5. using System.Web;
  6. using System.Web.Mvc;
  7.  
  8. namespace MyEmptyMVC1.Controllers
  9. {
  10. public class HomeController : Controller
  11. {
  12. // GET: Home
  13. public ActionResult Index()
  14. {
  15. #region 用ViewData來Pass值
  16. ViewData["DatetimeNow"] = DateTime.Now;
  17. ViewData["Address"] = "臺北市信義區市府路1號";
  18. ViewData["Years"] = 28;
  19. ViewData["Percent"] = 0.85;
  20.  
  21. ViewData["UnitPrice"] = 80;
  22. ViewData["CountOfOneWeek"] = 5;
  23.  
  24. List<string> lsFruit = new List<string>();
  25. lsFruit.Add("Orange");
  26. lsFruit.Add("Banana");
  27. lsFruit.Add("Peach");
  28.  
  29. ViewData["FruitList"] = lsFruit;
  30.  
  31. DataTable dt = new DataTable();
  32. dt.Columns.Add("Name");
  33. dt.Columns.Add("Title");
  34. dt.Columns.Add("Years");
  35.  
  36. DataRow row1 = dt.NewRow();
  37. row1["Name"] = "Amy";
  38. row1["Title"] = "會計";
  39. row1["Years"] = 5;
  40. dt.Rows.Add(row1);
  41. DataRow row2 = dt.NewRow();
  42. row2["Name"] = "Jack";
  43. row2["Title"] = "工程師";
  44. row2["Years"] = 8;
  45. dt.Rows.Add(row2);
  46. ViewData["EmployeeInfo"] = dt;
  47. #endregion
  48.  
  49. #region 用ViewBag來Pass值
  50. ViewBag.NowDate = DateTime.Now.Date;
  51. ViewBag.address = "台北市萬華";
  52. ViewBag.Num = 7;
  53. ViewBag.PI = 3.1415;
  54.  
  55. List<string> lsWeek = new List<string>();
  56. lsWeek.Add("Monday");
  57. lsWeek.Add("Tuesday");
  58. lsWeek.Add("Wednesday");
  59. lsWeek.Add("Thursday");
  60. lsWeek.Add("Friday");
  61. lsWeek.Add("Saturday");
  62. lsWeek.Add("Sunday");
  63. ViewBag.WeekDay = lsWeek;
  64.  
  65. DataTable dtScore = new DataTable();
  66. dtScore.Columns.Add("Name");
  67. dtScore.Columns.Add("Grade");
  68. dtScore.Columns.Add("Score");
  69.  
  70. DataRow dr1 = dtScore.NewRow();
  71. dr1["Name"] = "Tom";
  72. dr1["Grade"] = "一年級";
  73. dr1["Score"] = 82;
  74. dtScore.Rows.Add(dr1);
  75.  
  76. DataRow dr2 = dtScore.NewRow();
  77. dr2["Name"] = "Jason";
  78. dr2["Grade"] = "一年級";
  79. dr2["Score"] = 89;
  80. dtScore.Rows.Add(dr2);
  81.  
  82. DataRow dr3 = dtScore.NewRow();
  83. dr3["Name"] = "Mike";
  84. dr3["Grade"] = "二年級";
  85. dr3["Score"] = 93;
  86. dtScore.Rows.Add(dr3);
  87.  
  88. DataRow dr4 = dtScore.NewRow();
  89. dr4["Name"] = "Jason";
  90. dr4["Grade"] = "二年級";
  91. dr4["Score"] = 98;
  92. dtScore.Rows.Add(dr4);
  93.  
  94.  
  95.  
  96. ViewBag.ScoreTable = dtScore;
  97.  
  98.  
  99. #endregion
  100.  
  101.  
  102. return View();
  103. }
  104.  
  105.  
  106. public ActionResult Page1()
  107. {
  108. TempData["datetime"] = DateTime.Now;
  109. TempData["TmpData"] = "Tmp Data A";
  110. return View();
  111. }
  112.  
  113. public ActionResult Page2()
  114. {
  115. return View();
  116. }
  117.  
  118.  
  119. }
  120. }
就會發現第一次導向Page1時候
原存於TempData的值
再點導向Page2的link後就不見了



所以可得證
View讀取一次對應的TempData後即從TempData集合中刪除
不過如果TempData未被View讀取之前,其值可在Controller之間傳遞直到session timeout。

下圖為TempData 完整生命週期示意圖
摘自:


若不想TempData被View讀取使用後就被刪除,可透過如下兩種保存機制
1.使用TempData.Peek來長期儲存。
2.若是只想再儲存一次,之後被View再次讀取後就刪除則要使用TempData.Keep。


四種情境的說明

1. Not Read in First Request : 
If we do not read “TempData” in the current request then “TempData” value will be persisted for the next request.

2.Read In First Request : 
If we read “TempData” in the current request then “TempData” value will be not persist for the next request.

3.Read & Persist using Keep :
 If we read “TempData” in the current request and we can keep method to persist TempData for the next request. In MVC, we are having void keep() and  void keep(string key) methods to persist the data.

4.Peek and Read:
If you set a TempData in your action method and if you read it in your view by calling "Peek" method then TempData will be persisted and will be available in next request.


TempData.Keep使用方式
Keep() method marks the specified key in the dictionary for retention
主要功能是將被標註狀態為要刪除的資料恢復成不被刪除狀態

有分
保留特定Key的
public void Keep(string key);

跟全部保留的
public void Keep();





這裡在多擴充一個Page3的Action跟相應的View
來測試Page1 -> Page2 -> Page3的導向過程中TempData使用Keep的生命週期

Page1.cshtml
  1.  
  2. @{
  3. Layout = null;
  4. }
  5.  
  6. <!DOCTYPE html>
  7.  
  8. <html>
  9. <head>
  10. <meta name="viewport" content="width=device-width" />
  11. <title>Page1</title>
  12. </head>
  13. <body>
  14. <div>
  15. <h1>Page1</h1>
  16. Now Time:@TempData["datetime"]
  17. <br />
  18. TmpData:@TempData["TmpData"]
  19. <br />
  20.  
  21. @Html.ActionLink("連結到Page2","Page2","Home")
  22.  
  23. </div>
  24. </body>
  25. </html>
  26.  
Page2.cshtml

  1.  
  2. @{
  3. Layout = null;
  4. }
  5.  
  6. <!DOCTYPE html>
  7.  
  8. <html>
  9. <head>
  10. <meta name="viewport" content="width=device-width" />
  11. <title>Page2</title>
  12. </head>
  13. <body>
  14. <div>
  15. <h1>Page2</h1>
  16. Now Time:@TempData["datetime"]
  17. <br />
  18. TmpData:@TempData["TmpData"]
  19. <br />
  20.  
  21. @Html.ActionLink("連結到Page3", "Page3", "Home")
  22. </div>
  23. </body>
  24. </html>
  25.  
Page3.cshtml

  1.  
  2. @{
  3. Layout = null;
  4. }
  5.  
  6. <!DOCTYPE html>
  7.  
  8. <html>
  9. <head>
  10. <meta name="viewport" content="width=device-width" />
  11. <title>Page3</title>
  12. </head>
  13. <body>
  14. <div>
  15. <h1>Page3</h1>
  16. Now Time:@TempData["datetime"]
  17. <br />
  18. TmpData:@TempData["TmpData"]
  19. </div>
  20. </body>
  21. </html>
  22.  

HomeController.cs

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Data;
  4. using System.Linq;
  5. using System.Web;
  6. using System.Web.Mvc;
  7.  
  8. namespace MyEmptyMVC1.Controllers
  9. {
  10. public class HomeController : Controller
  11. {
  12. // GET: Home
  13. public ActionResult Index()
  14. {
  15. #region 用ViewData來Pass值
  16. ViewData["DatetimeNow"] = DateTime.Now;
  17. ViewData["Address"] = "臺北市信義區市府路1號";
  18. ViewData["Years"] = 28;
  19. ViewData["Percent"] = 0.85;
  20.  
  21. ViewData["UnitPrice"] = 80;
  22. ViewData["CountOfOneWeek"] = 5;
  23.  
  24. List<string> lsFruit = new List<string>();
  25. lsFruit.Add("Orange");
  26. lsFruit.Add("Banana");
  27. lsFruit.Add("Peach");
  28.  
  29. ViewData["FruitList"] = lsFruit;
  30.  
  31. DataTable dt = new DataTable();
  32. dt.Columns.Add("Name");
  33. dt.Columns.Add("Title");
  34. dt.Columns.Add("Years");
  35.  
  36. DataRow row1 = dt.NewRow();
  37. row1["Name"] = "Amy";
  38. row1["Title"] = "會計";
  39. row1["Years"] = 5;
  40. dt.Rows.Add(row1);
  41. DataRow row2 = dt.NewRow();
  42. row2["Name"] = "Jack";
  43. row2["Title"] = "工程師";
  44. row2["Years"] = 8;
  45. dt.Rows.Add(row2);
  46. ViewData["EmployeeInfo"] = dt;
  47. #endregion
  48.  
  49. #region 用ViewBag來Pass值
  50. ViewBag.NowDate = DateTime.Now.Date;
  51. ViewBag.address = "台北市萬華";
  52. ViewBag.Num = 7;
  53. ViewBag.PI = 3.1415;
  54.  
  55. List<string> lsWeek = new List<string>();
  56. lsWeek.Add("Monday");
  57. lsWeek.Add("Tuesday");
  58. lsWeek.Add("Wednesday");
  59. lsWeek.Add("Thursday");
  60. lsWeek.Add("Friday");
  61. lsWeek.Add("Saturday");
  62. lsWeek.Add("Sunday");
  63. ViewBag.WeekDay = lsWeek;
  64.  
  65. DataTable dtScore = new DataTable();
  66. dtScore.Columns.Add("Name");
  67. dtScore.Columns.Add("Grade");
  68. dtScore.Columns.Add("Score");
  69.  
  70. DataRow dr1 = dtScore.NewRow();
  71. dr1["Name"] = "Tom";
  72. dr1["Grade"] = "一年級";
  73. dr1["Score"] = 82;
  74. dtScore.Rows.Add(dr1);
  75.  
  76. DataRow dr2 = dtScore.NewRow();
  77. dr2["Name"] = "Jason";
  78. dr2["Grade"] = "一年級";
  79. dr2["Score"] = 89;
  80. dtScore.Rows.Add(dr2);
  81.  
  82. DataRow dr3 = dtScore.NewRow();
  83. dr3["Name"] = "Mike";
  84. dr3["Grade"] = "二年級";
  85. dr3["Score"] = 93;
  86. dtScore.Rows.Add(dr3);
  87.  
  88. DataRow dr4 = dtScore.NewRow();
  89. dr4["Name"] = "Jason";
  90. dr4["Grade"] = "二年級";
  91. dr4["Score"] = 98;
  92. dtScore.Rows.Add(dr4);
  93.  
  94.  
  95.  
  96. ViewBag.ScoreTable = dtScore;
  97.  
  98.  
  99. #endregion
  100.  
  101.  
  102. return View();
  103. }
  104.  
  105.  
  106. public ActionResult Page1()
  107. {
  108. TempData["datetime"] = DateTime.Now;
  109. TempData["TmpData"] = "Tmp Data A";
  110. TempData.Keep("datetime");//將字典中指定的索引鍵標記為保留。
  111. //TempData.Keep();//將字典中的所有索引鍵都標記為保留。
  112. return View();
  113. }
  114.  
  115. public ActionResult Page2()
  116. {
  117. return View();
  118. }
  119.  
  120. public ActionResult Page3()
  121. {
  122. return View();
  123. }
  124. }
  125. }

我們可以拿一個資料做TempData Keep的測試
會觀察到Now Time的值在導向到Page2後仍存在
Page1 -> Page2 -> Page3的導向過程
但在從Page2導向到Page3就消失了
Page1 -> Page2 -> Page3的導向過程

原因就在於
在被View讀取後,Keep只會被保留一次,然後就刪除了。

TempData.Peek使用方式

Peek() method returns an object that contains the element that is associated with the specified key, without marking the key for deletion

主要功能是用不標註狀態要刪除的方式取值

這裡改用Peek來測試效果

Page1.cshtml

  1. @{
  2. Layout = null;
  3. }
  4.  
  5. <!DOCTYPE html>
  6.  
  7. <html>
  8. <head>
  9. <meta name="viewport" content="width=device-width" />
  10. <title>Page1</title>
  11. </head>
  12. <body>
  13. <div>
  14. <h1>Page1</h1>
  15. Now Time:@TempData.Peek("datetime").ToString()
  16. <br />
  17. TmpData:@TempData["TmpData"]
  18. <br />
  19.  
  20. @Html.ActionLink("連結到Page2","Page2","Home")
  21.  
  22. </div>
  23. </body>
  24. </html>
  25.  
Page2.cshtml

  1.  
  2. @{
  3. Layout = null;
  4. }
  5.  
  6. <!DOCTYPE html>
  7.  
  8. <html>
  9. <head>
  10. <meta name="viewport" content="width=device-width" />
  11. <title>Page2</title>
  12. </head>
  13. <body>
  14. <div>
  15. <h1>Page2</h1>
  16. Now Time:@TempData.Peek("datetime").ToString()
  17. <br />
  18. TmpData:@TempData["TmpData"]
  19. <br />
  20.  
  21. @Html.ActionLink("連結到Page3", "Page3", "Home")
  22. </div>
  23. </body>
  24. </html>
  25.  

Page3.cshtml

  1.  
  2. @{
  3. Layout = null;
  4. }
  5.  
  6. <!DOCTYPE html>
  7.  
  8. <html>
  9. <head>
  10. <meta name="viewport" content="width=device-width" />
  11. <title>Page3</title>
  12. </head>
  13. <body>
  14. <div>
  15. <h1>Page3</h1>
  16. Now Time:@TempData.Peek("datetime").ToString()
  17. <br />
  18. TmpData:@TempData["TmpData"]
  19. </div>
  20. </body>
  21. </html>
  22.  

HomeController.cs

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Data;
  4. using System.Linq;
  5. using System.Web;
  6. using System.Web.Mvc;
  7.  
  8. namespace MyEmptyMVC1.Controllers
  9. {
  10. public class HomeController : Controller
  11. {
  12. // GET: Home
  13. public ActionResult Index()
  14. {
  15. #region 用ViewData來Pass值
  16. ViewData["DatetimeNow"] = DateTime.Now;
  17. ViewData["Address"] = "臺北市信義區市府路1號";
  18. ViewData["Years"] = 28;
  19. ViewData["Percent"] = 0.85;
  20.  
  21. ViewData["UnitPrice"] = 80;
  22. ViewData["CountOfOneWeek"] = 5;
  23.  
  24. List<string> lsFruit = new List<string>();
  25. lsFruit.Add("Orange");
  26. lsFruit.Add("Banana");
  27. lsFruit.Add("Peach");
  28.  
  29. ViewData["FruitList"] = lsFruit;
  30.  
  31. DataTable dt = new DataTable();
  32. dt.Columns.Add("Name");
  33. dt.Columns.Add("Title");
  34. dt.Columns.Add("Years");
  35.  
  36. DataRow row1 = dt.NewRow();
  37. row1["Name"] = "Amy";
  38. row1["Title"] = "會計";
  39. row1["Years"] = 5;
  40. dt.Rows.Add(row1);
  41. DataRow row2 = dt.NewRow();
  42. row2["Name"] = "Jack";
  43. row2["Title"] = "工程師";
  44. row2["Years"] = 8;
  45. dt.Rows.Add(row2);
  46. ViewData["EmployeeInfo"] = dt;
  47. #endregion
  48.  
  49. #region 用ViewBag來Pass值
  50. ViewBag.NowDate = DateTime.Now.Date;
  51. ViewBag.address = "台北市萬華";
  52. ViewBag.Num = 7;
  53. ViewBag.PI = 3.1415;
  54.  
  55. List<string> lsWeek = new List<string>();
  56. lsWeek.Add("Monday");
  57. lsWeek.Add("Tuesday");
  58. lsWeek.Add("Wednesday");
  59. lsWeek.Add("Thursday");
  60. lsWeek.Add("Friday");
  61. lsWeek.Add("Saturday");
  62. lsWeek.Add("Sunday");
  63. ViewBag.WeekDay = lsWeek;
  64.  
  65. DataTable dtScore = new DataTable();
  66. dtScore.Columns.Add("Name");
  67. dtScore.Columns.Add("Grade");
  68. dtScore.Columns.Add("Score");
  69.  
  70. DataRow dr1 = dtScore.NewRow();
  71. dr1["Name"] = "Tom";
  72. dr1["Grade"] = "一年級";
  73. dr1["Score"] = 82;
  74. dtScore.Rows.Add(dr1);
  75.  
  76. DataRow dr2 = dtScore.NewRow();
  77. dr2["Name"] = "Jason";
  78. dr2["Grade"] = "一年級";
  79. dr2["Score"] = 89;
  80. dtScore.Rows.Add(dr2);
  81.  
  82. DataRow dr3 = dtScore.NewRow();
  83. dr3["Name"] = "Mike";
  84. dr3["Grade"] = "二年級";
  85. dr3["Score"] = 93;
  86. dtScore.Rows.Add(dr3);
  87.  
  88. DataRow dr4 = dtScore.NewRow();
  89. dr4["Name"] = "Jason";
  90. dr4["Grade"] = "二年級";
  91. dr4["Score"] = 98;
  92. dtScore.Rows.Add(dr4);
  93.  
  94.  
  95.  
  96. ViewBag.ScoreTable = dtScore;
  97.  
  98.  
  99. #endregion
  100.  
  101.  
  102. return View();
  103. }
  104.  
  105.  
  106. public ActionResult Page1()
  107. {
  108. TempData["datetime"] = DateTime.Now;
  109. TempData["TmpData"] = "Tmp Data A";
  110.  
  111. //TempData.Keep("datetime");//將字典中指定的索引鍵標記為保留。
  112. //TempData.Keep();//將字典中的所有索引鍵都標記為保留。
  113. return View();
  114. }
  115.  
  116. public ActionResult Page2()
  117. {
  118. return View();
  119. }
  120.  
  121. public ActionResult Page3()
  122. {
  123. return View();
  124. }
  125. }
  126. }

就可以持續保留





上述這幾項都是適用在資料傳輸量不會太多的情況
若要傳輸較大量資料建議用ViewModel

參考此篇的建議





Ref:

How to Persist Data with TempData using Peek and Keep in MVC

MVC: WHEN TO USE KEEP() VS PEEK() WITH TEMPDATA IN ASP.NET MVC

MVC TempData – Peek vs Keep

Difference between TempData keep() And Peek() in Asp.Net MVC


ASP.NET MVC ViewData 與 TempData 的差別

Tempdata keep与peek

[創意料理] 再深入一點點對 ViewBag、ViewData、Model 的了解

[ASP.NET MVC] ASP.NET MVC 傳遞資料容器(一) - ViewData vs ViewBag


[探索 10 分鐘] 寫點有關 ASP.NET MVC ViewModel, ViewData, ViewBag, TempData 的代碼

asp.net mvc. Passing a list via viewData

What is the right time for ViewData, ViewBag, Session, TempData

When to use ViewBag, ViewData, or TempData in ASP.NET MVC 3 applications
Difference Between ViewData, ViewBag, TemData and Session in MVC

MVC传值方式及优缺点

TempData 生命週期

認識Controller - 傳資料給View

ASP.NET MVC中controller和view相互傳值的方式


從零開始的MVC開發-Controller對View的喊話



留言

這個網誌中的熱門文章

經得起原始碼資安弱點掃描的程式設計習慣培養(五)_Missing HSTS Header

經得起原始碼資安弱點掃描的程式設計習慣培養(三)_7.Cross Site Scripting(XSS)_Stored XSS_Reflected XSS All Clients

(2021年度)駕訓學科筆試準備題庫歸納分析_法規是非題