在mvc中Controller与View之间的传值与WebForm模式下页面之间的传值大同小异,都有Form表单,URL以及AJAX发送异步请求的传参方式,那么我们在这一篇文章中,我们主要讲解MVC中区别于WebForm的一些传值方法。
首先我们看看mvc中以ViewData方式来进行Controller于View之间的传值。二话不说,我们直接来个Demo看看效果:我们自定义一个TestViewData控制器,该控制器里面的方法如下:
public class TestViewDataController : Controller { public ActionResult Index() { ViewData["TestDropDownList"] = new[] { new SelectListItem{Value="0",Text="懒洋洋"}, new SelectListItem{Value="1",Text="薛小雨"}, new SelectListItem{Value="2",Text="彭县林"}, new SelectListItem{Value="3",Text="咸鱼"} }; return View(); } } |
创建一个Index视图,该视图定义如下:
@{ Layout = null; } <!DOCTYPE html> <html> <head> <title>Index</title> </head> <body> <div> @Html.DropDownList("TestDropDownList",ViewData["TestDropDownList"] as IEnumerable<SelectListItem>) </div> </body> </html> |
运行效果如下:
(PS:在IE10中下拉框的效果),这应该是这个最简单的一种传值方式了,但是由于ViewData传值采用的方式有点类似于“弱类型”,key是sting类型,在编译时无法检查到错误,因为微软官方也建议我们少用ViewData来进行传值。我们来看看微软给ViewData的官方定义:
public ViewDataDictionary ViewData { |
ViewData和包括后面我们要讲的ViewBag都是作为ControllerBase类的一个属性,ViewData属性返回的是一个ViewDataDictionary集合,该集合和普通的键值对“Key/Value”没有什么区别。ViewBag属性的定义如下:
public dynamic ViewBag { get { if (_dynamicViewDataDictionary == null) { _dynamicViewDataDictionary = new DynamicViewDataDictionary(() => ViewData); } return _dynamicViewDataDictionary; } } |
在ViewBag中我们可以发现ViewBag其实就是对ViewData的包装,它允许你为ViewBag动态的创建属性。
接着我们来看看TempData的用法,用TempData在Contoller与View之间传值有点特殊,当然如果是在同一次请求的生命周期里面,TempData与ViewData,ViewBag没有多大区别。但是ViewData和ViewBag都是只能在当前的Controller里面有效,不能在跨Controller的View中传值数据。先来看看demo吧。我们在ViewData定义如下:
public class ViewDataController : Controller { public ActionResult Index() { ViewBag.sss = "这里是给TempData[testTemp]赋值的Controller"; return View(); } } |
这里注意我在ViewData对应的View里面的写法:
@{ Layout = null; } <!DOCTYPE html> <html> <head> <title>Index</title> </head> <body> <div> @ViewBag.sss <br /> </div> </body> </html> |
然后在ViewDataTest对应的View里面输出该内容:
@{ Layout = null; } <!DOCTYPE html> <html> <head> <title>Index</title> </head> <body> <div> 这里是ViewDataTest控制器对应的Index<br /> @TempData["testTemp"] </div> </body> </html> |
我们先访问ViewData里面的Index,在访问ViewDataTest里面的Index,注意这个顺序不能调换,否则在ViewDataTest中会无法获取到TempData["testTemp"] 的值,因为该值是在ViewData中index给的。运行效果如下:
紧接着访问ViewDataTest里面的Index方法:
我们可以看到实现了跨Controller的效果,但是,别开心,当我们再次请求ViewDataTest里面的Index方法的方法,你会发现:
怎么回事,只是对第一次访问有效果?
我们再来看看另外一组demo,我们在ViewData对应的Index中加入这么一句代码:@TempData["testTemp"]
@{ Layout = null; } <!DOCTYPE html> <html> <head> <title>Index</title> </head> <body> <div> @ViewBag.sss <br /> <br /> </div> </body> </html> |
ViewDataTest对应的Index不做任何改变,然后按刚才的步骤运行:效果如下:
这里是ViewData对应的Index,下图是ViewDataTest对应的Index,当我们访问ViewDataTest里面的Index的时候,并没有显示在ViewData里面过来TempData["testTemp"]的值,因为该值已经在ViewData中显示过一次的缘故吗?
根据以上的测试我们可以知道,TempData支持跨Controller的View中传值,但是仅仅能在一次请求周期之内并且只能在当前或者随后的请求中才会有效。正是TempData的特殊的用法,因此我们如果要用TempData进行传值的话,我么必须得知道下一个请求的事项,且必须确保你会唯一一次重定向到你要处理的View。因此如上所说或许也只有当我们要用到重定向的时候才会考虑用TempData来传值,因为重定向操作会阻止当前的请求同时发送HTTP状态码302到客户端,重新发送一个新的请求到服务器从而渲染另外一个重定向后的View。
当然以上几种Controller与View之间的传值都有一个局限性:适合传输小数据量。对于传输大数据的话,mvc中推荐使用的是ViewModel强类型的方式,ViewModel的传值方式适合以下情况(来源:http://rachelappel.com/when-to-use-viewbag-viewdata-or-tempdata-in-asp.net-mvc-3-applications):
|
对于ViewModel的传值,这里就不写Demo详解了。