Passing Data in an ASP.NET MVC Application
The ASP.NET MVC framework provides page-level containers for passing data between controllers and views. This topic explains how to pass both weakly typed and strongly typed data in an MVC application. It also explains how to pass temporary state data between action methods.
Passing Data Between a Controller and a View
To render a view, you call the View method of the controller. To pass data to the view, you use the ViewData property of the ViewPage class. This property returns a ViewDataDictionary object that has case-insensitive string keys. To pass data to the view, you can assign values to the dictionary, as shown in the following example:
Dim petList As List(Of String) = New List(Of String)
petList.Add("Dog")
petList.Add("Cat")
petList.Add("Hamster")
petList.Add("Parrot")
petList.Add("Gold fish")
petList.Add("Mountain lion")
petList.Add("Elephant")
ViewData("pets") = New SelectList(petList)
List<string> petList = new List<string>();
petList.Add("Dog");
petList.Add("Cat");
petList.Add("Hamster");
petList.Add("Parrot");
petList.Add("Gold fish");
petList.Add("Mountain lion");
petList.Add("Elephant");
ViewData["Pets"] = new SelectList(petList);
If you call the View method without parameters (as shown in the previous example), the controller object's ViewData property is passed to the view that has the same name as the action method.
In the view page, you can access the ViewData property to obtain data that was passed to the view. The ViewData property is a dictionary that supports an indexer that accepts dictionary keys.
The following example shows the markup for a view that displays the data in an HTML form and enables the user to modify values and make selections.
<h2><%= Html.Encode(ViewData("Message")) %></h2>
<br /><br />
<% Using Html.BeginForm("HandleForm", "Home")%>
Enter your name: <%= Html.TextBox("name") %>
<br /><br />
Select your favorite color:<br />
<%= Html.RadioButton("favColor", "Blue", true) %> Blue <br />
<%= Html.RadioButton("favColor", "Purple", false)%> Purple <br />
<%= Html.RadioButton("favColor", "Red", false)%> Red <br />
<%= Html.RadioButton("favColor", "Orange", false)%> Orange <br />
<%= Html.RadioButton("favColor", "Yellow", false)%> Yellow <br />
<%= Html.RadioButton("favColor", "Brown", false)%> Brown <br />
<%= Html.RadioButton("favColor", "Green", false)%> Green
<br /><br />
<%=Html.CheckBox("bookType")%> I read more fiction than non-fiction.<br />
<br /><br />
My favorite pet: <%=Html.DropDownList("pets")%>
<br /><br />
<input type="submit" value="Submit" />
<% End Using%>
<h2><%= Html.Encode(ViewData["Message"]) %></h2>
<br /><br />
<% using(Html.BeginForm("HandleForm", "Home")) %>
<% { %>
Enter your name: <%= Html.TextBox("name") %>
<br /><br />
Select your favorite color:<br />
<%= Html.RadioButton("favColor", "Blue", true) %> Blue <br />
<%= Html.RadioButton("favColor", "Purple", false)%> Purple <br />
<%= Html.RadioButton("favColor", "Red", false)%> Red <br />
<%= Html.RadioButton("favColor", "Orange", false)%> Orange <br />
<%= Html.RadioButton("favColor", "Yellow", false)%> Yellow <br />
<%= Html.RadioButton("favColor", "Brown", false)%> Brown <br />
<%= Html.RadioButton("favColor", "Green", false)%> Green
<br /><br />
<%= Html.CheckBox("bookType") %> I read more fiction than non-fiction.<br />
<br /><br />
My favorite pet: <%= Html.DropDownList("pets") %>
<br /><br />
<input type="submit" value="Submit" />
<% } %>
Passing Strongly-Typed Data Between a Controller and a View
When you pass data between a view and a controller by using the ViewData property of the ViewPage class, the data is not strongly typed. If you want to pass strongly typed data, change the @ Page declaration of the view so that the view inherits from ViewPage<TModel> instead of from ViewPage, as shown in the following example:
<%@ Page Inherits="ViewPage<Product>" %>
ViewPage<TModel> is the strongly-typed version of ViewPage. The ViewData property of ViewPage<TModel> returns a ViewDataDictionary<TModel> object, which contains strongly typed data for the view based on a model. The model is a class that contains properties for each data item that you want to pass.
The following example shows the definition of a typical data model class named Person.
Public Class Person
Private _Id As Integer
Public Property Id() As Integer
Get
Return _Id
End Get
Set(ByVal value As Integer)
_Id = value
End Set
End Property
Private _Name As String
Public Property Name() As String
Get
Return _Name
End Get
Set(ByVal value As String)
_Name = value
End Set
End Property
Private _Age As Integer
Public Property Age() As Integer
Get
Return _Age
End Get
Set(ByVal value As Integer)
_Age = value
End Set
End Property
End Class
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
The following example shows a view that enables the user to modify the values of a Person object and to submit the changes for update.
<h2>Edit</h2>
<%=Html.ValidationSummary("Edit was unsuccessful. Please correct the errors and try again.")%>
<% Using Html.BeginForm() %>
<fieldset>
<legend>Fields</legend>
<p>
<label for="Id">Id:</label>
<%= Html.TextBox("Id", Model.Id) %>
<%= Html.ValidationMessage("Id", "*") %>
</p>
<p>
<label for="Name">Name:</label>
<%= Html.TextBox("Name", Model.Name) %>
<%= Html.ValidationMessage("Name", "*") %>
</p>
<p>
<label for="Age">Age:</label>
<%= Html.TextBox("Age", Model.Age) %>
<%= Html.ValidationMessage("Age", "*") %>
</p>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
<% End Using %>
<div>
<%=Html.ActionLink("Back to List", "Index") %>
</div>
<h2>Edit</h2>
<%= Html.ValidationSummary("Edit was unsuccessful. Please correct the errors and try again.") %>
<% using (Html.BeginForm()) {%>
<fieldset>
<legend>Fields</legend>
<p>
<label for="Id">Id:</label>
<%= Html.TextBox("Id", Model.Id) %>
<%= Html.ValidationMessage("Id", "*") %>
</p>
<p>
<label for="Name">Name:</label>
<%= Html.TextBox("Name", Model.Name) %>
<%= Html.ValidationMessage("Name", "*") %>
</p>
<p>
<label for="Age">Age:</label>
<%= Html.TextBox("Age", Model.Age) %>
<%= Html.ValidationMessage("Age", "*") %>
</p>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
<% } %>
<div>
<%=Html.ActionLink("Back to List", "Index") %>
</div>
The following example shows the action method that receives a Person object from the Edit view, checks its validity again the model, updates a list of Person objects, and then redirects to the Index action.
Passing State Between Action Methods
Action methods might have to pass data to the next action, such as if an error occurs when a form is being posted. In that case, the user might be redirected to another view that displays error information.
An action method can store data in the controller's TempDataDictionary object before it calls the controller's RedirectToAction method to invoke the next action. The TempData property value is stored in session state. The next action method can get values from the TempDataDictionary object to process or to display in its own view. The value of TempData persists only from one request to the next.
The following example shows a data class that is used to trap an error and to transfer data between actions.
Public Class InsertError
Public Property ErrorMessage() As String
End Property
Public Property OriginalFirstName() As String
End Property
Public Property OriginalLastName() As String
End Property
End Class
' CustomersController
Public Function InsertCustomer(ByVal firstName As String, _
ByVal lastName As String) As ActionResult
' Check for input errors.
If String.IsNullOrEmpty(firstName) Or _
String.IsNullOrEmpty(lastName) Then
Dim err As InsertError = New InsertError()
err.ErrorMessage = "Both names are required."
err.OriginalFirstName = firstName
err.OriginalLastName = lastName
TempData("error") = err
Return RedirectToAction("NewCustomer")
End If
' No errors
' ...
Return View()
End Function
Public Function NewCustomer() As ActionResult
Dim err As InsertError = CType(TempData("error"), InsertError)
If Not err Is Nothing Then
' If there is error data from the previous action, display it.
ViewData("FirstName") = err.OriginalFirstName
ViewData("LastName") = err.OriginalLastName
ViewData("ErrorMessage") = err.ErrorMessage
End If
' ...
Return View()
End Function
public class InsertError
{
public string ErrorMessage { get; set; }
public string OriginalFirstName { get; set; }
public string OriginalLastName { get; set; }
}
// CustomersController
public ActionResult InsertCustomer(string firstName, string lastName)
{
// Check for input errors.
if (String.IsNullOrEmpty(firstName) ||
String.IsNullOrEmpty(lastName))
{
InsertError error = new InsertError();
error.ErrorMessage = "Both names are required.";
error.OriginalFirstName = firstName;
error.OriginalLastName = lastName;
TempData["error"] = error;
return RedirectToAction("NewCustomer");
}
// No errors
// ...
return View();
}
public ActionResult NewCustomer()
{
InsertError err = TempData["error"] as InsertError;
if (err != null)
{
// If there is error data from the previous action, display it.
ViewData["FirstName"] = err.OriginalFirstName;
ViewData["LastName"] = err.OriginalLastName;
ViewData["ErrorMessage"] = err.ErrorMessage;
}
// ...
return View();
}
The following example shows the markup for a view that accepts user input and displays the error if one occurs.
<form action="/Home/InsertCustomer">
<% if (ViewData["ErrorMessage"] != null) { %>
The following error occurred while inserting the customer data:
<br />
<%= ViewData["ErrorMessage"] %>
<br />
<% } %>
First name:
<input type="text" name="firstName" value="<%= ViewData["FirstName"] %>" />
<br />
Last name:
<input type="text" name="lastName" value="<%= ViewData["LastName"] %>" />
<br />
<input type="submit" value="Insert" />
</form>