Views and View Rendering in MVC Applications
Introduction
The ASP.NET MVC framework supports the use of a view engine to generate views (UI). By default, the MVC framework uses custom types that inherit from the existing ASP.NET page (.aspx), master page (.master), and user control (.ascx) types as views.
In the typical workflow of an MVC Web application, controller action methods handle an incoming Web request. These action methods use the incoming parameter values to execute application code, and retrieve or update data model objects from a database. They then select a view that renders a response to a browser.
Note
To run the example code in this topic, you need the ASP.NET MVC Preview 3 release. You can download the release from the Microsoft ASP.NET MVC page of the ASP.NET Web site.
Rendering UI with Views
In the Model-View-Controller (MVC) pattern, views are intended exclusively for encapsulating presentation logic. They should not contain any application logic or database retrieval code. All application logic should be handled by the controller.
A view renders the appropriate UI by using the MVC view-related data object. The view obtains the data object from a controller action method, which passes the data object to the view when the action method calls the View method.
Note
The Views folder is the recommended location for views in the MVC Web project structure.
The following example shows how a view is rendered in a controller class.
Public Function Categories()
Dim categories As List(Of Category) = northwind.GetCategories()
Return View("Categories", categories)
End Function
public ActionResult Categories()
{
List<Category> categories = northwind.GetCategories();
return View("Categories", categories);
}
In the example, two parameters are passed in the View method call. The first parameter specifies the name of the view to render. Because the name of the view is the same as the name of the action method, this parameter is not required. The second parameter is a list of category objects that are passed to the view. These objects are used as data to generate the appropriate HTML UI.
Preventing Access to the Views Directory
For additional security in your ASP.NET MVC Web application, you can prevent direct access to the Views directory, but still allow programmatic access for the MVC framework. To do so, you can add the following authorization element to the system.web section of the Web.config file in the Views directory:
<authorization>
<deny users="*"/>
</authorization>
View Pages
A view page is an instance of the ViewPage class. It inherits from the Page class and implements the IViewDataContainer interface. The IViewDataContainer interface defines a ViewData property that returns a ViewDataDictionary object, which contains the data for the view to display.
You can create a view page by using templates that are provided in an ASP.NET Web application project. By default, views are ASP.NET Web pages that are rendered by the MVC framework. The MVC framework uses URL routing to determine which controller action to invoke, and the controller action then decides which views to render.
The following example shows the markup for the Index.aspx page. This page is one of the default views that is generated when you create a new MVC project. By convention, the name "Index" is given to the default view for an ASP.NET MVC application.
The @ Page directive contains the Inherits attribute, which defines the relationship between the application and the view. By default, the value of the Inherits attribute follows this pattern: Application.Views.Controller.View.
<%@ Page Language="VB" MasterPageFile="~/Views/Masters/Site.Master"
AutoEventWireup="true" CodeBehind="Index.aspx.vb"
Inherits="MvcApplication.Views.Home.Index" %>
<asp:Content ID="Content2"
ContentPlaceHolderID="BodyContentPlaceHolder"
runat="server">
Welcome!
</asp:Content>
<%@ Page Language="C#" MasterPageFile="~/Views/Masters/Site.Master"
AutoEventWireup="true" CodeBehind="Index.aspx.cs"
Inherits="MvcApplication.Views.Home.Index" %>
<asp:Content ID="Content2"
ContentPlaceHolderID="BodyContentPlaceHolder"
runat="server">
Welcome!
</asp:Content>
The following example lists the code for the Index.aspx.cs and Index.aspx.vb files. The code-behind file includes a partial-class definition that establishes that the page derives from the ViewPage class.
Imports System
Imports System.Configuration
Imports System.Collections
Imports System.Web
Imports System.Mvc
Namespace MvcApplication.Views.Home
Partial Class Index
Inherits ViewPage
End Class
End Namespace
using System;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Mvc;
namespace MvcApplication.Views.Home
{
public partial class Index : ViewPage
{
}
}
Master-Page Views
Like ASP.NET pages in Web Forms-based applications, ASP.NET page views (.aspx files) can use master pages to define a consistent layout and structure. In a typical site, the master page is bound to a content page in the @ Page directive of the content page. You can also use dynamic master pages (that is, you can assign a master page at run time) when you call the View method of the Controller base class.
The following example shows an ASP.NET page view that includes a reference to a master page. The name of the company that is displayed in the title is retrieved from the ViewData object that is associated with this view.
<%@ Page Language="VB" MasterPageFile="~/Views/Masters/Site.Master"
AutoEventWireup="true" CodeBehind="About.aspx.vb"
Inherits="MvcApplication.Views.Home.About" %>
<asp:Content ID="Content1"
ContentPlaceHolderID="HeadContentPlaceHolder"
runat="server">
<title><%= "About " & ViewData["CompanyName"] %></title>
</asp:Content>
<asp:Content ID="Content2"
ContentPlaceHolderID="BodyContentPlaceHolder"
runat="server">
Add information about your company here.
</asp:Content>
<%@ Page Language="C#" MasterPageFile="~/Views/Masters/Site.Master"
AutoEventWireup="true" CodeBehind="About.aspx.cs"
Inherits="MvcApplication.Views.Home.About" %>
<asp:Content ID="Content1"
ContentPlaceHolderID="HeadContentPlaceHolder"
runat="server">
<title><%= "About " + ViewData["CompanyName"] %></title>
</asp:Content>
<asp:Content ID="Content2"
ContentPlaceHolderID="BodyContentPlaceHolder"
runat="server">
Add information about your company here.
</asp:Content>
The following example lists the code for the About.aspx.cs and About.aspx.vb files that accompany the page listed in the previous example. Because the business logic of an MVC application is handled by the controller, the code-behind files of a view should contain only UI-rendering logic. In this case, the code-behind file has no application code in it; it exists only to establish that the page inherits from ViewPage.
Imports System
Imports System.Configuration
Imports System.Collections
Imports System.Web
Imports System.Mvc
Namespace MvcApplication.Views.Home
Partial Class About
Inherits ViewPage
End Class
End Namespace
[C#]
using System;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Mvc;
namespace MvcApplication.Views.Home
{
public partial class About : ViewPage
{
}
}
For more information about this example and about how to use a master page in a view, see the example in ASP.NET MVC Overview.
Passing Data to a View
Typically, you provide data for the view to render. 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:
Public Class SampleController
Inherits Controller
Public Function Welcome()
ViewData("FirstName") = "Joe"
ViewData("LastName") = "Healy"
Return View()
End Function
public SampleController : Controller {
public ActionResult Welcome() {
ViewData["FirstName"] = "Joe";
ViewData["LastName"] = "Healy";
return View();
}
}
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.
Passing Strongly Typed Data to a View
Passing data between a view and a controller using the ViewData property of the ViewPage class is convenient, but the data is not strongly typed. If you want to pass strongly typed data, change the class declaration in the code-behind file of the view so that the view inherits from ViewPage<TModel> instead of from ViewPage.
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 named User.
Public Class User
Public Property Name() As String
End Property
Public Property Id() As Integer
End Property
Public Property Age() As Integer
End Property
Public Property City() As String
End Property
Public Property State() As String
End Property
End Class
public class User
{
public string Name { get; set; }
public int Id { get; set; }
public int Age { get; set; }
....public string City { get; set; }
....public string State { get; set; }
}
The following example shows an action method that calls another method to populate the model that was shown in the previous example. The action method then passes the model to the view.
Public Public Function User(ByVal id As Integer) As ActionResult
Dim user As User = New User()
user = GetUserInfoFromDB(id)
Return View(user)
End Function
public ActionResult User(int id)
{
User user = new User();
user = GetUserInfoFromDB(id);
return View(user);
}
Accessing Data in a View
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, which supports an indexer that accepts dictionary keys.
The following example shows the markup for About.aspx, a page that uses the ViewData property to obtain the company name that was passed to the view.
<%@ Page Language="VB" AutoEventWireup="true"
CodeBehind="About.aspx.vb"
Inherits="MvcApplication5.Views.Home.About" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>ViewData Property - Dictionary Based</title>
</head>
<body>
<div>
<%="About " & ViewData("CompanyName")%>
</div>
</body>
</html>
<%@ Page Language="C#" AutoEventWireup="true"
CodeBehind="About.aspx.cs"
Inherits="MvcApplication5.Views.Home.About" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>ViewData Property - Dictionary Based</title>
</head>
<body>
<div>
<%="About " + ViewData["CompanyName"]%>
</div>
</body>
</html>
Accessing Strongly Typed Data in a View
If the view inherits from the ViewPage<TModel> class instead of from ViewPage, you can access the strongly typed ViewData property by using an expression. The expression uses the following dot-based syntax that is used to access properties:
ViewData.Model.Property name.
The following example shows the markup for a form that accesses strongly typed data in text boxes.
<form method="post" action="Home/Update">
Name: <%= Html.TextBox("name", ViewData.Model.Name) %><br />
Age: <%= Html.TextBox("age", ViewData.Model.Age %><br />
<input type="submit" value="Submit" />
</form>
Passing State Between Action Methods
Action methods might have to pass data to the next action, such as when 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 TempData dictionary 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 TempData dictionary 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 the markup for a view that displays an error.
<form action="/App/InsertCustomer">
<% If Not ViewData.ErrorMessage Is Nothing { %>
The following error occurred while inserting the customer data:
<br />
<%= ViewData.ErrorMessage %>
<br />
<% End If %>
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>
<form action="/App/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>
The following example shows a data class that is used to trap an error and transfer data between actions.
Public Class InsertError
Public ErrorMessage As String
Public OriginalFirstName As String
Public OriginalLastName As String
' CustomersController
Public Function InsertCustomer(ByVal firstName As String, _
ByVal lastName As String)
' Check for input errors.
If String.IsNullOrEmpty(firstName) Or _
String.IsNullOrEmpty(lastName) Then
TempData("error") = New InsertError("Both names are required", _
firstName, lastName)
Return RedirectToAction("NewCustomer")
End If
' No errors
' ...
End Function
Public Function NewCustomer()
Dim err As InsertError = CType(TempData, 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
End Function
' ...
Return View()
End Class
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)) {
TempData["error"] = new InsertError("Both names are required",
firstName, lastName);
return RedirectToAction("NewCustomer");
}
// No errors
// ...
}
public ActionResult NewCustomer() {
InsertError err = TempData 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();
}
Helper Classes and Members for Rendering Views
When you create views, many tasks are repetitive or require special MVC framework knowledge. To address these scenarios and to make rendering HTML easier, the framework includes helper classes and members. The design for helper classes is extensible so that you can add custom helper classes and members.
The MVC framework includes the following helpers:
-
Form helpers. These helpers are for form elements such as radio buttons, list boxes, select buttons, text boxes, text areas, hidden content, and password fields.
-
URL helpers.
-
HTML helpers.
You can access code-based rendering helpers by using properties that are added to the ViewPage, ViewUserControl, and ViewMasterPage classes.
This topic is ASP.NET Extensions documentation and is unsupported by Microsoft. Blank topics are included as placeholders and existing content is subject to change in future releases.