Fixing the Page Title
n order to realize the value of new features, it helps to discuss the reasoning behind them. I’m going to start by briefly taking you through a few traditional approaches to designing an ASP.NET Web site today, with Microsoft Visual Studio® .NET 2003, and I’ll place emphasis on some of the pain points that will be removed with Master Pages. I have provided two sample projects that implement User Controls with two different approaches.
To design a Web site with a consistent look and feel you’ll typically leverage user controls to design common interface elements. As you add new Web forms to the project, you can easily drag and drop these reusable controls so that each page shares these common elements. In my first example, using Visual Studio .NET 2003 I created a new project, and began by building a header and footer user control to be used on each page. The header control, hdr.ascx, contains a menu and header graphic with a logo. In the designer it looks like this:
Figure1. Design view for the hdr.ascx user control
Then I created a footer control, ftr.ascx, to look like this:
Figure 2. Design view for the ftr.ascx user control
I can place these controls onto each new Web form using drag and drop which generates the control registration tag and an instance of the control on the page. To refresh your memory, after adding a new Web form to the project, and placing the header and footer, it looks like this in the designer:
Figure 3. Before adding content, the design view of a new page consuming the header and footer controls would look something like this.
The HTML source includes two registration tags, and entries within the <form> tag for each control.
To insert content between the header and footer, I usually start by dropping an HTML table from design view to provide structure, then drop page controls and content within. So, after adding three pages to the application (default.aspx, register.aspx and about.aspx) I modified each <form> section to include content in a consistently formatted table, something like this:
<form id="Form1" method="post" runat="server"> <uc1:hdr id="Hdr1" runat="server"></uc1:hdr> <TABLE width="95%" align="center" border="0" cellspacing="5" cellpadding="5"> <!-- PAGE CONTENT GOES HERE --> </TABLE> <uc1:ftr id="Ftr1" runat="server"></uc1:ftr> </form>
With the help of a style sheet each page has a consistent looking header, footer, and style, with individual content as shown in the figures 4, 5 and 6:
Figure 4. Default.aspx using header and footer user controls
Figure 5. Register.aspx using header and footer user controls
Figure 6. About.aspx using header and footer user controls
The beauty of this architecture is that I can edit any of the common user controls and have changes automatically reflected in each Web form that consumes them. Furthermore, if I restructure hdr.ascx so that menus are separated into a child user control, there is no impact on pages that reference the header. Sounds good, right? I thought so, too. Until after building an entire site map for a client using these techniques, I was given a new set of graphics from the Web designer that significantly altered the layout required for each page. Most creative Web designers don’t design using squares and rectangles. They like to see overlapping graphical regions to make the site look more interesting. That means layering graphics and cutting them into rectangular parts that can be worked with in the HTML source. So, not only did I have to modify the contents of the header and footer controls, I also had to modify how they were positioned within each page frame, and I had to add some new user controls for containing sidebar content.
In my example above, I created a simple header and footer whose HTML tags are simply placed above and below the content are (as shown in Listing 1). The only effort in page layout is that for the content area. To add a sidebar that will have an alternate background color, new content, and that will span the height of the browser window I have to add table structure to organize the user control elements and page content. In my UserControlsV2 project sample, I demonstrate this by adding a sidebar control to the layout that allows users to subscribe to the newsletter. Consider the following desired result:
Figure 7. Runtime view of Register.aspx after modifying the page layout to include a sidebar on the right
This seemingly small change requires me to modify some existing user controls, create a new sidebar user control, and edit each page to massage the organizational layout. That last part is what really hurts. After a few pages worth of copying and pasting the new HTML layout and moving existing content into this new layout, you can imagine that I may introduce some errors even on a good day. And I get to do it all over again any time a significant change occurs with the site presentation. Furthermore, regression testing in this type of scenario literally requires testing every page in the site because I touched each page. So, if this is a pain for a three-page code sample, imagine the impact with a significant Web site.
My new HTML source layout looks like this:
<!-- outer table --> <table width="100%" height="100%" border="0" cellpadding="0" cellspacing="0"> <TBODY> <tr valign="top"> <td colspan="2"> <!-- header goes here --> <uc1:hdr id="Hdr2" runat="server"></uc1:hdr> </td> </tr> <tr valign="top"> <td> <!-- content goes here --> </td> <td align="right" valign="top" height="100%" nowrap=true width="225"> <!-- sidebar goes here --> <uc1:sidebar id="Sidebar2" runat="server"></uc1:sidebar> </td> </tr> <tr> <td colspan="2"> <!-- footer goes here --> <uc1:ftr id="Ftr2" runat="server"></uc1:ftr> </td> </tr> </table> </TR></TBODY></TABLE>
Using Visual Studio .NET 2003 there is a workaround for this challenge I present to you. As you might guess, you can reverse the roles of the Web Form and the User Control. You can create a single Web form that injects dynamic user control content as the user navigates. There are several issues with this approach. For example, you have to come up with a new resource navigation architecture since you will no longer have a unique *.aspx resource for each page. This also means that the browser URL may not indicate a resource name that matches the content being displayed. The following table provides an example for how the three pages from my previous example might be requested in this new scenario:
|Old Resource||New Resource||Functionality|
|http://…/default.aspx||http://…/default.aspx||Placeholder control has default content for home page.|
|http://…/register.aspx||http://…/default.aspx?page=register||Load register.ascx user control into default.aspx placeholder control.|
|http://…/about.aspx||http://…/default.aspx?page=about||Load about.ascx user control into default.aspx placeholder control.|
You can provide the user with a URL scheme consistent with the previous example if you create a custom HTTP handler factory to control how a request for *.aspx are handled, and make use of some combination of Server.Transfer and Server.Execute functionality to achieve variations on how the resulting output is generated. If the core benefit of editing just a few *.aspx page templates, and replacing some part of the content at runtime is your priority, this is an acceptable solution with our current ASP.NET architecture. But, I’m sure you’d agree that all that up front work to make it possible is just wrong because is shouldn’t be so complicated.
Master Pages were designed to make it easy to edit page templates in a single location, without modifying how we work with the page model and without the trickery on the back end. Now I’ll show you how ASP.NET Whidbey is going to knock your socks off with greater productivity.