在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
原文地址:http://www.dotblogs.com.tw/wadehuang36/archive/2010/10/02/tempdata.aspx
在看TempData的說明時,有人說用一次就刪除,有人說一個Request就結束,在道聽途說下,有一次我的Code就出了Bug,一直死在TempData,最後看Source Code才發現,我對TempData的認知出了錯誤。
原理在ASP.NET MVC中資料傳遞主要有ViewData與TempData,ViewData主要是Controller傳遞Data給View,存留期只有一個Action,要跨Action要使用TempData,而TempData依TempDataProvider的不同,會有不同的存留期,預設的TempDataProvider是SessionStateTempDataProvider,你沒有看錯,預設是用Session來存放TempData,Session不是使用者存放資料,而且存留時間預設在20分鐘的嗎? 所以SessionStateTempDataProvider有做一些手段,Controller起來時,從Session載入TempData,然後刪除Session,所以在Action時是不會看到TempData的Session,在讀取TempData時,會記錄用了那些Key,在Controller結束時,會把沒有過的TempData在存回Session中,所以一直沒有讀取的TempData是會存在到Session消失的。
錯誤重現下列這段Code,猜猜有什麼Bug。 public ActionResult Index() { this.TempData["UseDefault"] = "true"; return View(); } public ActionResult List() { //在Index的View,會使用RanderAction呼叫List,但那一個區塊是會用Ajax重載 if (this.TempData.ContainsKey("UseDefault")) { //從Index的View,使用RanderAction呼叫,使用預設值 .......... } else { //從Ajax呼叫 ........... } return View(); }
答案是 呼叫this.TempData.ContainsKey("UseDefult")一直都是True,因為ContainsKey不是使用,所以TempData["UseDefult"]會一直保留在Session,直到Session消失前都是true,所以從Ajax呼叫一直都是使用預設值。
原始碼分析載入與儲存時機 System.Web.Mvc.Controller.cs 片段 protected override void ExecuteCore() { //載入TempData PossiblyLoadTempData(); try { //呼叫Action ........... } finally { //儲存TempData PossiblySaveTempData(); }
TempData的一些操作 System.Web.Mvc.TempDataDictionary.cs 片段 //_data 是放Keys + Values //_initialKeys 是放Keys,使用時移除Key //_retainedKeys 是放有呼叫,Keep的Keys public void Load(ControllerContext controllerContext, ITempDataProvider tempDataProvider) { //載入放在Provider的資料 IDictionary<string, object> providerDictionary = tempDataProvider.LoadTempData(controllerContext); _data = (providerDictionary != null) ? new Dictionary<string, object>(providerDictionary, StringComparer.OrdinalIgnoreCase) : new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase); _initialKeys = new HashSet<string>(_data.Keys, StringComparer.OrdinalIgnoreCase); _retainedKeys.Clear(); } public void Save(ControllerContext controllerContext, ITempDataProvider tempDataProvider) { //keysToKeep = _initialKeys + _retainedKeys string[] keysToKeep = _initialKeys.Union(_retainedKeys, StringComparer.OrdinalIgnoreCase).ToArray(); //keysToRemove = _data - keysToKeep string[] keysToRemove = _data.Keys.Except(keysToKeep, StringComparer.OrdinalIgnoreCase).ToArray(); //刪除使用過且不保留的Keys foreach (string key in keysToRemove) { _data.Remove(key); } //將沒有使用的TempData存起來 tempDataProvider.SaveTempData(controllerContext, _data); } public object this[string key] { get { object value; if (TryGetValue(key, out value)) { //讀取時刪除Key,在Save時用來比較 _initialKeys.Remove(key); return value; } return null; } set { _data[key] = value; _initialKeys.Add(key); } } public void Keep(string key) { //保留Key _retainedKeys.Add(key); }
|
请发表评论