知识大全 浅谈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设计模式的实现 以下文字资料是由(全榜网网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.netMVC中Ajax的使用 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! MVC抛弃了
在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.NETMVC框架中的URL路径选择场景 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! A
Asp.netMVC中页面标题的新解决方法 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 在MV
浅谈ASP.NET中render方法 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! &n