In this tip, you learn how to create and use templates in the MVC framework that you can use to display database data. I show you how to create a new MVC Helper method named the RenderTemplate() method.
While I was back home in California during the 4th of July weekend, I was talking to my smarter, older brother about the differences among building web applications with ASP.NET Web Forms, ASP.NET MVC, and Ruby on Rails. I was bemoaning the fact that I really missed using controls when building an ASP.NET MVC application. In particular, I was complaining that I missed the clean separation between HTML and UI logic provided by the templates that you get with an ASP.NET Web Forms control. A Repeater control is really not the same as a for…next loop.
My brother told me something surprising. He said “Templates, Ruby on Rails has templates, they are called partials.” At first, I didn’t understand. I thought partials in the Ruby on Rails world were more or less the same as user controls in the ASP.NET MVC world. However, my brother explained that when you render a partial in a Ruby on Rails application, you can pass a collection of items. Each item in the collection is rendered with the partial.
Cool. You can use the same approach to create templates in an ASP.NET MVC application. Create a new helper method that accepts an IEnumerable and a path to a user control. The helper method can use the user control as a template for each item from the IEnumerable. Listing 1 contains the code for a new helper method named the RenderTemplate() method.
Listing 1 – TemplateExtensions.vb (VB.NET)
Imports System
Imports System.Text
Imports System.Collections
Imports System.Web.Mvc
Public Module TemplateExtensions
<System.Runtime.CompilerServices.Extension()> _
Public Function RenderTemplate(ByVal helper As HtmlHelper, ByVal items As IEnumerable, ByVal virtualPath As String) As String
Dim sb = New StringBuilder()
For Each item As Object In items
sb.Append(helper.RenderUserControl(virtualPath, item))
Next item
Return sb.ToString()
End Function
End Module
Listing 1 – TemplateExtensions.cs (C#)
using System;
using System.Text;
using System.Collections;
using System.Web.Mvc;
namespace Helpers
{
public static class TemplateExtensions
{
public static string RenderTemplate(this HtmlHelper helper, IEnumerable items, string virtualPath)
{
var sb = new StringBuilder();
foreach (object item in items)
{
sb.Append( helper.RenderUserControl(virtualPath, item));
}
return sb.ToString();
}
}
}
Imagine, for example, that you want to display a list of movies. You can use the HomeController in Listing 2 to return a collection of Movie entities. The Index() action executes a LINQ to SQL query and passes the query results to the Index view.
Listing 2 – HomeController.vb (VB.NET)
Public Class HomeController
Inherits System.Web.Mvc.Controller
Private _dataContext As New MovieDataContext()
Public Function Index() As ActionResult
Dim movies = _dataContext.Movies
Return View(movies)
End Function
End Class
Listing 2 – HomeController.cs (C#)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Tip14.Models;
namespace Tip14.Controllers
{
public class HomeController : Controller
{
private MovieDataContext _dataContext = new MovieDataContext();
public ActionResult Index()
{
var movies = _dataContext.Movies;
return View(movies);
}
}
}
The view in Listing 3 simply calls the RenderTemplate() method passing the method the ViewData.Model and the path to an MVC user control that contains the template for each movie.
Listing 3 — Index.aspx (VB.NET)
<%@ Page Language="VB" AutoEventWireup="false" CodeBehind="Index.aspx.vb" Inherits="Tip14.Index" %>
<%@ Import Namespace="Tip14" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title></title>
</head>
<body>
<div>
<%= Html.RenderTemplate(ViewData.Model, "~/Views/Home/MovieTemplate.ascx") %>
</div>
</body>
</html>
Listing 3 — Index.aspx (C#)
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Index.aspx.cs" Inherits="Tip14.Views.Home.Index" %>
<%@ Import Namespace="Helpers" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title></title>
</head>
<body>
<div>
<%= Html.RenderTemplate(ViewData.Model, "~/Views/Home/MovieTemplate.ascx") %>
</div>
</body>
</html>
The MovieTemplate.ascx MVC User Control is strongly typed. The code-behind file for this user control is contained in Listing 4. Notice that the User Control is strongly typed to represent a Movie entity.
Listing 4 – MovieTemplate.ascx.vb (VB.NET)
Public Partial Class MovieTemplate
Inherits System.Web.Mvc.ViewUserControl(Of Movie)
End Class
Listing 4 – MovieTemplate.ascx.cs (C#)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Tip14.Models;
namespace Tip14.Views.Home
{
public partial class MovieTemplate : System.Web.Mvc.ViewUserControl<Movie>
{
}
}
Finally, the view part of the MVC user control is contained in Listing 5. Notice that you can use expressions like ViewData.Model.Title and ViewData.Model.Director to display the movie title and movie director. These expressions work because you are using a strongly typed MVC User Control that represents a movie entity.
Listing 5 – MovieTemplate.ascx (VB.NET)
<%@ Control Language="VB" AutoEventWireup="false" CodeBehind="MovieTemplate.ascx.vb" Inherits="Tip14.MovieTemplate" %>
<b><%= ViewData.Model.Title %></b>
<br />
Director: <%= ViewData.Model.Director %>
<hr />
Listing 5 – MovieTemplate.ascx (C#)
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="MovieTemplate.ascx.cs" Inherits="Tip14.Views.Home.MovieTemplate" %>
<b><%= ViewData.Model.Title %></b>
<br />
Director: <%= ViewData.Model.Director %>
<hr />
When you request the Index view, you get the page shown in Figure 1. Notice that the MVC User Control has been rendered for each movie.
Figure 1 – The Movies records rendered with a template
Summary
In this tip, I explained how you can create and use templates in an ASP.NET MVC application. I’ve demonstrated how you can create a template by creating an MVC User Control and use the template to control how a set of database records is rendered. Now, there is no reason to ever use a Repeater control in an ASP.NET MVC application.
You can download the TemplateExtensions (which includes the RenderTemplate() method) by clicking the following link:

This already exists as Html.RenderComponent and Html.RenderUserControl I believe.
Ah, nevermind, you were just wanting to get rid of the lines for a foreach loop.
@Malkir — The RenderComponent and RenderUserControl methods don’t take a collection of items. The RenderTemplate() method described in this tip accepts a collection of items (such as database records) and renders each item using the template.
@Stephen, I think malkir was referring to the code that already exists in the “RenderUserControl” and accompanying methods (extensions on HtmlHelper). It means you’re repeating a lot of stuff that’s already there (the methods are even named the same “InstantiateControl”, “DoRendering”, “RenderPage” etc.). Why not just make a single extension method:
public static string RenderTemplate(this HtmlHelper helper, IEnumerable items, string virtualPath)
{ var sb = new StringBuilder();
foreach (object item in items)
{ sb.Append( helper.RenderUserControl(virtualPath, item);
}
return sb.ToString();
}
and forget about the rest (no need for that).
Cheers,
Mio
This is a nice one, althou I had a deja vu feeling.
I digged up Dynamic Data sources to see how they are instantiating Templates since DD is based on templates.
The instantiation is similar to yours, but maybe more ASP.Net “friendly”:
(IFieldTemplate) BuildManager.CreateInstanceFromVirtualPath(virtualPath, typeof(IFieldTemplate));
They use BuildManager straight instead of Activator.CreateInstance.
Upon digging the sources I thought it further (beware I’m new to MVC bits, but not the concept
). Why can’t we have standard “field” templates in a designated directory within an MVC app, which ones can be used by various views as needed and can be created on demand by a ITemplateFactory class.
Thanks,
Attila
@Mio – Really good point. I removed everything but the loop and a call to RenderUserControl(). Thanks!
Stephen, it would be nice if you could add the call that needs to be done from the ViewPage…
@Simone — I updated the tip so that it includes the ViewPage – thanks for pointing that out!
Hello Stephen,
I’m using this helper method in my MVC application. However, in preview 5 it doesn’t work anymore, because a text writer is used to render partial views aka usercontrols. Any idea how to fix this?
Thanx,
Henk
i use this:
public static void RenderTemplate(this HtmlHelper helper, IEnumerable items, string templateName)
{
foreach (object item in items)
{
helper.RenderPartial(templateName, item);
}
}
Template should be placed in shared directory for use with all controllers.
How can we render UserControl using ASP.NET MVC Framework Preview 5?
Would you please post the above workaround using MVC Preview 5? We are in trouble while rendering UserControl by Html.RenderPartial().
Does not work on RC.
The Html.RenderPartial() returns void.
Is there any workaround?
Actually I want to be able to render PartialView within my Htmlhelper extension.
Thanks
O
Typical dumb M$ example. What about demonstrating some real world application? Let’s say we throw a strongly typed model approach and some posting data back in the mix? What about that huh? I bet it will backfire and get stuck in your pooper forever! Good luck asking that to your older, smarter brother. You won’t even be able to post a descent solution adding your grandfather and Bill Gates into your brain-pool. ASP.NET MVC is code smell on its own!
Where “must” is my name and PortalMain is my resource file name.
I m not getting any error but message is also not coming.
Actually I want to be able to render PartialView within my Htmlhelper extension.
very nice post thanks!!!
interesting post
thanks!!! keep working like this
g v It looks like DataContextExtensions.cs line 45 of the Save method should pass the primaryKeyName through to Update.
Any idea how to make this work without RenderUserControl … cause it looks outdated ….
logo design | Multimedia Design | graphic design
selam hi This sounds fascinating sıcak sohbet I’m going to read that tracing articlekısa aşk şiirleri when I have a moment.
Wow. erotik film izle is
şifalı bitkiler zayıflama de
çet sohbet fer
netlog ger
müzik dinle err
şarkı dinle
cüneyt arkın filmleri kk
isyan sözleri fer
hikayeler er
islami çet ff
adet sancısına ne iyi gelir hh
escort bayanlar der
bedava chat dd
chat odaları der
liseli kızlar derf
kızlarla sohbet fder
kızlarla chat
sohbet errBNMÖÇ
As the users of HD Camcorders like Sony, Canon, Panasonic, this HD Video Converter is necessary to help us convert hd Video easily and quickly. The Converter for HD provides several practical editing functions to help you achieve ideal output effect. Trim function is to cut videos into clips which you can just convert and transfer to your player. Crop function helps you remove black bars around the movie. You could use Effect function to adjust video brightness, contrast, saturation and more parameters. More powerful and considerate functions are waiting for you to explore.MKV Converter l FLV Converter l DVD Ripper ..