33

我正在阅读一本关于 ASP.NET MVC 的书,我想知道下面的示例是如何工作的:

示例 #1

控制器

public class MyController : Controller
{
    public ActionResult Index()
    {
        ViewBag.MyProperty = 5;

        return View();
    }
}

看法

<h1>@ViewBag.MyProperty</h1>

现在我知道这ViewBag是一个动态对象,所以这就是设置属性的方式(尽管我对动态对象了解不多,从未使用过它们。)但是视图如何ViewBag从控制器获取特定实例,即使我们不直接传递任何东西?

我认为这ViewBag可能是一个public static对象,但是对它的任何更改都将是全局的,并且不会特定于视图实例。

您能否详细说明这在幕后是如何运作的?

示例 #2

控制器

public class MyController : Controller
{
    public ActionResult Index()
    {
        ViewBag.MyProperty = 5;

        return View();
    }

    public ActionResult Index2()
    {
        ViewBag.MyProperty = 6;

        return View();
    }
}

现在假设Index首先调用该方法,然后调用Index2. 最后, 的值ViewBag.MyProperty将最终为 6(来自 的值Index2)。我觉得这不是一件好事,但同时我觉得我在考虑桌面开发方面的问题。与 ASP.NET MVC 一起使用时可能无关紧要,因为 Web 是无状态的。是这样吗?

4

3 回答 3

28

ViewBag是 的一个属性ControllerBase,所有控制器都必须从该属性继承。它是一个dynamic对象,这就是为什么您可以向它添加新属性而不会出现编译时错误的原因。

它不是static,它是对象的成员。在请求的生命周期中,控制器实例被创建和释放,所以你不会有“并发”问题,比如覆盖值。

View及其变体)方法也不static是很好,这就是视图接收ViewBag值的方式:在呈现视图的过程中,控制器实例也有它的 ViewBag 实例。

于 2013-06-05T21:13:25.140 回答
11

如果您分析ControllerBase类,您会看到 ViewBag 属性是 ViewData 属性的“代理”,只是为了让您的源代码看起来更好。(我什至记得 Scott Hanselman 接受了 Phil Haack 的采访,Phil 介绍了 ViewBag 属性作为 ViewData 的快捷方式,并消除了重复方括号和引号的需要)。即使ViewBag属性作为dynamic对象公开,它也实现了一个直接与 ViewData 一起工作的DynamicViewDataDictionary类。

查看Controller类的源代码,您可以找到此方法:

protected internal virtual ViewResult View(string viewName, string masterName, object model)

因此,基本上,当您return View();从控制器调用时,它会创建一个新的类实例,ActionResult将 ViewData 从控制器传递到它的构造函数。然后将实例ActionResult传递给特定的视图引擎(ASPX、Razor),以便它可以用于呈现有问题的视图。

将 ViewBag/ViewData 设为公共静态可能是有害的。对 MVC 应用程序的每个 Web 请求都会创建一个新的控制器实例。如果您将 ViewData/ViewBag 作为公共静态,那么两个并发用户将共享来自 ViewBag/ViewData 的相同数据。

是一个视频。04:05开始讨论ViewBag(formder ViewModel)

于 2013-06-05T21:17:56.343 回答
6

ViewBag是 的一个属性ControllerBase。定义如下:

public Object ViewBag { get; }

请注意,此签名实际上是不正确的。以下是源代码的实际样子:

public dynamic ViewBag {
        get {
            if (_dynamicViewDataDictionary == null) {
                _dynamicViewDataDictionary = new DynamicViewDataDictionary(() => ViewData);
            }
            return _dynamicViewDataDictionary;
        }
    }

_dynamicViewDataDictionary是一个 ExpandoObject;您可以在运行时向其添加属性。它的生命周期与控制器的生命周期相同,也就是 HTTP 请求的生命周期。

于 2013-06-05T21:27:40.760 回答