ASP.NET MVC provides us with three ways to pass data from Controllers to Views. We've already discussed using TempData to create a FlashMessage partial. Now, let's discuss the second method available to us: ViewBag.

What's in the Bag?

ViewBag, according to MSDN, "enables you to dynamically share values from the controller to the view". The key word there is "dynamically"; ViewBag is of type dynamic. Essentially, they are a type where the actual type (e.g. int, string, char, DateTime, etc) isn't determined until runtime. Which means we can do things like this:

public ActionResult Index() //We'll set the ViewBag values in this action  
{
    ViewBag.PageTitle = "This is the page title";
    ViewBag.PageDescription = "This is the page description.  We'll make it rather longer.";
    ViewBag.PageCreateDate = DateTime.Now;
    ViewBag.CurrentUser = new User()
    {
         Name = "Test Name",
         ID = 4,
         LogonDate = DateTime.Now.AddDays(-20)
    };
    return View();
}

(Scott Hanselman has a pretty good post about dynamic types over on his blog.)

We can put anything we want in ViewBag. It doesn't matter what it is, because it won't be resolved until runtime. And we can then use it on the view:

<h3>@ViewBag.PageTitle</h3>

<p>  
    @ViewBag.PageDescription
</p>

<span>Created on @ViewBag.PageCreateDate.ToShortDateString()</span>

Current user:  
<div>  
    <dl>
        <dt>Name:</dt>
        <dd>@ViewBag.CurrentUser.Name</dd>
        <dt>ID:</dt>
        <dd>@ViewBag.CurrentUser.ID</dd>
        <dt>Logon Date:</dt>
        <dd>@ViewBag.CurrentUser.LogonDate.ToShortDateString()</dd>
    </dl>
</div>  

All in all a pretty sweet thing! We can take anything we want, shove it in ViewBag, and then use it on the View. What could be better?

The Hole in the Bag

As it turns out, almost anything is better than ViewBag. The problem with ViewBag is exactly that it is dynamic. That means, since you can type anything you want as a value in it, you won't catch errors like this:

public ActionResult Index() //We'll set the ViewBag values in this action  
{
    ViewBag.PageTitle = "This is the page title";
    ViewBag.PageDesciption = "This is the page description.  We'll make it rather longer.";
    ViewBag.PageCreateDate = DateTime.Now;
    ViewBag.CurrentUser = new User()
    {
         Name = "Test Name",
         ID = 4,
         LogonDate = DateTime.Now.AddDays(-20)
    };
    return View();
}

Did you catch it? Because the compiler won't catch this error. Dynamic types are exempt from normal type checking, which means things like checking to make sure a name exists in the ViewBag doesn't occur at all. That PageDesciption is now a variable name in ViewBag, and the view won't find the PageDescription it is looking for.

But we can also attempt to do some crazy things by treating one type like another type. Say we wanted to treat a DateTime like it's a String:

public ActionResult Index() //We'll set the ViewBag values in this action  
{
    ViewBag.PageTitle = "This is the page title";
    ViewBag.PageDescription = "This is the page description.  We'll make it rather longer.";
    ViewBag.PageCreateDate = DateTime.Now;
    ViewBag.LastIndexOfC = ViewBag.PageCreateDate.LastIndexOf('c');
    ViewBag.CurrentUser = new User()
    {
        Name = "Test Name",
        ID = 4,
        LogonDate = DateTime.Now.AddDays(-20)
    };
    return View();
}

LastIndexOfC is checking the value of PageCreateDate and attempting to get the last index of 'c', hence assuming PageCreateDate is a string.. But it's not a string, it's a DateTime, and we don't catch this error until we attempt to execute the code, when we will get an exception. There's no protection from misspelling, or from using one type as another, so we can pretty easily shoot ourselves in the foot.

Toss the Bag!

So what's our alternative? Why, using a ViewModel of course!

[HttpGet]
public ActionResult About() //This time, let's use a ViewModel  
{
    HomeAboutVM model = new HomeAboutVM();
    model.PageTitle = "This is the About page";
    model.PageDescription = "See how much better using a ViewModel is?";
    model.PageCreateDate = DateTime.Now;
    model.CurrentUser = new User()
    {
        Name = "Test Name",
        ID = 4,
        LogonDate = DateTime.Now.AddDays(-20)
    };
    return View(model);
}

Now, we've got strong type protection, and any attempts to treat a variable of one type like a different type will be caught and handled by the compiler.

We should always favor ViewModels over ViewBag, if for no other reason than ViewModels are strongly typed.

One Exception

There's one scenario in which using ViewBag is appropriate (because it's mandatory), and that's when we want to set a Page Title on a given view:

@{
    ViewBag.Title = "This shows up in the browser tab";
}

Other than that, we should avoid using ViewBag. It's a poor way to transfer data between controllers and views.

Feel free to grab a sample project demonstrating ViewBag from GitHub.

Happy Coding!