ASP.NET MVC中的ViewBag如何在幕后工作?

时间:2013-06-05 20:40:25

标签: c# asp.net-mvc dynamic viewbag

我正在阅读一本关于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是无状态的。 是这种情况吗?

3 个答案:

答案 0 :(得分:28)

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

它不是static,它是对象的成员。在请求生命周期中,控制器实例被创建和处理,因此您不会遇到“并发”问题,例如覆盖该值。

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

答案 1 :(得分: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中的相同数据。

Here是一段视频。关于ViewBag(formder ViewModel)的讨论从​​04:05开始

答案 2 :(得分:6)

ViewBagControllerBase的属性。它的定义如下:

public Object ViewBag { get; }

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

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

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