|
Home Articles We've Written Web Templates
Creating a Visual Web Page Template
By Lynn Torkelson for
smartisans.com
Copyright 2002 SoftMedia Artisans, Inc.
Published September 2002
Web developers moving to ASP.NET face the problem of creating a Web page
template to enforce a consistent look and feel across a Web site. When your
organization or customer wants to tweak the appearance of a site, you don't
want to go through large numbers of Web pages to make identical changes. You
want to change a single template used by all of your Web pages.
With the inheritance capability built into the .NET languages, you have
several choices available to you for creating such a template. At the end of
this article, you'll find links to other articles that explain different Web
template approaches. Each approach has its advantages and disadvantages, and
you'll want to know the options available to you and your team. Compare them
all and select the approach that makes sense for your Web application.
The advantage of the technique I present in this article is its simplicity.
You create your visual Web page template as a single ASPX in the Visual Studio
.NET designer. Then you route each incoming page request for handling by the
template, which displays the content of the specific page requested.
Except for the source of the content, the visual Web page template described
in this article resembles the templates used for database-driven Web sites.
This technique avoids the need to hard-code lots of HTML. (Check out the amount
of hard-coded HTML required by other popular approaches.)
The VbTemplate demonstration project (view demo in new
browser window) illustrates the technique that I explain in this article.
Take a look at the different pages in the demo, and then keep the demonstration
window open to experiment with while you read the explanation of how this
template works. For this demonstration I used Visual Basic .NET, but you can
use the .NET language of your choice.
Designing the Template
All five pages in the VbTemplate demonstration share a single ASPX file,
index.aspx. The design of index.aspx (see Figure 1) controls the appearance of
all pages.
Figure 1. The index.aspx file is the only ASPX file in the
VbTemplate demonstration project.

By using Visual Studio .NET, you gain the ability to drag and drop controls on
the designer and you get a visual impression of how the pages in the Web site
will look. For this demo, I dropped the default Styles.css file on the designer
to give the template some style, then added CSS styles—only three, as it turned
out—when I needed them.
You can see the CSS styles I added (see Listing 1) in the Visual Studio
screenshot in Figure 1. The Selected style applies to the bold font labels in
the Pages cell. When a page is rendered, a bold font label names the page to be
displayed in the browser, and all of the other pages show up as links. As I'll
demonstrate shortly, the code behind index.aspx determines which alternative in
the page list is visible, depending upon which page the visitor has requested.
Listing 1. CSS classes added to Styles.css for the VbTemplate
demo.
.Selected
{
font-weight: bold;
color: #003366;
}
.Time
{
color: #003366;
}
.Copyright
{
font-size: .7em;
color: #003366;
text-align: center;
}
The Time style applies only to the lblTime label control in the top cell of
the template. I added the time stamp to demonstrate that output caching works
correctly using this visual Web page template technique. The Copyright style
applies to copyright notice on the bottom line in Figure 1.
Because index.aspx acts as a template for all of the Web pages in the site,
its content cannot be determined until the visitor selects a particular page.
Therefore I added the PlaceHolder control plcContent to hold the
actual content once known. In the VbTemplate demo, the content for each page
resides in a separate ASCX user control file. (At the end of this article, I
discuss a variant of this technique that does not use ASCX files for content.)
Looking at the Template Structure
As the only ASPX file in the VbTemplate demo, index.aspx naturally receives
the startup page designation. You can see at the top of Listing 2, however,
that the Page directive specifies VbTemplate.PageBase as the base class for the
page instead of Visual Studio's default value of VbTemplate.index. I reserved
the latter class name for the user control that contains the content for
index.aspx.
Listing 2. The HTML listing for index.aspx.
<%@ Page Language="vb" AutoEventWireup="false"
Codebehind="index.aspx.vb"
Inherits="VbTemplate.PageBase" %>
<%@ OutputCache Duration="1000" Location="Server" VaryByParam="*"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>
<asp:literal id="litTitle" runat="server">Template</asp:literal>
</title>
<meta name="description" content="Visual Web Template Demo">
<meta name="keywords" content="ASP.NET, VB.NET, Visual, Template">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta content="Microsoft Visual Studio.NET 7.0" name="GENERATOR">
<meta content="Visual Basic 7.0" name="CODE_LANGUAGE">
<meta content="JavaScript" name="vs_defaultClientScript">
<meta content="http://schemas.microsoft.com/intellisense/ie5"
name="vs_targetSchema">
<link href="Styles.css" type="text/css" rel="stylesheet">
</head>
<body>
<form id="Form1" method="post" runat="server">
<table id="tblMain" cellspacing="1" cellpadding="1"
width="100%" border="0">
<tr>
<td align="middle" colspan="2">
<h1>Visual Web Page Template</h1>
<p><asp:label id="lblTime" runat="server" cssclass="Time">
11:35:10 AM</asp:label></p>
<hr width="100%">
</td>
</tr>
<tr>
<td valign="top" width="25%">
<h2>Pages</h2>
<asp:label id="lbl_index" runat="server"
visible="False" cssclass="Selected">Home
</asp:label>
<asp:hyperlink id="lnk_index" runat="server"
navigateurl="index.aspx">Home
</asp:hyperlink><br>
<asp:label id="lbl_static_text" runat="server"
visible="False" cssclass="Selected">Static Text
</asp:label>
<asp:hyperlink id="lnk_static_text" runat="server"
navigateurl="static_text.aspx">Static Text
</asp:hyperlink><br>
<asp:label id="lbl_dynamic_text" runat="server"
visible="False" cssclass="Selected">Dynamic Text
</asp:label>
<asp:hyperlink id="lnk_dynamic_text" runat="server"
navigateurl="dynamic_text.aspx">Dynamic Text
</asp:hyperlink><br>
<asp:label id="lbl_button_click" runat="server"
visible="False" cssclass="Selected">Button Click
</asp:label>
<asp:hyperlink id="lnk_button_click" runat="server"
navigateurl="button_click.aspx">Button Click
</asp:hyperlink><br>
<asp:label id="lbl_text_input" runat="server"
visible="False" cssclass="Selected">Text Input
</asp:label>
<asp:hyperlink id="lnk_text_input" runat="server"
navigateurl="text_input.aspx">Text Input
</asp:hyperlink>
</td>
<td valign="top" width="75%">
<h2>Content</h2>
<asp:placeholder id="plcContent" runat="server">
</asp:placeholder>
</td>
</tr>
<tr>
<td align="middle" colspan="2">
<hr width="100%">
<div class="Copyright">
Copyright
<asp:label id="lblYears" runat="server">© 2001 - 2002
</asp:label>
SoftMedia Artisans, Inc. All Rights Reserved.
</div>
</td>
</tr>
</table>
</form>
</body>
</html>
The OutputCache directive in Listing 2 specifies server caching as the default
condition for all pages generated by this template. If you check the time stamp
on the Home page, then return to the Home page after viewing other pages,
you'll see that you receive a cached version of the Home page on your second
request. In a later example, I show how to turn off output caching for
individual pages where it is not appropriate.
Depending upon your application's requirements, you might need a more
sophisticated OutputCache directive or you might need to create user controls
for finer control over caching. (In Chapter 10 of our book
Programming the Web with Visual Basic .NET, we explain, with code
examples, the output caching options available.)
Designers commonly use HTML tables to provide a liquid design structure for
their Web pages. When you resize the browser window, the text flows within the
table to accomodate its new size. As you can see in Listing 2, I've adopted
that strategy for this demo.
In the head section of the HTML, the title element contains
the following line:
<asp:literal id="litTitle" runat="server">Template</asp:literal>
Because the title will change depending upon the page actually requested, I
inserted a Literal control to receive the appropriate title programmatically.
In the Pages cell, all of the links start with Visible=True (the
default) and all of the corresponding Selected labels start with
Visible=False. Once the page requested is known, the template code reverses the
values of the Visible properties corresponding to that page. Of course the code
cannot do that unless it knows what page the visitor requested. Let's take a
look at how that's done.
Routing an Incoming Request to the Template
The Global.asax.vb file contains handlers for events that fire before and
after page processing. The event to use for routing an incoming request to the
template is Application.BeginRequest. Listing 3 contains the code that does
this routing in the VbTemplate demo.
Listing 3. The handler for the Application.BeginRequest event
in the global.asax.vb file.
Sub Application_BeginRequest( _
ByVal sender As Object, ByVal e As EventArgs)
' Fires at the beginning of each request
Dim sPath As String = Request.Path.ToLower
Dim iStart As Integer = sPath.LastIndexOf("/") + 1
Dim sPage As String = sPath.Substring( _
iStart, sPath.IndexOf(".aspx") - iStart)
If Not sPage = "index" Then
Context.RewritePath(sPath.Substring(0, iStart) _
& "index.aspx?page=" & sPage)
End If
End Sub
The code in Listing 3 extracts the name of the page requested from the
Request.Path property. If it is not the index page, the code uses the
Context.RewritePath method to route the request to the template, appending a
query string with the name of the page actually requested. If the request is
for the index page, the code does not reroute it.
Note that on a postback, the Request.Path will request the index page and will
be accompanied by a query string identifying the page originally requested. In
the next section we look at how the template code uses the query string,
however it originated, to determine the content of the response.
Handling the Incoming Request
As I mentioned earlier, the code behind the template bears the class name
PageBase even though it resides in the index.aspx.vb file. The template code
for this demo, shown in Listing 4, does its work in the handlers for the
Page.Load and Page.PreRender events.
Listing 4. The PageBase code in index.aspx.vb.
Option Strict On
Imports System.Web.UI.WebControls
Public Class PageBase
Inherits System.Web.UI.Page
Protected WithEvents litTitle As Literal
Protected WithEvents lblTime As Label
Protected WithEvents lbl_index As Label
Protected WithEvents lnk_index As HyperLink
Protected WithEvents lbl_static_text As Label
Protected WithEvents lnk_static_text As HyperLink
Protected WithEvents lbl_dynamic_text As Label
Protected WithEvents lnk_dynamic_text As HyperLink
Protected WithEvents lbl_button_click As Label
Protected WithEvents lnk_button_click As HyperLink
Protected WithEvents lbl_text_input As Label
Protected WithEvents lnk_text_input As HyperLink
Protected WithEvents lblYears As Label
Protected WithEvents plcContent As PlaceHolder
#Region " Web Form Designer Generated Code "
'This call is required by the Web Form Designer.
<System.Diagnostics.DebuggerStepThrough()> _
Private Sub InitializeComponent()
End Sub
Private Sub Page_Init(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Init
'CODEGEN: This method call is required
' by the Web Form Designer
'Do not modify it using the code editor.
InitializeComponent()
End Sub
#End Region
Private _sPage As String
Private _oContent As ControlBase
Private Sub Page_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles MyBase.Load
'Determine the page requested
_sPage = Request.QueryString("page")
If _sPage Is Nothing Then _sPage = "index"
'Use time stamp to show caching
Me.lblTime.Text = Now.ToLongTimeString
'Set copyright years
Me.lblYears.Text = "© 2001 - " & Year(Today).ToString
Try
'Add content from user control
_oContent = CType( _
Page.LoadControl(_sPage & ".ascx"), ControlBase)
Me.plcContent.Controls.Add(_oContent)
'Show the page selected in bold text
Me.ShowSelection(_sPage)
Catch
'Unsupported page request
Me.plcContent.Controls.Add(New LiteralControl( _
"Please select a link from the list."))
End Try
End Sub
Private Sub Page_PreRender(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles MyBase.PreRender
If (Not _oContent Is Nothing) Then
'Page request is supported
If (_oContent.Title <> String.Empty) Then
'Get page title from user control
Me.litTitle.Text = _oContent.Title
Else
'Get page title from link text
Dim oLink As HyperLink = _
CType(Me.FindControl("lnk_" & _sPage), HyperLink)
Me.litTitle.Text = oLink.Text
End If
End If
End Sub
Private Sub ShowSelection(ByVal Page As String)
'Turn off link for the current selection
Dim oLink As HyperLink = _
CType(Me.FindControl("lnk_" & Page), HyperLink)
oLink.Visible = False
Dim oLabel As Label = _
CType(Me.FindControl("lbl_" & Page), Label)
oLabel.Visible = True
End Sub
End Class
The Page_Load code in Listing 4 retrieves the query string passed by the
Application_BeginRequest procedure like this:
_sPage = Request.QueryString("page")
If _sPage Is Nothing Then _sPage = "index"
If the visitor requests the index page directly, the query string will be
empty, so the second line is necessary.
Using this visual Web page template technique, the content for each page
resides in an ASCX (user control) file. For example, the content for index.aspx
resides in the index.ascx file. When the ASCX corresponding to the request
exists, the following lines add the user control to the PlaceHolder located in
the Content section of the template:
_oContent = CType( _
Page.LoadControl(_sPage & ".ascx"), ControlBase)
Me.plcContent.Controls.Add(_oContent)
Note that ControlBase, rather than UserControl, is the base class for all of
the ASCX files in this demo. I'll explain why in the next section of this
article.
If the ASCX does not exist, the Catch block adds a generic message instead.
(Because the Application_BeginRequest procedure routes all incoming ASPX
requests to the template, ASP.NET cannot identify a Page Not Found error.)
That's all it takes to add the requested content to the page. However, the
display of the template itself needs to be changed to reflect the actual page
requested, like this:
Me.ShowSelection(_sPage)
The ShowSelection procedure (see the bottom of Listing 4) replaces the link to
the selected page with a bold font label.
Finally, the Page_PreRender procedure performs any tasks required because of
actions taken by the code behind the ASCX file. For this demo, we take this
opportunity to set the page title (which displays at the top of the browser
window) to the value of the user control's Title property, like this.
Me.litTitle.Text = _oContent.Title
If the user control doesn't supply a Title value, the procedure simply sets
the page title to the text used for the page link.
Having looked at how the template code uses the Title property, we're now
going to examine the mechanism actually used to supply the page title and to
provide other common functionality for the ASCX files.
Subclassing the UserControl Class
By default, the code behind a user control inherits directly from the
UserControl class. If the content portions of your Web application contain no
common processing requirements, that default works fine.
Usually, however, you'll want to provide some common functionality beyond that
provided by the UserControl class. To do so, you create a custom base class
like that shown in Listing 5. The ControlBase class in the demo inherits from
UserControl, but exposes two properties and adds the link to this article that
appears at the bottom of the content.
Listing 5. The ControlBase class code in ControlBase.vb.
Option Strict On
Imports System
Imports System.Web
Imports System.Web.UI
Public Class ControlBase
Inherits UserControl
Private _sTitle As String
Public Property Title() As String
Get
Return _sTitle
End Get
Set(ByVal Value As String)
_sTitle = Value
End Set
End Property
Private _sAppend As String
Public Property Append() As String
Get
Return _sAppend
End Get
Set(ByVal Value As String)
_sAppend = Value
End Set
End Property
Private Sub Page_PreRender(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles MyBase.PreRender
If Append <> String.Empty Then
Me.Controls.Add(New LiteralControl(Append & vbCrLf))
End If
Dim sFoot As String = _
"<hr width='100%' />" & vbCrLf _
& "<div>Read about this template: " _
& "<a href='http://www.smartisans.com/" _
& "articles/vb_templates.aspx'>" _
& "Creating a Visual Web Page Template" _
& "</a>.</div>" & vbCrLf
Me.Controls.Add(New LiteralControl(sFoot))
End Sub
End Class
When the code behind a user control inherits from ControlBase, it inherits all
of the UserControl functionality as well as the functionality provided in
Listing 5.
The Title property allows the user control to specify the title to be
displayed at the top of the browser window. At the end of the last section we
looked at the code that uses this property to set the page title.
The Append property provides a means to append text or HTML to the static
content of the ASCX page. The dynamic_content page demonstrates the use of this
property.
The Page_PreRender procedure appends the text, if any, to the Controls
collection. Then it adds the link at the bottom of the content.
Providing Static Content
Aside from the link to this article, which always appears, two of the Web
pages in this demo display static text only. The first is the Home page,
index.aspx. Figure 2 shows how its text appears in the Visual Studio .NET
designer.
Figure 2. The index.ascx file provides the content for the
index.aspx Web page.

When you work in the designer, you can have Visual Studio .NET create HTML for
you. The italicized text in Figure 2, for example, was formatted by
highlighting the desired text and clicking the italics icon. You can create a
link by highlighting some text and pressing Ctrl-L, and so on. Listing 6
provides the HTML that was created by typing the text shown in Figure 2.
Listing 6. The HTML listing for the index.ascx user control.
<%@ Control Language="vb" AutoEventWireup="false"
Codebehind="index.ascx.vb" Inherits="VbTemplate.index"
TargetSchema="http://schemas.microsoft.com/intellisense/ie5"%>
<p>
This project uses a single ASPX template file,
<em>index.aspx</em>, to display all five of its content pages.
The actual content for each page resides in its ASCX file.
The content for this page, for example, can be found
in <em>index.ascx</em>.
</p>
<p>
The mechanism used to forward each incoming request is the
Context.RewritePath method in the Application_BeginRequest
event handler. A query string supplies the name of the page
originally requested by the visitor.
</p>
<p>
Click the links to see how the template handles
different types of content.
</p>
The second of the text-only Web pages in this demo is static_text. This Web
page displays the content of the static_text.ascx file. Figure 3 shows its
content in the Visual Studio .NET designer.
Figure 3. The static_text.ascx file provides the content for
the static_text.aspx Web page.

I don't show the code behind either index.ascx or static_text.ascx in this
article because both listings do nothing but set the page title property in the
same manner as the listings that follow. Let's move on to the user controls
that do a bit more.
Appending Content Dynamically
The content for the dynamic_text Web page resides in the dynamic_text.ascx
file. This content includes a short unnumbered list, as shown in Figure 4.
Figure 4. The dynamic_text.ascx file provides the content for
the dynamic_text.aspx Web page.

If you request the
Dynamic Text page of the demo, you see an additional paragraph appended
to the text in Figure 4. Listing 7 shows how the ControlBase.Append property
was set. Note that, as I promised, the dynamic_text class inherits from
ControlBase instead of UserControl.
Listing 7. Code in the Page_Load event handler in
dynamic_text.ascx.vb specifies content to be appended by ControlBase.vb.
Option Strict On
Public MustInherit Class dynamic_text
Inherits ControlBase
#Region " Web Form Designer Generated Code "
'This call is required by the Web Form Designer.
<System.Diagnostics.DebuggerStepThrough()> _
Private Sub InitializeComponent()
End Sub
Private Sub Page_Init(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Init
'CODEGEN: This method call is required
' by the Web Form Designer
'Do not modify it using the code editor.
InitializeComponent()
End Sub
#End Region
Private Sub Page_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
Me.Title = "Visual Web Page Template Demo: Dynamic Text"
Me.Append = "<p>But this sentence was appended " _
& "programmatically during the Page.Load event " _
& "in <em>dynamic_text.ascx.vb</em>.<p>"
End Sub
End Class
You can also see in Listing 7 how the Page_Load procedure sets the Title
property. Similar statements exist in all of the ASCX.VB code files in this
demo.
To this point, none of the pages we've discussed post back to the server. And
in Web applications that supply content to visitors, that is the normal
situation. As I'm about to show, however, this technique can also handle
postbacks.
Posting Back to the Template
Using the visual Web page template technique described in this article,
postbacks are handled in the ASCX.VB code files for their respective pages. The
button_click page illustrates the use of an HTML input button to post back to
the server. Figure 5 depicts the content for the page as it appears in the
Visual Studio .NET designer.
Figure 5. The button_click.ascx file provides the content for
the button_click.aspx Web page.

Working in the designer, you can double-click a button control to direct
Visual Studio .NET to stub in the proper event handler for you. I did this with
the button in Figure 5 to start the btnClick_ServerClick procedure at the
bottom of Listing 8.
Listing 8. Code in the btnClick_ServerClick event handler in
button_click.ascx.vb reports when the user control recognizes a button click in
the browser.
Option Strict On
Imports System.Web.UI.HtmlControls
Public MustInherit Class button_click
Inherits ControlBase
Protected WithEvents btnClick As HtmlInputButton
Protected WithEvents pReply As HtmlGenericControl
#Region " Web Form Designer Generated Code "
'This call is required by the Web Form Designer.
<System.Diagnostics.DebuggerStepThrough()> _
Private Sub InitializeComponent()
End Sub
Private Sub Page_Init(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Init
'CODEGEN: This method call is required
' by the Web Form Designer
'Do not modify it using the code editor.
InitializeComponent()
End Sub
#End Region
Private Sub Page_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
Me.Title = "Visual Web Page Template Demo: Button Click"
End Sub
Private Sub btnClick_ServerClick( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles btnClick.ServerClick
pReply.InnerText = "You clicked the button!"
End Sub
End Class
If you request the
Button Click page of the demo, you can verify that the event handler in
Listing 8 gets control. Click the button and note the response.
Now take a look at the URL displayed in the address box of your browser. The
postback returns the URL built in the Application_BeginRequest procedure when
it routed the original request to the template.
If your Web application requires postbacks and you want to conceal the
postback URL from your visitors, you can do so. The next example shows how.
Accepting Input from the Visitor
The text_input.aspx page provides an HTML input text box for entering text
plus an HTML input submit button for posting the text back to the server.
Figure 6 shows the appearance of the text_input content in Visual Studio .NET.
Figure 6. The text_input.ascx file provides the content for the
text_input.aspx Web page.

If you request the
Text Input page of the demo, you can test its operation for yourself. The
server returns the text you enter while retaining the original URL. In the code
behind the text_input.ascx file, shown in Listing 9, the Page_Load and
btnSubmit_ServerClick procedures work together to accomplish this result.
Listing 9. The event handlers in text_input.ascx.vb return
data entered at the browser while concealing the URL of the template.
Option Strict On
Imports System.Web.UI.HtmlControls
Public MustInherit Class text_input
Inherits ControlBase
Protected WithEvents txtInput As HtmlInputText
Protected WithEvents btnSubmit As HtmlInputButton
Protected WithEvents pReply As HtmlGenericControl
#Region " Web Form Designer Generated Code "
'This call is required by the Web Form Designer.
<System.Diagnostics.DebuggerStepThrough()> _
Private Sub InitializeComponent()
End Sub
Private Sub Page_Init(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Init
'CODEGEN: This method call is required
' by the Web Form Designer
'Do not modify it using the code editor.
InitializeComponent()
End Sub
#End Region
Private Const sPage As String = "text_input"
Private Sub Page_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
Me.Title = "Visual Web Page Template Demo: Text Input"
Response.Cache.SetNoServerCaching()
Dim sInput As String = CStr(Session(sPage))
If Not sInput = String.Empty Then
txtInput.Value = sInput
pReply.InnerText = "You submitted: " & sInput
Session(sPage) = Nothing
End If
End Sub
Private Sub btnSubmit_ServerClick( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles btnSubmit.ServerClick
Session(sPage) = txtInput.Value
Response.Redirect(sPage & ".aspx")
End Sub
End Class
Here is the example I promised where output caching should be turned off. If
you plan to return data to the visitor in the same Web page that captured the
data, output caching will defeat your purpose: ASP.NET will return the original
page from the cache without ever executing your code. In Listing 9, the
Page_Load procedure kills output caching (for the text_input page only) like
this:
Response.Cache.SetNoServerCaching()
Check the time stamps on the demo pages to verify that output caching does not
apply to the text_input page.
The text_input page conceals the template URL after postback by means of these
two statements in the btnSubmit_ServerClick procedure:
Session(sPage) = txtInput.Value
Response.Redirect(sPage & ".aspx")
The code saves the value entered by the visitor in a session state variable,
then uses the Response.Redirect method to request a fresh copy of the Web page.
When issuing the response to this request, the Page_Load procedure retrieves
the value from session state and returns it to the visitor.
I've taken you through this demo to illustrate the basic concepts of this
simple visual Web page template technique. You can, of course, add many bells
and whistles to the basic structure if your Web application needs them.
But there are many ways to skin a cat. To conclude this article, I'm going to
provide some information about alternative approaches that you might take.
Selecting a Template Approach
If the content for your Web site resides in a database, you can use a visual
Web page template technique identical to the one described in this article,
except that the content comes from the database instead of from ASCX files.
Here too, a single ASPX file serves up many different Web pages.
In Chapter 15 of our book Programming the
Web with Visual Basic .NET, we provide a complete case study that
contains two visual Web page templates of this type. One template provides
database content selected by the visitor via either a search or a browse. The
other template provides browse listings by category. Our
sample chapter contains the Application_BeginRequest procedure needed to
distinguish between the templates, plus other code required for the database
approach.
The visual Web page template technique explained in this article works well
for many Web sites, particularly content-centric sites. However, there is no
"one size fits all" in Web programming. I recommend that you look at and
evaluate the approaches described by other authors too before you settle upon
an approach for your project.
Jonathan Goodyear wrote Create
Page Templates and, later, Page
Templates Revisited in Visual Studio Magazine. Philip Quinn wrote Page
Templates, available at ASPalliance.com. Peter Provost wrote ASP.NET
Page Templates, available at The Code Project. All of these authors
describe ways to use inheritance to build a Web site with a consistent look and
feel. Paul Wilson maintains a Web
site that uses inheritance throughout, with source code available for
download. By reading the information at these links, you can determine how
other Web page template approaches compare with the technique described in this
article.
Only you can determine the best approach for your project. Factors to consider
include the development time available, the programming skills of your team,
and the unique requirements of your Web application. Whichever approach you
choose, creating a Web page template will improve both the consistency and
maintainability of your Web site.
Downloading the Source Code
To try out the demo I used in this article, and to experiment with it
yourself, download
the source code and give it a test drive. Here's how to install it:
-
In Visual Studio .NET, create a Visual Basic ASP.NET Web Application named
VbTemplate.
-
Unzip the files in VbTemplate_Code.zip and copy them to
Inetpub\wwwroot\VbTemplate (overwrite existing files).
-
In the Visual Studio Solution Explorer, click the "Show All Files" icon.
-
Select the new ASPX, ASCX, and VB files, right click, then choose "Include In
Project".
-
Toggle off the "Show All Files" options (unless you prefer otherwise).
-
Right click index.aspx and select "Set As Start Page".
-
Delete WebForm1.aspx.
Home Articles We've Written Web Templates
|