Walkthrough: Using Templated Helpers to Display Data in ASP.NET MVC
Templated helpers provide a way to automatically build UI based on a data model that is marked with attributes defined in the System.ComponentModel.DataAnnotations namespace. For example, a property in the data model can be marked with the DataTypeAttribute attribute to specify that the property represents a date. A templated helper can then automatically render the property value as a date by using a control designed for dates, instead of using the default rendering, which is to display the property value as a date and time string.
In this walkthrough, you will modify the home controller of an ASP.NET MVC 2 application to display the Products table from the AdventureWorksLT2008 database. By using type matching (sometimes referred to as data scaffolding) that is built into ASP.NET MVC 2 templated helpers, you will also generate views that automatically render appropriate UI for the data in the model.
A Visual Studio project with source code is available to accompany this topic: Download.
Prerequisites
In order to complete this walkthrough, you will need:
Microsoft Visual Studio 2008 Service Pack 1 or Visual Web Developer 2008 Express Edition Service Pack 1.
ASP.NET MVC 2 framework. If you have installed Visual Studio 2010, the ASP.NET MVC 2 is already installed on your computer. To download the most up-to-date version of the framework, see the ASP.NET MVC download page.
The AdventureWorksLT_2008 sample database. For information about how to download and install the SQL Server sample database, see Microsoft SQL Server Product Samples: Database on the CodePlex site. Make sure that you install the correct version of the sample database for the version of SQL Server that you are running (Microsoft SQL Server 2005 or Microsoft SQL Server 2008).
Note
This walkthrough assumes that the MVC project that you have created has the MvcTmpHlprs. All the namespaces used in the walkthrough are MvcTmpHlprs. If you have created a project with a different name, you will need to change the namespace of the sample code to the namespace of your project.
This walkthrough also assumes that you are familiar with MVC. For more information, see ASP.NET MVC 2.
Creating a MVC Project with an AdventureWorks DB Model
This walkthrough uses an Entity Data model (EDM) that is created from the AdventureWorksLT_2008 sample database. As the first step in this walkthrough, you will create a new MVC 2 project and add and EDM from the AdventureWorksLT_2008 sample database.
To create a MVC Project with an AdventureWorks DB Model
Create a new MVC 2 project with the name MvcTmpHlprs.
In Solution Explorer, right-click the App_Data folder and then click Add, then click Existing Item.
The Add Existing Item dialog box is displayed.
Navigate to the folder that contains the AdventureWorksLT2008_Data.mdf, select the AdventureWorksLT2008_Data.mdf file, and then click Add.
Note
You can copy the AdventureWorksLT2008_Data.mdf file from the download that is provided for this walkthrough.
In Solution Explorer, right-click MvcTmpHlprs project, click Add, and then click New Item.
The Add New Item dialog box is displayed.
Under Installed Templates, click ADO.NET Entity Data Model.
In the Name box accept the default model name Model1.edmx.
Click Add.
The Entity Data Model Wizard window is displayed.
Click Generate from database.
Under Which data connection should your application use to connect to the database?, select AdventureWorksLT2008_Data.mdf from the list.
Make sure that the Save entity connection settings in Web.config as check box is selected. You can leave the default connection string name.
Click Next.
The wizard displays a page where you can specify what database objects you want to include in your model.
Select the Tables node to select all tables from the database. You can leave the default model namespace.
Click Finish.
The ADO.NET Entity Data Model Designer is displayed. Close the designer.
Creating a List View To Display Data Fields
As the next step in this walkthrough, you will modify the Home controller to display data from the Products table.
To create a list view to display data fields
Open the HomeController class in the editor.
Just under the class declaration, add the following line to the home controller so you can access the AdventureWorksLT2008 database.
AdventureWorksLT2008Entities _db = new AdventureWorksLT2008Entities ();
Dim _db As AdventureWorksLT2008Entities = _ New AdventureWorksLT2008Entities
Replace the contents of the Index method of the HomeController class with the following line in order to display the products from the AdventureWorksLT2008 database.
var dn = _db.Product .Where(c => c.ProductID < 715); return View(dn);
Dim dn = _db.Product _ .Where(Function(c) c.ProductID < 715) Return View(dn)
The Where clause limits the index page to a subset of the rows in the Products table.
Delete the Views\Home\Index.aspx file.
Right-click inside the Index action method, and then click Add View.
The Add View dialog box is displayed.
Select the Create strongly-typed view check box.
From the View data class list, select the Product class.
The fully qualified product class name will include a namespace such as MvcTmpHlprs.Models.Product.
In the View content list, select List.
Creating a list view automatically adds the IEnumerable type to the Inherits attribute value for the page.
Accept the default values for the other text boxes and check boxes.
Click Add.
A view named Index is created for the Home controller.
Replace everything but the @ Page directive in the Views\Home\Index.aspx file with the following markup:
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"> MVC Product Index Sample </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <h2>Index using Html.DisplayFor</h2> <table> <tr> <th> Product ID </th> <th>Name</th> <th>Color</th> <th>Std. Cost</th> <th>List Price</th> <th>Size</th> <th>Weight</th> <th>Sell Start Date</th> <th>Sell End Date</th> <th>Discontinued Date </th> </tr> <% foreach (var item in Model) { %> <tr> <td> <%= Html.DisplayFor(c => item.ProductID) %> </td> <td> <%= Html.DisplayFor(c => item.Name)%> </td> <td> <%= Html.DisplayFor(c => item.Color) %></td> <td> <%= Html.DisplayFor(c => item.StandardCost)%> </td> <td> <%= Html.DisplayFor(c => item.ListPrice)%> </td> <td> <%= Html.DisplayFor(c => item.Size) %></td> <td> <%= Html.DisplayFor(c => item.Weight) %> </td> <td> <%= Html.DisplayFor(c => item.SellStartDate, "Date") %> </td> <td> <%= Html.DisplayFor(c => item.SellEndDate) %></td> <td> <%= Html.DisplayFor(c => item.DiscontinuedDate)%></td> </tr> <% } %> </table> </asp:Content>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"> MVC Product Index Sample </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <h2>Index using Html.DisplayFor</h2> <table> <tr> <th> Product ID </th> <th>Name</th> <th>Color</th> <th>Std. Cost</th> <th>List Price</th> <th>Size</th> <th>Weight</th> <th>Sell Start Date </th> <th>Sell End Date</th> <th>Discontinued Date </th> </tr> <% For Each item In Model%> <tr> <td> <%=Html.DisplayFor(Function(c) item.ProductID)%> </td> <td> <%= Html.DisplayFor(Function(c) item.Name)%> </td> <td> <%= Html.DisplayFor(Function(c) item.Color) %></td> <td> <%= Html.DisplayFor(Function(c) item.StandardCost)%> </td> <td> <%= Html.DisplayFor(Function(c) item.ListPrice)%> </td> <td> <%= Html.DisplayFor(Function(c) item.Size) %></td> <td> <%= Html.DisplayFor(Function(c) item.Weight) %> </td> <td> <%=Html.DisplayFor(Function(c) item.SellStartDate, _ "Date")%> </td> <td> <%= Html.DisplayFor(Function(c) item.SellEndDate) %></td> <td> <%= Html.DisplayFor(Function(c) item.DiscontinuedDate)%></td> </tr> <% Next%> </table> </asp:Content>
Note
You must use the correct namespace in the Inherits attribute of the page directive. The strongly typed Products class must be of type IEnumerable.
Press CTRL+F5 to run the application.
A table of product data is displayed. The three DateTime fields (Sell Start Date, Sell End Date, and Discontinued Date) display the date and time.
Creating a Date Template
In this step you will create a date template that will render DateTime data using only the date portion (the time will not be displayed).
To add a date template
In the Views\Home folder, create a DisplayTemplates folder.
In the Views\Shared folder, create another DisplayTemplates folder.
The display templates in the Views\Shared\DisplayTemplates folder will be used by all controllers. The display templates in the Views\Home\DisplayTemplates folder will be used by the home controller. Display templates that will be used by more than one controller should be placed in the Views\Shared\DisplayTemplates folder. (If a template with the same name appears in both folders, the template in the Views\Home\DisplayTemplates folder will be used.)
In Solution Explorer, expand the Views folder, expand the Shared folder, and then right-click the Views\Shared\DisplayTemplates folder.
Click Add, and then click View.
The Add View dialog box is displayed.
In the View name box, type Date.
Select the Create a partial view (.ascx) check box. Make sure that the Create strongly-typed view check box is not selected.
Click Add.
The Views\Shared\DisplayTemplates\Date.ascx control is created.
Add markup that formats the property as a date (without the time).
The following example shows the complete Date.ascx control. The String.Format method is used to format the property value.
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %> <%= Html.Encode(String.Format("{0:d}", Model)) %>
<%@ Control Language="VB" Inherits="System.Web.Mvc.ViewUserControl" %> <%= Html.Encode([String].Format("{0:d}", Model)) %>
Press CTRL+F5 to run the application.
The SellStartDate column now displays a date without the time. When you run the application, the MVC framework displays the Index.aspx page as the default view. In the Index.aspx page, the following line uses the overload of the Html.DisplayFor extension method to specify that the Date.aspx control should be used to render the property. By modifying the Date.aspx control, you have customized how a date value is displayed.
<td> <%= Html.DisplayFor(Product=> item.SellStartDate, "Date") %> </td>
<td> <%=Html.DisplayFor(Function(c) item.SellStartDate, _ "Date")%> </td>
Using DataAnnotations Attributes to Specify a How Data is Rendered
In this step you will apply add attributes to the data model partial class in order to specify a template to render the data. This will cause the ASP.NET MVC template to display dates by using the template helper that you just created.
To use DataAnnotations attributes to specify how data is rendered
Add a class to your project to contain the partial class definitions. For more information, see How to: Validate Model Data Using DataAnnotations Attributes.
Add a reference to System.ComponentModel.DataAnnotations.dll to the project.
Replace the contents of the partial class file that you just created with the following code:
using System.ComponentModel.DataAnnotations; namespace MvcTmpHlprs { [MetadataType(typeof(ProductMD))] public partial class Product { public class ProductMD { public object SellStartDate { get; set; } [UIHint("rbDate")] public object SellEndDate { get; set; } [DataType(DataType.Date)] public object DiscontinuedDate { get; set; } [ScaffoldColumn(false)] public object ModifiedDate { get; set; } [ScaffoldColumn(false)] public object rowguid { get; set; } [ScaffoldColumn(false)] public object ThumbnailPhotoFileName { get; set; } } } }
Imports System.ComponentModel.DataAnnotations <MetadataType(GetType(ProductMD))> _ Partial Public Class Product End Class Public Class ProductMD Private _SellStartDate As Object Public Property SellStartDate() As Object Get Return _SellStartDate End Get Set(ByVal value As Object) _SellStartDate = value End Set End Property Private _SellEndDate As Object <UIHint("rbDate")> _ Public Property SellEndDate() As Object Get Return _SellEndDate End Get Set(ByVal value As Object) _SellEndDate = value End Set End Property Private _DiscontinuedDate As Object <DataType(DataType.Date)> _ Public Property DiscontinuedDate() As Object Get Return _DiscontinuedDate End Get Set(ByVal value As Object) _DiscontinuedDate = value End Set End Property Private _ModifiedDate As Object <ScaffoldColumn(False)> _ Public Property ModifiedDate() As Object Get Return _ModifiedDate End Get Set(ByVal value As Object) _ModifiedDate = value End Set End Property Private _rowguid As Object <ScaffoldColumn(False)> _ Public Property rowguid() As Object Get Return _rowguid End Get Set(ByVal value As Object) _rowguid = value End Set End Property Private _ThumbnailPhotoFileName As Object <ScaffoldColumn(False)> _ Public Property ThumbnailPhotoFileName() As Object Get Return _ThumbnailPhotoFileName End Get Set(ByVal value As Object) _ThumbnailPhotoFileName = value End Set End Property End Class
Save the class.
Press CTRL+F5 to run the application.
The Discontinued Date column now displays a date without the time. The DataTypeAttribute attribute in the Product partial class uses the DataType enumeration to specify that the DiscontinuedDate property is typed as a date. When a property is annotated with data-type information, the MVC framework searches for a template with the same name.
Using UIHint to Specify a Template to Render Data
In this step you will create a date template that displays DateTime data as a bold red string. You will apply the UIHintAttribute attribute to the SellEndDate property in order to specify that the data should be rendered using a date control that includes markup to display the date in bold red text. The date control in this step will be created in the Views\Home\DisplayTemplates folder and will apply to only the Home controller. The Views\Shared\DisplayTemplates\Date.ascx control is shared by all controllers.
In the preceding section of the walkthrough, you used the DataTypeAttribute attribute to specify a template to use to render a data type. The UIHintAttribute attribute has the advantage of letting you pass an arbitrary number of name/value pairs in order to specify additional information for the template. For more information about how to write a custom UIHintAttribute class, see the entry Setting font attributes with UIHint in your Entity Partial Class on Rick Anderson's blog.
To use UIHint to specify a template to render data
Copy the Views\Shared\DisplayTemplates\Date.ascx control to the Views\Home\DisplayTemplates folder.
Rename the Date.ascx file to rbDate.ascx.
Open the Views\Home\DisplayTemplates\rbDate.ascx file in the editor.
Change the markup to render the property in red bold text.
<span style="font-weight:bold;color:red;"> <%= Html.Encode(String.Format("{0:d}", Model)) %> </span>
<span style="font-weight:bold;color:red;"> <%= Html.Encode([String].Format("{0:d}", Model)) %> </span>
Press CTRL+F5 to run the application.
The SellEndDate column now displays the date in red bold text. The SellEndDate property is annotated with the UIHintAttribute attribute, which specifies that the rbDate control should be used to render the property.
Next Steps
This walkthrough has provided you with an overview of using templated helpers to display data in an MVC application.
The sample project that you can download includes an edit page that uses the Html.EditorFor templated helper. This templated helper displays edit controls, such a text box, that let users enter or change property values. The Html.EditorFor templated helper also renders validation logic that enforces constraints that are built into the data model or that you can add as System.ComponentModel.DataAnnotations attributes to a partial class that is associated with the data model. For example, the following illustration shows validation errors that are displayed when the System.ComponentModel.DataAnnotations constraints applied in the partial class are violated.
For more information about how to use templated helpers, see the entry Using the New MVC 2 Templated Helpers on Rick Anderson's blog.
See Also
Tasks
How to: Validate Model Data Using DataAnnotations Attributes