这三个对象均可用作视图和控制器的属性。根据经验,您将使用ViewData,ViewBag和TempData对象来往于特定位置(例如,用于视图的控制器或视图之间的控制器)来回传输少量数据。ViewData和ViewBag对象在以下情况下均能正常工作:
- 将查找数据的下拉列表合并到实体中
- 像购物车这样的组件
- 像用户个人资料小部件一样的小部件
- 少量汇总数据
尽管TempData对象在一种基本情况下运行良好:
- 在当前和下一个HTTP请求之间传递数据
如果需要处理大量数据,报告数据,创建仪表板或处理多个不同的数据源,则可以使用功能更强大的ViewModel对象。请参阅我在ViewModels上的详细博客文章,以获取有关使用ViewModels的更多详细信息。
ViewData和ViewBag对象
- ViewData
- ViewData是您将数据放入其中的字典对象,然后该对象可用于视图。ViewData是ViewDataDictionary类的派生类,因此您可以通过熟悉的“键/值”语法进行访问。
- ViewBag
- ViewBag对象是ViewData对象的包装,它允许您为ViewBag创建动态属性。
ViewData和ViewBag对象都非常适合在控制器和视图之间访问额外的数据(即,在数据模型外部)。由于视图已经期望将特定的对象作为其模型,因此对额外数据的这种类型的数据访问,MVC将其实现为视图和控制器的属性,从而简化了对这些对象的使用和访问。
下面的代码示例概述了ViewBag,ViewData和TempData对象的语法和用法,该示例填充了在面包店的主页中视图呈现的特色产品对象:
public ActionResult Index() { var featuredProduct = new Product { Name = "Special Cupcake Assortment!", Description = "Delectable vanilla and chocolate cupcakes", CreationDate = DateTime.Today, ExpirationDate = DateTime.Today.AddDays(7), ImageName = "cupcakes.jpg", Price = 5.99M, QtyOnHand = 12 }; ViewData["FeaturedProduct"] = featuredProduct; ViewBag.Product = featuredProduct; TempData["FeaturedProduct"] = featuredProduct; return View(); } }
Index.cshtml视图通过使用与控制器中相同的语法访问代码来呈现Product对象。请注意,您必须强制转换ViewData和TempData对象,而不是ViewBag。
@using FourthCoffee.Models; @{ ViewBag.Title = "Home Page"; var viewDataProduct = ViewData["FeaturedProduct"] as Product; var tempDataProduct = TempData["FeaturedProduct"] as Product; } <h2>Welcome to Fourth Coffee Bakery</h2> <div> <a href="/Products"> <img src=‘@Url.Content("\Content\Images\cake.jpg")‘ alt="Fourth Coffee Bakery"/> </a> <div> Today‘s Featured Product is! <br /> <h 4>@ViewBag.FeaturedProduct.Name</h4> <h3>@viewDataProduct.Name</h3> <h2>@tempDataProduct.Name</h2> </div> @Html.ActionLink("Test Tempdata","Featured") </div>
ViewBag对象使您可以向其添加动态属性,这使其成为非常通用的工具。
尽管在渲染此视图时所有三个都显示了某些内容,但是以这种方式使用TempData可能会很麻烦,这就是为什么……
临时数据
TempData是一个非常短暂的实例,您只应在当前请求和后续请求中使用它!由于TempData以这种方式工作,因此您需要确定下一个请求将是什么,并且只有重定向到另一个视图时,您才能保证这一点。因此,唯一可以可靠使用TempData的方案是在重定向时。这是因为重定向会终止当前请求(并发送HTTP状态代码302 Object Moved)到客户端),然后在服务器上创建一个新请求以提供重定向视图。回顾先前的HomeController代码示例,这意味着TempData对象产生的结果可能与预期的不同,因为无法保证下一个请求的起源。例如,下一个请求可以源自完全不同的计算机和浏览器实例。
如下所述,使用TempData的语法与ViewData相同。
// TempData sample public ActionResult Featured() { var featuredProduct = new Product { Name = "Assorted Cupcakes", Description = "Delectable vanilla and chocolate cupcakes", CreationDate = DateTime.Today, ExpirationDate = DateTime.Today.AddDays(7), ImageName = "cupcakes.jpg", Price = 5.99M, QtyOnHand = 12 }; ViewData["FeaturedProduct"] = featuredProduct; ViewBag.Product = featuredProduct; TempData["FeaturedProduct"] = featuredProduct; //After the redirect, the ViewBag & ViewData objects are no longer available //Only TempData survives a redirect return new RedirectResult(@"~Featured"); }
但是,一旦控制器重定向,ViewBag和ViewData将包含空值。如果您在重定向后使用调试工具检查TempData对象,则会看到该对象已完全填充有特色产品。这是因为重定向是仅后续请求,因此只有它可以访问TempData对象,而不必担心。
@using FourthCoffee.Models; @model FourthCoffee.Models.Product @{ ViewBag.Title = "Details"; var featuredProduct = TempData["FeaturedProduct"] as Product; }
常规Session对象是TempData对象的后备存储,并且与常规会话相比,它的销毁速度更快,即在后续请求之后立即销毁。由于其生存期短,因此非常适合将错误消息传递到错误页面。
格雷格(Greg shackles)的博客文章非常全面,涵盖了您需要了解的有关TempData的所有内容。
既然您已经了解了如何以及何时使用ViewData,ViewBag和TempData对象,那么您可能想知道在使用更大的数据集或更复杂的场景时该怎么做。幸运的是,MVC可以处理这些通常需要的方案。
在ViewBag之外思考
您的需求可能需要您代表以下类型的数据,这些类型在使用ViewBag,ViewData或TempData对象时不太适合。MVC 3框架包含ViewModel对象,以供您在需要更多ViewData时使用。非常适合ViewModels的数据类型如下:
- 主从数据
- 更大的数据集
- 复杂的关系数据
- 报告和汇总数据
- 仪表板
- 来自不同来源的数据
在应用程序开发过程中,您可能会遇到这些或类似情况。
摘要
ViewData和ViewBag对象使您可以访问模型中附带的那些额外数据,但是对于更复杂的数据,您可以上移至ViewModel。另一方面,TempData专门用于处理HTTP重定向上的数据,因此请记住在使用TempData时要谨慎。