Understanding ViewData, ViewBag and TempData
While working with ASP.NET MVC applications you often need to pass data from
controller action methods to the view. And there are various techniques to
accomplish that goal - ViewData, ViewBag and TempData. This article explains
these techniques, their usage and the difference between them.
In an ASP.NET MVC application a controller can easily pass a model to a view
using an overloaded View() method as shown below:
public ActionResult Index()
{
List<Customer> model = GetCustomers();
return View(model);
}
As you can see the Index() method gets a List of Customer objects from a
hypothetical GetCustomers() helper method and then passes it to the Index view
by calling the View() method. The Index view can then access this model using
the Model property.
Although passing data to a view through a model or view model class is a
recommended practice, at times you need to pass some arbitrary data to the view. For example, you may need to pass a success or error message
from a controller to a view so that it can be rendered in the browser. Or you may want to pass an auxiliary
object holding some calculated results to the view. Since such data is not a part of
the model you need some mechanism to pass it to the view. That is where ViewData, ViewBag and TempData
objects come into picture. ViewData,
ViewBag and TempData are inbuilt objects available to controllers and views. Each
of these objects have their own specialties and
features. So, let's examine each of them in bit more detail.
If you need to pass reasonable amount of data from a controller to a view
that's not a part of
model itself, you should give a thought to creating a view model. If something can't go
in view model for some reason you can use the techniques discussed here to facilitate the data
transfer.
ViewData
The primary purpose of ViewData is to carry data from the controller to the
view. ViewData is a dictionary object and is of type ViewDataDictionary. Just
like any other dictionary object in .NET, ViewData allows you to store key-value
pairs. Data stored in ViewData object exists only during the current request. In
other words, as soon as the view is rendered in the browser the ViewData object
is emptied.
The following code shows an action method that sets a ViewData key named
message with a developer defined message.
public ActionResult Index()
{
Customer model = new Customer() {
CustomerID = "ALFKI",
CompanyName = "Company 1",
ContactName = "Contact 1",
Country = "Country 1" };
ViewData["message"] = "This is a test message";
return View(model);
}
The Index() action method creates an instance of Customer class. The Customer
object thus created is supposed to act as the model for the Index view.
Then the code stores message key in the ViewData dictionary with its value set
to This is a test message. Finally, the action method returns Index
view by calling View() method and passing Customer model to it.
The following code from the Index view shows how ViewData dictionary can be
accessed inside a view.
@model ViewDataViewBagTempData.Models.Customer
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
<h1>@Model.CustomerID</h1>
<h3>@ViewData["message"]</h3>
<h2>@ViewData.Model.CompanyName</h2>
</body>
</html>
Notice the code marked in bold letters. The @model sets the data model for
the view to ViewDataViewBagTempData.Models.Customer. This data model can be
accessed using Model property as shown by @Model.CustomerID line. Next, the code
outputs the value of message ViewData key using the dictionary syntax. The last
line marked in bold letters may surprise you. It uses Model property of ViewData
object to access the model associated with the view. So, ViewData provides a
pointer to the model although you will use it rarely in this fashion because the
model is directly available to a view through Model property.
As soon as the request-response cycle completes the ViewData dictionary is emptied.
In the preceding example, you stored a string value in ViewData. You could
have stored any other type of data such as integer, Boolean or object. The
following code stores CustomerInfo object into ViewData:
public ActionResult Index()
{
Customer model = new Customer() { ... };
CustomerInfo info = new CustomerInfo() {
LastOrderID = 100,
LastOrderDate = new DateTime(2013, 01, 20),
LastOrderAmount = 12345.6M };
ViewData["extrainfo"] = info;
return View(model);
}
The above code creates Customer model as before. Additionally, it
creates an instance of CustomerInfo class. The CustomerInfo class has three
properties - LastOrderID, LastOrderDate and LastOrderAmount. It then sets a
ViewData key named extrainfo to this CustomerInfo object.
Whatever you store inside ViewData gets stored as a generic object and you
must typecast it while retrieving it inside a view. The following code shows how:
<h3>@{
CustomerInfo info = (CustomerInfo)ViewData["extrainfo"];
@info.LastOrderID
@: |
@info.LastOrderDate
@: |
@info.LastOrderAmount
}</h3>
As you can see the above code residing in the Index view retrieves
extrainfo from ViewData and typecasts it to CustomerInfo class. You can
then use properties of CustomerInfo class to display their values in the view.
Remember that you also need to check for null values in your view in case you
expect ViewData entries to be null.
ViewBag
ViewBag is a wrapper over ViewData and allows you to store and retrieve
values using object-property syntax rather than key-value syntax used by
dictionary objects. It does so using the
dynamic data type feature of
.NET. In addition to providing object-properties syntax ViewBag also saves
you from the job of typecasting as you did with ViewData object. Let's see how
ViewBag can be used:
public ActionResult Index()
{
Customer model = new Customer() { ... };
CustomerInfo info = new CustomerInfo() { ... };
ViewBag.ExtraInfo = info;
return View(model);
}
As you can see, this time the code uses ViewBag object to store CustomerInfo
object. It does so by declaring a developer defined property ExtraInfo and
setting it to info object. If you observe ViewData object in Quick Watch window
you will see this:

The ExtraInfo dynamic property is actually stored as ExtraInfo ViewData key !
Of course, you should stick to a uniform syntax while accessing this object
(stick to ViewBag syntax in this case).
To retrieve CustomerInfo passed to the view you will write the following
code:
<h3>@{
@ViewBag.ExtraInfo.LastOrderID
@: |
@ViewBag.ExtraInfo.LastOrderDate
@: |
@ViewBag.ExtraInfo.LastOrderAmount
}</h3>
This time you don't need to typecast ExtraInfo to CustomerInfo and you can
access its properties directly (Remember, however, that these properties won't
be displayed in VS IntelliSense as such).
While deciding whether to use ViewData or ViewBag you need to consider
developer choice and need for typecasting. Since ViewBag is just a wrapper over
ViewData, whatever you store inside ViewBag is accessible only during the
current request.
TempData
TempData offers a dictionary storage like ViewData. However, values stored in
TempData exists unless they are read in some view. Most commonly TempData is used
to pass a value between the current request and the subsequent request.
Consider an example where you are deleting a record from the database. You have
created two action methods - Index() and Delete(). The Index() action method
fetches a set of record and passes then to Index view to display in a table. The
Index view consists of a table showing all the records and each table row has a
Delete link that points to the Delete() action method. The Delete() action
method does the job of deleting a record and once a record is deleted it takes
the control to Index() action method so that the table can be re-displayed. Now
suppose that when the table is re-displayed after deleting a record you wish to
display a message to the user informing that so-and-so record has been deleted.
You can't pass such a message using ViewData or ViewBag because here one request
(the one that causes deletion) wants to pass data to another request (the one
that renders a table of records).
The following code makes this clear:
public ActionResult Index()
{
Customer model = new Customer() { ... };
return View(model);
}
public ActionResult Delete(int id)
{
//delete record here
TempData["message"] = "Record deleted successfully!";
//transfer control to Index(). This will be another request.
return RedirectToAction("Index");
}
In this case request that invokes Delete() is the first request. During this
request you store a TempData key named message and assign it some value. You
then call RedirectToAction() to take the control to Index() method. Remember
that RedirectToAction() returns HTTP 302 response to the browser so that the
browser makes a GET request to the specified action method. At this
point of time the second request is made. You wish to access data set during the
first request in the second request and hence you use TempData.
The value set in the TempData can be accessed in the Index view like this:
<body>
<h1>Index View</h1>
<h3>@TempData["message"]</h3>
</body>
So far so good. While the above example works as expected, you need to be
aware of a tricky thing. If you don't read the TempData values in the second
request, they are persisted and can be read in yet subsequent request. They
exist unless you read them in some view at which point of time they are removed.
Consider the following code that makes this behavior clear:
public ActionResult Index1()
{
TempData["message"] = "Test message!";
return View();
}
public ActionResult Index2()
{
return View();
}
public ActionResult Index3()
{
return View();
}
Assume that Index1 view has a link pointing to Index2 action method and
Index2 view has a link pointing to Index3 action method. Now, if Index1 and
Index2 views do not use TempData at all then it is still available to Index3
view. However, if Index1 or Index2 views use TempData then it is removed as soon
as the respective request completes. Index3 view won't be able to read TempData
value in that case.
There is one more twist in the TempData story that you should be aware of.
The TempData object has Keep() method that can preserve the value(s) even after
they are read. To do so, once you finish reading the values call TempData.Keep()
or TempData.Keep(<key>). Calling Keep() marks the tempdata key(s) for
retention till next read operation.
It would be interesting to know that TempData values are actually stored in
ASP.NET Session and are automatically removed once they are read. To prove that
they are indeed stored in Session just disable session state altogether by
adding this line in web.config:
<sessionState mode="Off"></sessionState>
If you try to run the same example now, you will get this error.

Just like ViewData, TempData also requires typecasting and null value
checking while accessing its values.
To summarize,
- ViewData, ViewBag and TempData allow you to pass values from a
controller to a view.
- ViewData and TempData objects allow you to store values as key-value
pairs.
- ViewBag object allows you to store values using object-properties
syntax.
- ViewBag is a wrapper over ViewData.
- ViewData and ViewBag values are available only during current request.
- TempData values are accessible in the current request and the subsequent
requests. They are removed when a view reads them.
- TempData internally uses Session to store its values. The values are
removed once they are read.
- ViewData and TempData require typecasting and null checking whereas
ViewBag doesn't need such checking.