Views and Rendering Helpers
Introduction
The ASP.NET MVC framework supports using any templating engine to generate views (UI). By default, the MVC framework uses the existing ASP.NET page (.aspx), master page (.master), and user control (.ascx) types for this purpose.
In the typical workflow of an MVC Web application, controller action methods handle the incoming Web request. These action methods use the incoming parameter values to execute application code, retrieve or update data model objects from a database, and 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 2 release. You can download the release from the ASP.NET Web site.
Rendering UI with Views
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.
Views render the appropriate UI by using the MVC view-related data objects that a controller action method provides when it calls the RenderView 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 Sub Categories()
Dim categories As List(Of Category) = northwind.GetCategories()
RenderView("Categories", categories)
End Sub
public void Categories()
{
List<Category> categories = northwind.GetCategories();
RenderView("Categories", categories);
}
In the example, the RenderView method is called with two parameters. The first parameter indicates the name of the view to render. The second parameter is a list of category objects that are passed to the view and that 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 permit programmatic access for the MVC framework). Add the following authorization element to the system.web section of the Web.config file in the Views directory:
<authorization>
<deny users="*"/>
</authorization>
ASPX Page Views
A view page of type ViewPage is an instance of a Page class that implements the IView interface. 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 found through the MVC framework by using the built-in rendering engine.
The following example lists the markup for a page named Index.aspx.
<%@ 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.
Imports System
Imports System.Configuration
Imports System.Collections
Imports System.Web
Imports System.Mvc
Namespace MvcApplication.Views.Home
Partial Class Index
Inherits ViewPage(Of CompanyInfo)
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<CompanyInfo>
{
}
}
The following example shows how to use the ViewData property. There are two variants of this property. If your view inherits from the System.Web.Mvc.ViewPage class, the ViewData property is a dictionary. The property supports an indexer that accepts dictionary keys
The following example lists the markup for About.aspx, a page that uses a dictionary-based ViewData property.
<%@ 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>
The following example shows the code for the About.aspx.cs and About.aspx.vb files.
Imports System
Imports System.Web
Imports System.Mvc
Namespace MvcApplication.Views.Home
Partial Class About
Inherits ViewPage
End Class
End Namespace
using System;
using System.Web;
using System.Web.Mvc;
namespace MvcApplication5.Views.Home
{
public partial class About : ViewPage
{
}
}
Alternatively, you can use a strongly typed ViewData property. This provides better type checking of the data that is passed from the controller to the view. However, it is not as flexible as using the dictionary. The following example shows the same page as the previous example, but this example uses a strongly typed ViewData property.
<%@ Page Language="VB" AutoEventWireup="true" CodeBehind="About.aspx.vb" Inherits="MvcApplication.Views.Billing.Account" %>
<head id="Head1" runat="server">
<title>ViewData Property - Strongly Typed</title>
</head>
<body>
<div>
<%="About " & ViewData.CompanyName %>
</div>
</body>
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="About.aspx.cs" Inherits="MvcApplication.Views.Billing.Account" %>
<head id="Head1" runat="server">
<title>ViewData Property - Strongly Typed</title>
</head>
<body>
<div>
<%="About " + ViewData.CompanyName %>
</div>
</body>
Instead of indexing the ViewData property as if it were a dictionary, the code uses normal property syntax.
The code for the page uses the generic ViewPage<T> base class (ViewPage(Of T) in Visual Basic) to specify the type of the view data, as shown in the following example:
Imports System
Imports System.Configuration
Imports System.Collections
Imports System.Web
Imports System.Mvc
Namespace MvcApplication.Views.Billing
Partial Class Account
Inherits ViewPage(Of AcctInfo)
End Class
End Namespace
using System;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Mvc;
namespace MvcApplication.Views.Billing
{
public partial class Account : ViewPage<AcctInfo>
{
}
}
Master-Page Views
Like ASP.NET Web pages in non-MVC 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) by overloading the RenderView method of the Controller base class.
The following example shows an ASP.NET page view that includes a reference to a master page.
<%@ 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.
Imports System
Imports System.Configuration
Imports System.Collections
Imports System.Web
Imports System.Mvc
Namespace MvcApplication.Views.Home
Partial Class About
Inherits ViewPage(Of CompanyInfo)
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<CompanyInfo>
{
}
}
For more information about this example code, which includes information about the master page, see the example in ASP.NET MVC Overview.
Setting View Data
Typically, you provide data for the view to render. To render a view, you call the RenderView method of the controller. There are two ways to pass data from a controller to a view. The Controller class exposes a ViewData property, which returns an IDictionary<string,object> with case-insensitive string keys. You can assign indexed values to the dictionary, as shown in the following example:
Public Class SampleController
Inherits Controller
<ControllerAction()> _
Public Sub Welcome()
ViewData("FirstName") = "Joe"
ViewData("LastName") = "Healy"
RenderView("Welcome")
End Sub
public SampleController : Controller {
[ControllerAction]
public void Welcome() {
ViewData["FirstName"] = "Joe";
ViewData["LastName"] = "Healy";
RenderView("Welcome");
}
}
If you call the RenderView method with only a view name, as shown in the previous example, the Controller object's ViewData property is passed as a dictionary to the view. If you want to use a strongly typed ViewData property, you can ignore the ViewData property. Instead, in your controller action, you create an object that you want to pass to the view and then pass it to the RenderView method. The following example shows how to call the RenderView method with strongly typed data.
Public Class SampleViewData
Public FirstName As String
Public LastName As String
End Class
Public Class SampleController
Inherits Controller
Public Sub Welcome()
Dim viewData As SampleViewData = New SampleViewData()
viewData.FirstName = "Joe"
viewData.LastName = "Healy"
RenderView("Welcome", viewData)
End Sub
End Class
public class SampleViewData {
public string FirstName { get; set; }
public string LastName { get; set; }
}
public SampleController : Controller {
public void Welcome() {
SampleViewData viewData = new SampleViewData();
viewData.FirstName = "Joe";
viewData.LastName = "Healy";
RenderView("Welcome", viewData);
}
}
Passing State Between Action Methods
Action methods might have to pass data to the next action, such as when an error occurs while a form is being posted. In that case, the user might be redirected to the entry form (view), which can display error information.
An action method can set the controller's TempData property to an arbitrary object before the action method calls the controller's RedirectToAction method to invoke the next action. The TempData property value is stored in session state. The next action can check the TempData property and get values from it to display in its own view. The value of TempData persists only from one request to the next.
The following example shows how to trap an error and redirect to an error page with the original data.
<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 transfer data between actions.
Public Class InsertError
Public ErrorMessage As String
Public OriginalFirstName As String
Public OriginalLastName As String
' CustomersController
Public Sub 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 required", _
firstName, lastName)
RedirectToAction("NewCustomer")
Return
End If
' No errors
' ...
End Sub
Public Sub 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 Sub
' ...
End Class
public class InsertError {
public string ErrorMessage { get; set; }
public string OriginalFirstName { get; set; }
public string OriginalLastName { get; set; }
}
// CustomersController
public void InsertCustomer(string firstName, string lastName) {
// Check for input errors.
if (String.IsNullOrEmpty(firstName) ||
String.IsNullOrEmpty(lastName)) {
TempData["error"] = new InsertError("Both names required",
firstName, lastName);
RedirectToAction("NewCustomer");
return;
}
// No errors
// ...
}
public void 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;
}
// ...
}
Rendering Helpers
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 helpers is extensible so that you can add custom helper classes and members.
The MVC framework includes the following helpers:
-
Methods for processing and rendering simple data, such as encoding HTML strings and generating URLs for invoking actions.
-
Methods for more complex tasks such as rendering complete grids of data.
-
Controls that call the rendering helpers. These helpers can improve design-time rendering.
-
Classes that incorporate more complex logic such as rendering a multi-column layout in a table format.
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 3.5 Extensions pre-release documentation and is unsupported by Microsoft. Blank topics are included as placeholders and existing content is subject to change in future releases. To provide feedback or ask questions about the release, please go to the ASP.NET 3.5 Extensions forums.