當前位置:編程學習大全網 - 源碼下載 - 淺談ASP.NET MVC中TempData的實現機制

淺談ASP.NET MVC中TempData的實現機制

 本篇主要討論ASP NET MVC中TempData是如何實現的 通過研讀MVC的源代碼妳將清楚的了解MVC是如何實現TempData功能的

 TempData特性

 TempDataDictionary與ITempDataProvider

 TempDataDictionary的設計

 SessionStateTempDataProvider與ITempDataProvider

 TempData特性Top

 TempData的特性就是可以在兩個Action之間傳遞數據 它會保存壹份數據到下壹個Action 並隨著再下壹個Action的到來而失效 所以它被用在兩個Action之間來保存數據 比如 這樣壹個場景 妳的壹個Action接受壹些post的數據 然後交給另壹個Action來處理 並顯示到頁面 這時就可以使用TempData來傳遞這份數據

 那到底TempData是怎樣完成這個功能的呢?下面我們從MVC的源代碼入手來解析TempData的機制

 TempDataDictionary與ITempDataProviderTop

 首先來看看ITempDataProvider接口 從字面意思上看我們先把它翻譯為 暫時數據的提供者所遵從的規則 它約定了兩個方法

 public interface ITempDataProvider

 {

 IDictionary LoadTempData(ControllerContext controllerContext);

 void SaveTempData(ControllerContext controllerContext IDictionary values);

 }

 這兩個方法是LoadTempData和SaveTempData 我們猜想這兩個方法是用來取得TempData容器和保存TempData數據的 因為LoadTempData返回壹個IDictionary類型 而SaveTempData沒有返回類型 而參數ControllerContext就是針對不同的用戶上下文來設計的 標明是對那壹個上下文的TempData進行操作 的確是這樣的 後面會驗證我們的猜想

 再來看看TempDataDictionary 我們對這個類的第壹印象在哪裏呢?是在ControllerBase類中的TempData屬性 在普通的Controller中我們打上tempdata vs幫助我們完成的那個屬性其實就是ControllerBase類中的TempData 因此我們明白了 不管是在controller中 還是在view中 所有對TempData的操作都是對TempDataDictionary類型的操作 那ITempDataProvider有是怎麽與TempDataDictionary聯系的呢?看壹下TempDataDictionary的設計便壹目了然

 TempDataDictionary的設計Top

 public class TempDataDictionary : IDictionary<string object> ISerializable

 這是TempDataDictionary的簽名 我們看到它繼承了壹個IDictionary<string object>的字典類型和壹個ISerializable的接口 因此我們知道它是可以被序列化和反序列化的 該類有壹個常字符串類型的字段和壹個Dictionary<string object>類型的字段

 internal const string _tempDataSerializationKey = __tempData ;? internal Dictionary<string object> _data;

 在它帶參的構造函數中發現了對_tempDataSerializationKey的使用

 protected TempDataDictionary(SerializationInfo info StreamingContext context)

 {

 _initialKeys = new HashSet<string>(StringComparer OrdinalIgnoreCase);

 _modifiedKeys = new HashSet<string>(StringComparer OrdinalIgnoreCase);

 _data = info GetValue(_tempDataSerializationKey typeof(Dictionary<string object>))

 as Dictionary<string object>;

 }

 我們可以看到這是用來從壹個流中 反序列化得到壹個Dictionary類型的過程

 另壹點 在controller中 我們可以這樣使用TempData的

 TempData[ msg ] = new Object();? Object obj = TempData[ msg ] as object; 在了解它的索引器之前我們先看看它的幾個字段和方法 TempDataDictionary類重要的字段有三個

 internal Dictionary<string object> _data;? private HashSet<string> _initialKeys;? private HashSet<string> _modifiedKeys; _data用來存放真正的數據 _initialKeys用來存放原先數據的key _modifiedKeys用來存放修改過或新添加的數據key 為什麽要這樣呢?回想壹下TempData的特性 TempData只存放壹次數據 到第三個Action時 第壹個Action存放的數據就失效了 所以 _initialKeys被設計來存放那些數據是原來的 _modifiedKeys被設計來存放那些數據是修改過的或是新添加上的 這樣就區分了 舊 數據和 新 數據 那下壹步就是把 舊 的刪除 把 新 的記錄了

 我們再到索引器看看 因為我們對TempData的操作是從索引器開始的 下面是索引器的代碼

 public object this[string key]

 {

 get

 {

 object value;

 if (TryGetValue(key out value))

 {

 return value;

 }

 return null;

 }

 set {

 _data[key] = value;

 _modifiedKeys Add(key);

 }

 }

 當我們TempData[ msg ]=new Object();時不僅向_data中添加了數據 同時_modifiedKeys也保存了 新 數據的key 那什麽時候 新 數據被保存 舊 數據被刪除 真正的執行呢?這個過程是在Load和Save方法中發生的 下面看它們的具體實現

 public void Load(ControllerContext controllerContext ITempDataProvider tempDataProvider)

 {

 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);

 _modifiedKeys Clear();

 }

 public void Save(ControllerContext controllerContext ITempDataProvider tempDataProvider)

 {

 if (_modifiedKeys Count > )

 {

 // Apply change tracking

 foreach (string x in _initialKeys)

 {

 if (!_modifiedKeys Contains(x))

 {

 _data Remove(x);

 }

 }

 // Store the dictionary

 tempDataProvider SaveTempData(controllerContext _data);

 }

 }

 我們看到TempDataDictionary的Load方法首先是調用了ITempDataProvider的LoadTempData方法來獲取tempdata容器 然後讓_initialKeys等於_data Keys 相當於保存了 舊 數據的key 然後清空_modifiedKeys 相當於目前沒有 新 數據 而Save方法則是檢查_modifiedKeys Count是否大於 就相當於檢查是否有 新 數據 有則調用ITempDataProveder的SaveTempData方法保存掉 新 數據 這裏也驗證了我們先前的猜想是正確的

 說到這裏 我們似乎還沒有發現沒有壹個地方調用TempDataDictionary的Load和Save方法 也就是說 新 舊 數據壹直在都在_data中 似乎 舊 的數據沒有真正刪除 新 數據也壹直沒有壹個安定的家

 我們說對TempData中數據的 刷新 操作(刷新操作即把 舊 數據刪除 把 新 數據保存)應該發生在執行Action的時候 那在什麽地方我們執行了Action呢 是在IController的Execute方法中 IController<=ControllerBase<=Controller 順著這樣的繼承順序 我們找到Controller類的ExecuteCore方法 這裏是執行Action的地方 下面我們看看ExecuteCore方法的實現

 protected override void ExecuteCore()

 {

 TempData Load(ControllerContext TempDataProvider);

 try {

 string actionName = RouteData GetRequiredString( action );

 if (!ActionInvoker InvokeAction(ControllerContext actionName))

 {? HandleUnknownAction(actionName);

 }

 }

 finally

 {

 TempData Save(ControllerContext TempDataProvider);

 }

 }

 我們看到在這裏 Action執行之前TempData Load Action執行之後TempData Save 這就實現了TempData的 刷新 操作

 SessionStateTempDataProvider與ITempDataProviderTop

 到這裏 我們發現似乎還不知道到底數據是怎麽被保存的 我們只知道ITempDataProvider提供了壹個保存數據和獲取容器的這麽壹個約定 那麽具體的實現肯定是繼承了ITempDataProvider接口的類來做 SessionStateTempDataProvider就是這麽壹個類

 我們知道是在Controller類中的ExecuteCore方法中執行了 刷新 操作 我們還知道TempDataDictionary的Load和Save方法需要壹個ITempDataProvider的方法 那麽我們可以推斷肯定要去Controller類中尋找ITempDataProvider的實現 如我們所料

 public ITempDataProvider TempDataProvider {

 get {

 if (_tempDataProvider == null)

 {

 _tempDataProvider = new SessionStateTempDataProvider();

 }

 return _tempDataProvider;

 }

 set {

 _tempDataProvider = value;

 }

 }

 這裏使用了屬性註入 強硬的註入了壹個SessionStateTempDataProvider對象 那麽具體是怎樣實現存儲的就要去看壹下SessionStateTempDataProvider類了

 SessionStateTempDataProvider有壹個常字符串字段

 internal const string TempDataSessionStateKey = __ControllerTempData ; 下面是LoadTempData方法

 public virtual IDictionary LoadTempData(ControllerContext controllerContext)

 {

 HttpContextBase ;

 if ( == null)

 {

 throw new InvalidOperationException(

 MVCResources SessionStateTempDataProvider_SessionStateDisabled);

 }

 Dictionary<string object> tempDataDictionary = [TempDataSessionStateKey]? as Dictionary<string object>;

 if (tempDataDictionary != null)

 {

 // If we got it from Session remove it so that no other request gets it

 (TempDataSessionStateKey);

 return tempDataDictionary;

 }

 else

 {

 return new Dictionary<string object>(StringComparer OrdinalIgnoreCase);

 }

 }

 上面的代碼很簡單 原來它把Dictionary類型的數據存進了Session[ __ControllerTempData ]裏 讀的時候也只是簡單的類型轉換壹下就返回了

 下面是SaveTempData方法

 public virtual void SaveTempData(ControllerContext controllerContext IDictionary values)

 {

 HttpContextBase ;

 if ( == null)

 {

 throw new InvalidOperationException(

 MVCResources SessionStateTempDataProvider_SessionStateDisabled);

 }

 [TempDataSessionStateKey] = values;

 } SaveTempData方法也很簡單

 總結Top

lishixinzhi/Article/program/net/201311/13479

  • 上一篇:河南做小程序多少錢?有多貴嗎
  • 下一篇:夢源文件的分析
  • copyright 2024編程學習大全網