ages in Web applications often share common UI components, such as headers, sidebars, and footers. Developers often seek to encapsulate these common components into a page template, which each page can consume and possibly customize. However, in ASP.NET, this can be a nightmare. This is because there is no blunt, intuitive way to structure an application to accomplish page templating. The task becomes even more complicated when pages are large and require nested user controls to organize them into manageable units.
This article shows you how to rise to the challenge of building an effective page templating scheme. As you will see, combining a Web Control that represents the template to the Web designer with a user control that contains the actual template code, you can achieve an elegant yet simple and reusable approach that’s easy to maintain and takes full advantage of the ASP.NET framework. This approach becomes especially important when dealing with complex sites containing large data-driven pages that require page-level customization.
Page Template Methods to Avoid Many developers have invented ad hoc page templating schemes, with mixed results. The most common approaches are discussed below, along with reasons why you should avoid them.
Classic ASP Method. This method is the most archaic, yet most common way of handling page templating in ASP.NET. Developers create include files, containing header and footer content just as they did in classic ASP. Often, you’ll find that heavy use of include files is a side effect of migration. While include files still work, you should avoid using them because the include scheme doesn’t take advantage of the ASP.NET framework.
Begin-And-End User Control Method. As developers become more familiar with .NET, they often create two user controls, one for header content and one for footer content, usually named something like template_begin.ascx and template_end.ascx. At best, this approach bewilders and confuses the people responsible for page layout, and at worst, it causes errors. Because the opening and closing tags are separated into two files, nesting server-side controls inside the template is not possible?the ASP.NET runtime doesn’t allow this. Figure 1 shows a screenshot of the errors generated by Visual Studio .NET when trying to do so. In the end this results in treating the user controls as nothing more than glorified include files, which is really no better than the Classic ASP method.
Page Template Architecture The page template architecture presented in this article consists of three main controls: Each control can be summarized as follows:
The page template, implemented as a user control.
The PageBody server control, which provides the plumbing between the template and the page that uses it.
The NamingPlaceHolder control, which extends the PlaceHolder Web Control by making it a NamingContainer.
Figure 2 shows the relationship between these controls.
Building the PageBody Server Control The most important aspect of this model is exposing a server control to the calling page which controls the loading and customizing of the underlying page template. The purpose of doing this is to control the instantiation of all the page-specific content on the calling page, both static HTML as well as dynamic controls. By doing so, we can guarantee that all the server controls can participate in the intrinsic events, such as Init, Load, and LoadViewState. This would not be possible with the other ad hoc methods mentioned above.
Listing 5 shows the code for the PageBody server control. The control serves two major functions. First, by overriding the appropriate methods, it controls the instantiation of the child controls found on the page so that they are declared inside the placeholder of the page template. Second, it exposes public properties which are part of the customization process. In the case of the example above, the table cell containing the header requires a different CSS class attribute value when users are logged in or out. The HeaderCSSClass property holds the customizable data element:
Public Property HeaderCssClass() As String
To understand the code you need to visualize the timeline of execution. When the browser requests an .aspx page that consumes the template the ASP.NET engine must first parse the text for tag data. When it parses the tag for the PageBody control, it instantiates that class and then populates the values mapped to the properties, if any exist in the opening tag. As the parser continues to parse the inner text, it repeatedly calls the AddParsedSubObject() method, adding each inner child control to the _ControlList ArrayList. Later, the runtime calls the CreateChildControls() method. At that point, the PageBody control adds the controls in the ArrayList into the NamingPlaceHolder found inside the page template.
One can argue that it would be cleaner and simpler to eliminate the PageBody control from this architecture and declare the page template user control itself in the calling page. There are some problems with that approach. First, this creates an ambiguity between the child controls declared in the .ascx file and the child controls contained within the nested template calling tags. Actually what happens is the ASP.NET runtime places the child controls contained within its calling tags directly after the code in the .ascx file. It would be a mess to try to figure out where this partition occurs, and would eventually require hacks to make it work. The other major problem is one of flexibility?by using this server control as a bridge, you can not only customize the template, but you can take it a step further an allow the page to choose from one or more available page templates, if your application requires it.
As pointed out previously, because the CreateChildControls() method is implemented, the template and the page-level content are merged so that the page-level controls participate in the ASP.NET intrinsic events. If you load a user control programmatically from another user control or from the page, that user control does not participate in events which precede the point at which it was loaded. In other words, if you load a user control during the Page.Load event, the events which come before it are not raised within the user control, so handlers such as Page_Init do not get executed. For more information, visit the Control Execution Lifecycle page at MSDN.
Providing Unique Control IDs The final step is to create a naming placeholder. To do that, create a class that inherits from PlaceHolder and implements the INamingContainer interface. The following code a NamingPlaceHolder control class. The control extends the ASP.NET PlaceHolder control by guaranteeing that controls contained within have their own isolated namespace, eliminating duplicate IDs.
' This class extends the PlaceHolder class. ' This implementation gives all the child controls ' within a unique naming space, eliminating the possibility ' of a naming collision among one or more ' IDs between the pages and the page template. Imports System.Web.UI Imports System.Web.UI.WebControls Public Class NamingPlaceHolder Inherits PlaceHolder Implements INamingContainer End Class
INamingContainer is a marker interface that, when implemented by a control, creates unique IDs for its child controls. For example, when a control that implements INamingContainer has an ID of ctrlMain, its child controls will have IDs prefixed with this parent ID plus a colon, such as ctrlMain:TextBox1. This naming scheme guards against potentially dangerous naming collisions; the ASP.NET runtime will throw an exception if a server control inside the page template has the same ID as a control on the calling page. With potentially large sites, this extra step avoids the tedious task of manually ensuring that the IDs of server controls on the pages do not conflict with any IDs in any of the page templates for the site.
Putting It Together You can see how efficient and elegant this approach is. The following code shows the TypicalPage.aspx page with page templating implemented. As you can see, the code for the page has been significantly reduced. The page can now use the PageBody server control instead of copying the same HTML code from page to page. Using the page template, designers can manage template layout and page-level content layout separately.
My Site - Home
The beauty of this architecture is that it you can extend it to allow more than one page template. Furthermore, you can encapsulate the PageBody and NamingPlaceHolder classes in its own implementation for reuse in other Web applications. Each application would then inherit from PageBody, adding the properties required by the Web designers to customize the template.
Implementing Multiple Page Templates For some Web applications, one page template doesn’t provide enough flexibility. For instance, the look and feel of your site for customers who are not logged into your site may be drastically different from the UI for users who are, requiring multiple templates.
You can extend the single-template model you’ve already seen to a multi-template model by taking two extra steps. First, you must add a property to the PageBody class that stores a template path identifying the appropriate template to load. You can assign this TemplatePath property either inline, where you declare the PageBody control on the page, or in the code for that page. Here’s the property definition.
Public Property TemplatePath() As String Get Return _TemplatePath End Get Set(ByVal Value As String) If _TemplateLoaded Then Throw New System.Web.HttpException( _ "The page template cannot be set " & _ "more than once.") End If _TemplatePath = Value _TemplateLoaded = True End If End Set End Property
Listing 6 shows how to modify the PageBody class. One drawback is that after you set the TemplatePath property, you cannot change it, which ensures that the page template is loaded only once. This is because after determining the appropriate template, the application must load it into memory immediately so that you can instantiate child controls inside the NamingPlaceHolder. Once that’s done the child controls cannot be removed from the NamingPlaceHolder in one template and re-instantiated in another because that would cause the intrinsic events for the child controls to fire more than once.
The next step is to declare a generic, abstract PageTemplate class that each specific page template inherits from (see Listing 7). The class defines a property that references the PageBody control class for the Web application. The base class is necessary because you don’t know which template to load until runtime. Now, the PageBody class references the page template from this base class type, as opposed to the actual page template user control class as in the one-to-one page template model shown earlier.
The calling page specifies the correct template to use. If the value of the TemplatePage property never changes for a given page in your Web application, then it may be simpler to specify it declaratively inline with the PageBody declaration:
Otherwise, you should specify the correct template in code:
Remember, it has to be one or the other. You cannot specify the template declaratively and programmatically.
Encapsulating Templates for Reuse You can develop a reusable, extendable version from the page template architecture described in this article by creating an assembly containing three classes: one that contains an abstract definition for PageBody, one that contains an abstract definition for PageTemplate, and the NamingPlaceHolder class. Figure 3 shows the diagram for this assembly.
Migrating to ASP.NET 2.0 In October 2003, Microsoft officially outlined the specifications for ASP.NET 2.0, code-named “Whidbey”. One key feature is Master Pages, Microsoft’s better-late-than-never implementation of page templates. A master page is a new type of control, a sibling of the current Page and UserControl classes. In it, you define your page template. Then, you create content pages which reference one of the master pages contained within your application.
Master Pages are seamlessly integrated with the ASP.NET framework, and integrate well into the designer. When you’re designing a content page, the UI from the master page displays semi-transparently in the designer so you can see the completed design without having to run the application.
Work you perform to implement template pages today isn’t wasted?you can migrate the model described in this article to the new Master Pages architecture when ASP.NET 2.0 becomes available. Table 1 shows the functional equivalent for each aspect of this architecture. When you migrate to ASP.NET 2.0, you’ll need to convert your page template user controls into master pages. For multiple page templates, you can create a base implementation from the MasterPage class. Then, you can define all the customizable properties. One drawback is that you can’t set these properties declaratively, because you access the master page through the Content control. Instead, you will have to set these properties in the code-behind file using the Page.Master property.
PageTemplate User Control
Customizable properties defined in PageBody class
Customizable properties defined in MasterPage code-behind class
Author’s Note: When this article was written, it was too early to determine exactly how Microsoft will implement Master Pages in ASP.NET 2.0. Therefore, the information presented here is subject to change and should be treated lightly.
Developing an efficient page templating scheme is far from straightforward. But with some knowledge of how server controls work you can construct a scalable scheme for any Web application. Furthermore, this model can be extended to accommodate multiple-page templates within a single site. You can incorporate this page templating scheme into your ASP.NET applications without writing much code.
An op-ed, produced using Microsoft’s Bing Chat AI software, recently appeared in the St. Louis Post-Dispatch, discussing the potential concerns surrounding the employment of artificial intelligence (AI) in journalism. These
The Overshoot Commission has recently released a comprehensive report that discusses the controversial topic of Solar Geoengineering, also known as Solar Radiation Modification (SRM). The Commission’s primary objective is to
School districts are preparing to reveal a substantial technological upgrade designed to significantly improve remote learning experiences for both educators and students amid the ongoing pandemic. This major investment, which
Scientists John Connell and Yi Lin from NASA’s Solid-state Architecture Batteries for Enhanced Rechargeability and Safety (SABERS) project are working on experimental solid-state battery packs that could dramatically change the
In recent times, battery startups have experienced a significant boost in investments, with three businesses obtaining over $1 billion in funding within the last month. French company Verkor amassed $2.1
Microsoft’s latest offering, Microsoft Copilot, aims to revolutionize the way we interact with technology. By integrating various AI capabilities, this all-in-one tool provides users with an improved experience that not
Senser, an AIOps platform based in Tel Aviv, has introduced its groundbreaking AI-powered observability solution to support developers and operations teams in promptly pinpointing the root causes of service disruptions
Bebob has introduced new 4- and 8-channel battery charging stations primarily aimed at rental companies, providing a convenient solution for clients with a large quantity of batteries. These wall-mountable and
The Pentagon has recently unveiled its ambitious strategy to acquire thousands of sophisticated drones within the next two years. This decision comes in response to Russia’s rapid utilization of airborne
Microsoft has recently announced a series of new features and updates across their applications, including Outlook, Microsoft Teams, and SharePoint. These new developments are centered around improving user experience, streamlining
As we continue to face the repercussions of climate change, scientists and experts seek innovative ways to mitigate its impacts. Solar geoengineering (SG), a technique involving the distribution of aerosols
The fintech sector continues to attract substantial interest, as demonstrated by a dedicated fintech stage at a recent event featuring panel discussions and informal conversations with industry professionals. The gathering,