ASP.NET MVC TempData使用心得)

來源:互聯網
上載者:User

原文地址: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消失的

Note:

ViewData的存留期測試

HomeController.cs 片段public ActionResult Index(){    this.ViewData["Data"] = "Index";    return View();}public ActionResult List(){    //什麼Data都沒有輸出    return View();}
Index.aspx 片段<div>    Partial:    <%        //ViewData是使用Index,不會執行List的Action        Html.RenderPartial("List");    %>        </div><div>    Action:    <%        //ViewData是使用List,會執行List的Action        Html.RenderAction("List");    %></div>List.ascx 片段<%:this.ViewData["Data"] %>

 

結果

 

執行Partial或RanderPartial是在同一個Action中直接呼叫View,共用同一個ViewData。

執行Action或RanderAction會呼叫另一個Action,那一個Action再呼叫View,使用不用的ViewData。

如果要在不同的Action中傳遞資料,要使用TempData。

 錯誤重現

下列這段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的Keyspublic 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);}

Note:

我曾經想過寫一個Provider,資料是存放在HttpContext.Items,因為我習慣Temp的資料,在一個Request結束後就消失,不過專案成員們都覺得太多此一舉了,而作罷。

//自訂的TempDataProvider,沒辦法用設定改變(至少我沒找到),只能用繼承來覆寫CreateTempDataProvider作到統一使用public class MyControllerBase : Controller{    protected override ITempDataProvider CreateTempDataProvider()    {        return new HttpContextItemsTempDataProvider();    }}//使用public class HomeControllerBase : MyControllerBase{     }

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.