知识大全 浅谈ASP.NET MVC中TempData的实现机制

Posted

篇首语:对我来说,不学习,毋宁死。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 浅谈ASP.NET MVC中TempData的实现机制相关的知识,希望对你有一定的参考价值。

浅谈ASP.NET MVC中TempData的实现机制  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  本篇主要讨论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

cha138/Article/program/net/201311/13479

相关参考

知识大全 浅谈ASP.NET开发下的MVC设计模式的实现

浅谈ASP.NET开发下的MVC设计模式的实现  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!&nb

知识大全 浅谈ASP.NET MVC中的FluentHtml与连续接口

浅谈ASP.NETMVC中的FluentHtml与连续接口  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一

知识大全 浅谈基于URL的权限控制ASP.NET MVC中的实现

浅谈基于URL的权限控制ASP.NETMVC中的实现  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

知识大全 Asp.net MVC 中Ajax的使用

Asp.netMVC中Ajax的使用  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  MVC抛弃了

知识大全 在Asp.net MVC中使用Repeater

在Asp.netMVC中使用Repeater  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  Re

知识大全 asp.net中mvc使用ajax提交参数的匹配问题解决探讨

本文为大家介绍下使用javaScript解决aspnet中mvc使用ajax提交参数的匹配问题遇到类似情况的朋友可以参考下希望对大家有所帮助 想到在aspnet的mvc中如果使用ajax向服

知识大全 Asp.net Mvc Pv4中使用AjaxHelper

Asp.netMvcPv4中使用AjaxHelper  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

知识大全 ASP.NET MVC框架中的URL路径选择场景

ASP.NETMVC框架中的URL路径选择场景  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  A

知识大全 Asp.net MVC中页面标题的新解决方法

Asp.netMVC中页面标题的新解决方法  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  在MV

知识大全 浅谈ASP.NET中render方法

浅谈ASP.NET中render方法  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! &n