asp.net
ASP.NET Page Templates
By Mike Borromeo
What?
A website templating system is a small collection of page templates that contain and control any non page specific (redundant) code and HTML.
Who?
This applies to anyone looking for a flexible method for implementing page templates in ASP.NET. Readers new to templates will find them invaluable. Readers trained in the template arts but looking for a better implementation already know the value of templates and hopefully will find the methods described here useful for their specific situation (if not I’d like to hear from you, if so I’d also like to hear from you).
Why?
In a one page website page templates would be of little use, but when you start building 5+ page sites life starts to get difficult sans templates. A well designed templating system (and I emphasize well designed) has the following benefits to name a few: more efficient and easier development through the elimination of redundant blocks of code, easier integration of designers and programmer through separation of HTML and server-side script, and easier development of consistent user interface through forced reuse of UI code.
Where & When?
Me personally, I would use templates in any site that has more than one page. And really there’s no reason not to, so I suppose these ideas apply everywhere and all the time.
How?
Ah How… the fun part. Here we’ll take a look at an example of a template and a page that employs the template. The entire collection of files you will need along with a more advanced example is available for download.
So you ask, is it difficult to understand or implement? In a word, no. In two words, heck no. If you can count to ten you can use templates. Ok, maybe that’s a bit of an overstatement but nevertheless. You’ll be templating, as it were, in no time. First let’s take a look at a simple example of a page that uses a template (a.k.a. a templated page).
<%@ Page Language="c#" Codebehind="Default.aspx.cs" Inherits="Example._Default" %><%@ Register TagPrefix="example" TagName="template" Src="/Includes/Template.ascx"%><example:template title=”Example of Page Templating” id="template" runat="server" > <body> Here lies the page content. </body></example:template>
This is about as simple as a templated page gets. You should have a vague idea what everything here means but I’ll explain everything starting at the top. The Page directive isn’t specific to this project so we won’t detail it’s meaning. The register directive simply tells ASP.NET that we’re going to be using the template located as /Includes/Template.ascx. What’s that you say? User control? Why yes it is. The thinking in making a template a user control is this: you write C# in a C# editor and HTML in an HTML editor. Obvious? Maybe. But I’ve seen templates proposed that are implemented as a custom control (written in a code editor, not an HTML editor). It’s just easier to write HTML in the VS .NET HTML editor just as it’s easier to write C# in the C# .NET editor and with user controls we’re allowed this luxury. Intellisense anyone? You could say sure, you can design the template in the HTML editor the convert it to C# rendered output but then enters the question of maintainability. No designer I know wants to go in an edit a C# file and recompile the bloody web application. Ok, now I’m hearing something about speed concerns? Well granted compiled code custom control code is faster than the equivalent user control code but it is said that caching erases all your sins or was it cache is king, or maybe cache and thou shall be saved. Whichever the case, by using simple native caching techniques in ASP.NET you can eliminate many of the slowdowns caused by dynamic pages. However, in the case where a page is generated uniquely for each view and also depending on the site load, speed may be the prevailing factor for which custom control page templates may be the answer. User control versus custom control concerns aside, let’s move on to the beginning of the template tags “<example:template>”. I should mention now that this example template was designed with simplicity in mind and customization should, nay, must be performed by you the reader in order to make this system truly useful. What do I mean by customization? Well, take the title attribute for example. You don’t have to be a Burt Muston to realize the title attribute in the template tag corresponds to the title tag in the resulting HTML. Using our imagination picture something else in addition to the title attribute, perhaps the path to a cascading style sheet, or maybe the keywords for the page that will end up in the meta tag. Go nuts with it. Use your imagination. I should say of course adding the type of customizations I just mentioned are as easy as proverbial pie and we’ll go over just such a change later. But moving on we see the body tag. Body in this case is where the main content for the page goes. Note: don’t confuse the body tag here with the body tag in “traditional” pages. In previous version of this system the body tag was called main until I realized that Intellisense is fully functional when inside a body tag. At any rate, whatever you put in your body tags will show up in the template where you specify. In the spirit of customizations it should be said that having a body tag is simply a function of the needs of the page. So for example if each page needs a sidebar for navigation or whatnot you can add a sidebar tag that resides on the same level as the body tag in the templated page and likewise can put the contents of the sidebar where ever appropriate in the template. Again, go nuts and use your imagination… more examples to come.
Ok, so I’ll bet you’re saying Mike, I can handle this no problem. Good, because we’re moving on to the template itself. I’ll just put the entire template file here and we’ll sort it all out afterwards.
<%@ Control Language="c#" Codebehind="Template.ascx.cs" Inherits="HallofFame.Includes.Template" %><html> <head> <title> <%=this.Title%> </title> <script runat="server"> /// <summary> /// Insert the body the user provided in our body placeholder. /// </summary> protected override void CreateChildControls() { // insert the main content body if available if( null != Body ) Body.InstantiateIn( bodycontainer ); } </script> </head> <body> <table width="100%" height="100%" border="1"> <tr> <td colspan="2" height="80"><font size="1">Header</font></td> </tr> <tr> <td width="100%" height="100%"></td> <td> <asp:placeholder id="bodycontainer" runat="server" /> </td> </tr> <tr> <td colspan="2" height="20"><font size="1">Footer</font></td> </tr> </table> </body></html>
The attentive reader will notice that there are only three things special to this page compared to any ordinary ASP.NET page. First, the <%=this.Title%> which lies naturally in the title tag (and I’ll explain just how all this works later). Second, the block of server code that contains the function CreateChildControls which basically takes the body content supplied by the templated page and drops it right where the asp:placeholder is waiting. Which brings us to the third noteworthy bit of code and that’s the asp:placeholder which like we just mentioned is where the body content goes.
How does all this work? How does the title and body content get transferred to the Template object that the user control inherits from? To answer this lets take peek at the code behind and unmask the wizard.
using System;using System.Data;using System.Drawing;using System.Web;using System.Web.UI;using System.Web.UI.WebControls;using System.Web.UI.HtmlControls;namespace HallofFame.Includes{ /// <summary> /// The main template for this website. /// </summary> [ParseChildren(true)] public abstract class Template : UserControl, INamingContainer { /// <summary> /// The main content template. /// </summary> private ITemplate main; /// <summary> /// The name of the page. /// </summary> private string title; /// <summary> /// The main content template. /// </summary> public ITemplate Body { get { return this.main; } set { this.main = value; } } /// <summary> /// The name of the page. /// </summary> public string Title { get { return this.title; } set { this.title = value; } } Web Form Designer generated code }}
Looking at this code we see a couple of familiar faces, namely the body and title properties. And in the world of user controls this is how you expose attributes. So remembering back to the example page we introduced near the beginning which looked something like this
<%@ Page Language="c#" Codebehind="Default.aspx.cs" Inherits="Example._Default" %><%@ Register TagPrefix="example" TagName="template" Src="/Template.ascx"%><example:template title=”Example of Page Templating” id="template" runat="server" > <body> Here lies the page content. </body></example:template>
We see the title is set as a template attribute and the body is set as a sub-tag. And now referring back to the code behind the template the body is of type ITemplate and the title is of type string bringing up some good questions. Do attributes have to be strings? No, they can be integers any other type ASP.NET can parse from a string. And what is the ITemplate type all about? It tells ASP.NET that the body property will contain children objects. What is ParseChildren and why is it true? The ParseChildren C# attribute tells ASP.NET that this class will be a container for child controls and those should be parsed as opposed to placing everything between the start and end tags in a LiteralControl object. How can I add more sections similar to the body section? Simply and easily… by just declaring a member variable of the type ITemplate and exposing it via a property. Basically copy and paste the body blocks and rename accordingly. Then in the Template.ascx file place an asp:placeholder and in the CreateChildControls function instantiate the new section in the asp:placeholder. Pretty easy, no?
Conclusions
During the writing of this article I researched several other methods of doing page templates not only in ASP.NET but also PHP and ASP. Both PHP and ASP have a few that have a large following and they really boil down to the same features similar to those mentioned above. But ASP.NET allows page templates to be implemented so they appear to be a native looking extension integrating seamlessly with VS .NET.
Available for download are all the files we discussed here and another more complicated example outlining how to use server controls inside the templated page body. Bear in mind however that these examples are very simplified to make for easier digestion. They can and should be expanded and improved upon. If you noticed any errors or misinformation please email me at mborromeo@phosl.com. If you have a better or improved upon method of doing page templates in ASP.NET I would be hearing about it. Thanks and come again.
Download ASPTemplates.zip
Tools Used
Visual Studio .NET and Windows 2000 Server running IIS 5.0 with ASP.NET