ASP.NET MVC 中 TempData、ViewData、ViewBag 三大資料傳遞機制完整比較
ASP.NET MVC 控制器向視圖傳遞資料有三種主要機制:ViewData、ViewBag、TempData。它們生命週期、型別安全性、適用場景各異,正確選擇至關重要。
核心差異速查表
| 特性 | ViewData | ViewBag | TempData |
| 型別 | ViewDataDictionary (字典) | 動態物件 (DynamicObject) | TempDataDictionary (字典) |
| 語法 | ViewData["key"] = val | ViewBag.Key = val | TempData["key"] = val |
| 型別安全 | 無 (需轉型) | 無 (動態解析) | 無 (需轉型) |
| 生命週期 | 當前請求 (Controller → View) | 當前請求 (Controller → View) | 當前請求 + 下一個請求 (重導向場景) |
| 儲存機制 | Session (預設) | Session (預設) | Session (預設) |
| 自動清除 | 視圖渲染後 | 視圖渲染後 | 讀取後 (或 Keep() 保留) |
| IntelliSense | 無 | 有 (動態屬性) | 無 |
ViewData:字典基礎機制
// Controller
public ActionResult Index() {
ViewData["Message"] = "Hello World!";
ViewData["UserCount"] = 42;
return View();
}
// View (Razor)
<h1>@ViewData["Message"]</h1>
<p>用戶數: @ViewData["UserCount"]</p>
- 本質是
Dictionary<string, object>,需字串鍵值存取。
- 視圖中取值需轉型:
(int)ViewData["UserCount"]。
- 鍵名拼寫錯誤執行時才發現,無編譯期檢查。
ViewBag:動態包裝器 (C# 4.0+)
// Controller
public ActionResult Index() {
ViewBag.Message = "Hello World!";
ViewBag.UserCount = 42;
ViewBag.User = new { Name = "Tom", Role = "Admin" }; // 匿名型別
return View();
}
// View
<h1>@ViewBag.Message</h1>
<p>@ViewBag.User.Name</p>
- 內部封裝
ViewData,透過 DynamicObject 提供屬性語法。
- 語法更簡潔,支援巢狀動態屬性。
- 同樣無編譯期型別檢查,拼寫錯誤執行時拋出
RuntimeBinderException。
TempData:跨請求資料傳遞 (PRG 模式核心)
// Controller - 動作 A (POST 處理)
[HttpPost]
public ActionResult Create(FormModel model) {
if (ModelState.IsValid) {
_service.Save(model);
TempData["SuccessMessage"] = "資料已儲存!"; // 存入 TempData
return RedirectToAction("Index"); // PRG: 重導向至 Index
}
return View(model);
}
// Controller - 動作 B (GET 顯示)
public ActionResult Index() {
// TempData 自動保留到此請求,讀取後標記刪除
ViewBag.Message = TempData["SuccessMessage"]; // 取出傳給 ViewBag
return View();
}
// View (Index)
@if (ViewBag.Message != null) {
<div class="alert alert-success">@ViewBag.Message</div>
}
- 專為 Post-Redirect-Get (PRG) 模式設計:POST 動作存資料 → 重導向 → GET 動作取資料顯示。
- 預設讀取即刪除:
TempData["key"] 存取後標記移除,下一請求不可用。
TempData.Keep("key") 或 TempData.Keep() 保留到再下一請求。
TempData.Peek("key") 僅讀取不標記刪除。
實戰選擇指南
| 場景 | 推薦機制 | 理由 |
| Controller → View 一般資料 | ViewModel (強型別) | 編譯期檢查、IntelliSense、重構安全、關注點分離 |
| 少量臨時資料、快速原型 | ViewBag | 語法簡潔、動態彈性 |
| 需轉型、字典語意明確 | ViewData | 明確字串鍵、相容舊代碼 |
| 重導向後顯示成功/錯誤訊息 | TempData | 跨請求生命週期、自動清除符合 PRG |
| 多步驟精靈、跨多請求暫存 | TempData + Keep() | 手動控制保留輪數 |
最佳實務:強型別 ViewModel 為主
// ViewModel
public class ProductViewModel {
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public string SuccessMessage { get; set; } // 包含 TempData 內容
}
// Controller
public ActionResult Index() {
var vm = new ProductViewModel {
SuccessMessage = TempData["SuccessMessage"]?.ToString()
};
return View(vm);
}
// View (@model ProductViewModel)
@if (!string.IsNullOrEmpty(Model.SuccessMessage)) {
<div class="alert-success">@Model.SuccessMessage</div>
}
- ViewModel 模式 解決所有三者的型別不安全、重構脆弱、測試困難問題。
TempData 僅用於跨請求傳遞原始資料,控制器讀取後立即映射到 ViewModel。
- 視圖完全強型別,享受完整工具支援。
Session 儲存提供者影響
- 預設使用
InProc Session,單機部署正常。
- Web Farm/雲端部署需切換
StateServer、SQLServer、Redis (ASP.NET Core IDistributedCache),確保 TempData/ViewData 跨實例共享。
- 無 Session 情境 (Web API、SignalR) 不應依賴此三者。
總結
- ViewData/ViewBag:單一請求 Controller→View,語法偏好不同,均不建議大量使用。
- TempData:PRG 模式專用,跨重導向請求傳遞暫時資料。
- 黃金法則:強型別 ViewModel 為主,三者僅作為輔助/遷移過渡方案。