34

I am reading a book on ASP.NET MVC and I'm wondering how the following example works:

Example #1

Controller

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

        return View();
    }
}

View

<h1>@ViewBag.MyProperty</h1>

Now I understand that ViewBag is a dynamic object, so that's how you can set the property (though I don't know much about dynamic objects, never worked with them.) But how does the view get the specific instance of the ViewBag from the controller, even though we don't pass anything directly?

I thought that the ViewBag could be a public static object, but then any change to it would be global and it wouldn't be specific to a view instance.

Could you elaborate as to how this works behind the scenes?

Example #2

Controller

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

        return View();
    }

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

        return View();
    }
}

Now let's say the Index method is called first, and then the Index2. In the end the value of ViewBag.MyProperty will end up as 6 (the value from Index2). I feel that it is not a good thing to do, but at the same time I feel that I'm thinking in desktop development terms. Maybe it doesn't matter when used with ASP.NET MVC, as the web is stateless. Is this the case?

Shog9
  • 156,901
  • 35
  • 231
  • 235
hattenn
  • 4,371
  • 9
  • 41
  • 80
  • 1
    I would imagine that the `ViewBag` object is simply instantiated with the controller object as an instance property (not `static`). – Robert Harvey Jun 05 '13 at 20:42
  • You can see it's actually a member of the controller: http://msdn.microsoft.com/en-us/library/system.web.mvc.controllerbase.viewbag(v=vs.98).aspx – McGarnagle Jun 05 '13 at 20:44
  • So if there are two methods returning different views set the same property on the `ViewBag` instance, it can affect each other? Wouldn't that cause a problem? I feel that I'm still thinking in desktop development though. – hattenn Jun 05 '13 at 20:44
  • 1
    The controller is instantiated when `Index()` is called, and disposed after `return View();` is executed. So `ViewBag` goes out of scope once the entire request is completed. That's why the `ViewBag` properties do not persist across requests. – Robert Harvey Jun 05 '13 at 20:46
  • @RobertHarvey, alright then. It makes sense now. I didn't know what was instantiated when. As I said, still thinking in desktop development way. Could you write these as an answer, I will choose it as the accepted answer. – hattenn Jun 05 '13 at 20:50
  • I would, but it's unclear from the MSDN page that @dbaseman linked what is actually stored in that `object` property. I suspect that it is an [`ExpandoObject`](http://msdn.microsoft.com/en-us/library/system.dynamic.expandoobject.aspx). – Robert Harvey Jun 05 '13 at 20:54
  • @hattenn WebForms is a web framework that's *close* to desktop development. MVC, however, is way much different. It's much more the web paradigm. So, trying to understand MVC tools (such as the ViewBag) making a parallel to desktop will always lead you to confusing conclusions (or questions). – Andre Calil Jun 05 '13 at 20:55
  • I remember reading it was an `ExpandObject` couple minutes ago somewhere, let me see. – hattenn Jun 05 '13 at 20:55
  • Wow, `ExpandoObject` is cool. It implements `IEnumerable`, so all of the Linq methods work on it. – Robert Harvey Jun 05 '13 at 20:58
  • @RobertHarvey, in this answer http://stackoverflow.com/a/14985891/494094; Aniket says that it is an `ExpandObject`, but unfortunately he didn't cite his resource. @AndreCalil, you are right that it is completely different than desktop development. I'm just trying to wrap my mind around it and change my mindset. – hattenn Jun 05 '13 at 20:58
  • You can browse the classes definition from VS: `Controller` inherits `ControllerBase` that has the `public dynamic ViewBag { get; }` property – Andre Calil Jun 05 '13 at 20:59
  • @RobertHarvey I believe that this question deserves an wiki answer =) – Andre Calil Jun 05 '13 at 21:00
  • There are so many things that works like magic behind the scenes of ASP.NET MVC though, it's not just trying to understand the way web works. So many conventions and magic stuff. It looks great but nothing that I'm used to. – hattenn Jun 05 '13 at 21:05
  • @hattenn I had this feeling when I started on ASP.NET MVC too, and I hate it. If I ask myself "how does this work?" and I can't give a reasonable answer, I'll look for it. Keep using MVC and you'll notice that there's no magic, it's all conventions (which you have to discover, somtimes). – Andre Calil Jun 05 '13 at 21:07
  • @AndreCalil, yeah sure, but it looks like magic until you read it and understand how it is implemented :) It's kind of cool though, I like it. It's just a bit tiring as I keep asking "Wait a minute, how the hell would that work?" all the time. – hattenn Jun 05 '13 at 21:09
  • @hattenn While learning ASP.NET MVC, http://nerddinner.codeplex.com/ helped me a lot. Check it out! – Andre Calil Jun 05 '13 at 21:14
  • @AndreCalil, thanks for the link. I have heard about it before and will definitely check it out. – hattenn Jun 05 '13 at 21:40

3 Answers3

28

ViewBag is a property of ControllerBase, which all controllers must inherit from. It's a dynamic object, that's why you can add new properties to it without getting compile time errors.

It's not static, it's a member of the object. During the request lifetime, the controller instance is created and disposed, so you won't have "concurrency" problems, like overwriting the value.

The View (and its variants) method is not static as well, and this is how the view receives the ViewBag values: during the process of rendering the view, the controller instance has its ViewBag instance as well.

Ant P
  • 24,820
  • 5
  • 68
  • 105
Andre Calil
  • 7,652
  • 34
  • 41
  • 1
    `ViewBag` is a property of `WebViewPage` as well. how does it get data which is assigned to `ControllerBase.ViewBag` property. Can you elaborate please ? – Abi May 23 '17 at 07:25
  • @Abi the view receives it from the controller when the `ActionResult` is being created. If we take ASP.NET Core MVC as an example, you can see that `ViewContext` receives it on the ctor: https://github.com/aspnet/Mvc/blob/dev/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Rendering/ViewContext.cs – Andre Calil May 23 '17 at 14:46
12

If you would analyse ControllerBase class you would see that ViewBag property is a "proxy" to ViewData property just to make your source look nicer. (I even remember Scott Hanselman taking interview from Phil Haack where Phil introduced ViewBag property as a shortcut to ViewData and eliminating the need of repeated square brackets and quotes). Even though ViewBag property is exposed as dynamic object it implements a DynamicViewDataDictionary class which works directly with ViewData.

Looking at source code of Controller class you can find this method:

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

So basically when you call return View(); from your controller it creates a new instance of ActionResult class passing ViewData from controller to it's constructor. Instance of ActionResult is then passed to a particular view engine (ASPX, Razor) so it could be used to render a view in question.

Making ViewBag/ViewData public static could be harmful. Each web request to your MVC application creates a new instance of controller. If you'd have ViewData/ViewBag as public static then two concurrent users would share same data from ViewBag/ViewData.

Here is a video. Discussion on ViewBag (formder ViewModel) starts at 04:05

Ramunas
  • 3,853
  • 1
  • 30
  • 31
6

ViewBag is a property of ControllerBase. It is defined as follows:

public Object ViewBag { get; }

Note that this signature is actually incorrect. Here's what the source code actually looks like:

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

_dynamicViewDataDictionary is an ExpandoObject; you can add properties to it at runtime. Its lifetime is the same as that of the controller, which is the lifetime of the HTTP request.

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
  • 1
    It appears the ViewBag property of ControllerBase has been consistently defined as dynamic, perhaps recently: `public dynamic ViewBag { get; }` – brntsllvn Sep 08 '16 at 17:53
  • ViewBag is a property of WebViewPage as well. how does it get data which is assigned to ControllerBase.ViewBag property. Can you elaborate please ? – Abi May 23 '17 at 07:36