ASP.NET MVC中的两个Action之间值的传递--TempData
一. ASP.NET MVC中的TempData
在ASP.NET MVC框架的ControllerBase中存在一个叫做TempData的Property,它的类型为TempDataDictionary,顾名思义是一个字典类。TempData在ASP.NET MVC中的作用是:可用于在Action执行过程之间传值。简单的说,你可以在执行某个Action的时候,将数据存放在TempData中,那么在下一次Action执行过程中可以使用TempData中的数据。
如:
1 public ActionResult Index() 2 { 3 this.TempData["MyNane"] = "XiaoMing"; 4 return View(); 5 } 6 public ActionResult Index2() 7 { 8 string MyName=this.TempData["MyNane"] as string; 9 return View(); 10 }
上面的代码中,Index()给TempData添加了一个键值对,假设我们先请求Index这个Action,接着请求Index2这个Action,那么在Index2中,我们便可以得到之前添加到TempData的键值对。有趣的是,这时如果再次请求Index2,那么从TempData中读到的MyName的值会是null。于是,我们需要了解TempData的生命周期。
二. TempData的生命周期
我们知道Http是无状态的,为什么TempData可以在两次请求之前传递数据呢?很明显,这个数据必定是已某种形式保存了。查看Controller类的源代码,很容易的找到了我们想要的东西:
1 protected override void ExecuteCore() 2 { 3 TempData.Load(ControllerContext, TempDataProvider); 4 try 5 { 6 string actionName = RouteData.GetRequiredString("action"); 7 if (!ActionInvoker.InvokeAction(ControllerContext, actionName)) 8 { 9 HandleUnknownAction(actionName); 10 } 11 } 12 catch (Exception) 13 { 14 15 TempData.Save(ControllerContext, TempDataProvider); 16 } 17 }
从上面的代码可以看出,每次在执行Action之前,都要调用一下TempData.Load()方法,执行完Action之后,再调用一下TempData.Save()方法。另外这里还有一个重要成员TempDataProvider。
阅读了相关源代码之后,真相大白了。
TempData.Load()
1 public void Load(ControllerContext controllerContext, ITempDataProvider tempDataProvider) 2 { 3 IDictionary<string, object> providerDictionary = tempDataProvider.LoadTempData(controllerContext); 4 _data = (providerDictionary != null) ? new Dictionary<string, object>(providerDictionary, StringComparer.OrdinalIgnoreCase) : 5 new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase); 6 _initialKeys = new HashSet<string>(_data.Keys); 7 __modifiedKeys.Clear(); 8 }
TempData.Save()
1 public void Save(ControllerContext controllerContext, ITempDataProvider tempDataProvider) 2 { 3 if (_modifiedKeys.Count > 0) 4 { 5 6 // Apply change tracking. 7 foreach (string x in _initialKeys) 8 { 9 if (!_modifiedKeys.Contains(x)) 10 { 11 _data.Remove(x); 12 } 13 } 14 15 // Store the dictionary 16 tempDataProvider.SaveTempData(controllerContext, _data); 17 _modifiedKeys.Clear(); 18 } 19 }
TempDataProvider用于暂存数据。在TempData.Load()方法中,TempDataProvider中保存的数据会被读到TempData中,供Action调用过程中使用。Action执行完后,TempData.Save()所作的事情则是,移除TempData中任何没有被更新的键值对,然后再将TempData中的数据保存,供下一次调用使用(注:也就是说,只有更新过的,以及新添加的键值对才能再下次request中继续使用)。为什么TempData中的数据需要迅速被清除呢?很简单,节约内存嘛。
三. ITempDataProvider
前面提到的TempDataProvider是Controller的一个Property,它的定义是这样的:
1 public ITempDataProvider TempDataProvider 2 { 3 get 4 { 5 if(_tempDataProvider==null){ 6 _tempDataProvider = new SessionStateTempDataProvider(); 7 } 8 return _tempDataProvider; 9 } 10 set 11 { 12 _tempDataProvider = value; 13 } 14 }
这里我们看到了一个默认实现的SessionStateTempDataProvider类。也就是说,默认情况下,ASP.NET MVC通过SessionStateTempDataProvider来保存TempData的数据。很明显,数据是存在Session中的,也就是说,如果你禁用SessionState,那么你的页面就报异常了。
ASP.NET MVC生来就是被设计为易扩展的,我们可以很容易通过实现自己的ITempDataProvider类来替换这个默认的SessionStateTempDataProvider。需要注意的是,TempDataProvider存放的数据必需具有用户独立性。
ITempDataProvider接口定义非常简单:
1 public interface ITempDataProvider 2 { 3 IDictionary<string, object> LoadTempData(ControllerContext controllerContext); 4 void SaveTempData(ControllerContext controllerContext, IDictionary<string, object> values); 5 }
在MvcFutures中,你也可以找到一个CookieTempDataProvider,提供了将TempData存储在Cookie中的实现。