All ASP.NET pages extend the Page class in the System.Web.UI namespace, which defines the base functionality, events, methods, and properties common to all ASP.NET pages. This includes common objects like
Session, along with the mechanisms for serializing view state, injecting client-side script, and managing the ASP.NET page's lifecycle. You can provide additional functionality to all your ASP.NET pages in your application by:
- Creating your own class that includes the extra functionality desired,
- Have this class derive from the .NET Framework's
Page class, and
- Configure your ASP.NET pages to extend the custom class created in step 1, rather than the .NET Framework's
Such custom classes are referred to as base page classes. For more information on creating and using base page classes check out Using a Custom Base Class for your ASP.NET Pages' Code-Behind Classes.
Base page classes usually contain customizations that are specific to the application for which they were created, but can also contain more common functionality that, for one reason or another, was not provided by Microsoft in their
Page class. This article shares four helpful features you can add to your base page class.
The complete code for the following features is available for download from this article, along with a demo page. The code snippets below show just the code relevant to the particular feature being examined.
alert(message) function displays the specified message in a modal dialog and is commonly used to display status information. For example, you can have any user input validation errors displayed in a client-side dialog box by adding a ValidationSummary control to your page and setting its
ShowMessageBox property to
alert function to display a summary of validation errors.
The base page class in the download includes a method named
DisplayAlert that takes a string as input and emits the client-side script to display the passed-in string in a dialog box.
DisplayAlert method can be called from any ASP.NET page that extends the custom base page class with the following code:
Recursively Search the Control Hierarchy
All ASP.NET controls include a
FindControl(id) method that searches the children controls for a one whose
ID property is equal to the passed-in id string. Unfortunately,
FindControl does not penetrate through naming containers, which are commonly used in templated controls. As a result, it can be a pain to get a programmatic reference to those controls within templated controls. The good news is that it's not at all hard to write a recursive
FindControl method, and such a method is a good fit for a base page class.
My implementation below has two overloads: the first accepts just an id input parameter and starts the search at the root of the page's control hierarchy; the second one allows for a starting node in the hierarchy. If you are searching within a particular control, use the second method so as to narrow the search space.
The demo available for download shows this method in action with a LoginView control. The LoginView control is composed of templates and renders one of its templates based on the user visiting the page. For example, if the visitor is anonymous then the LoginView's AnonymousTemplate is rendered. Because the LoginView control is composed of templates and because these templates act as naming containers, you have to use the
FindControl method to programmatically work with any of the Web controls within its templates. However, you have to be certain to use the
FindControl method from the parent container because it does not penetrate naming containers.
To better understand this, consider the following LoginView, which has a TextBox named
UserNameInTextBox in its LoggedInTemplate and a Label named
CurrentTime in its AnonymousTemplate.
To set the
CurrentTime Label control's
Text property you need to first use the
FindControl method to get a reference to it. But you need to be careful here because the
FindControl method's search does not penetrate naming containers and the LoginView's template constitutes a naming container. Consequently, the following call to
FindControl will return
Instead, you have to start at the parent container, LoginView:
Note the difference in the two code snippets above: one calls the
FindControl method, the other calls the LoginView's
FindControl method. The first returns null because the search does not drill into the LoginView's templates to find
CurrentTime, but the second one succeeds because it starts its search from that same naming container that the Label exists in.
A simpler approach is to use our new recursive method,
FindControlRecursive. Because this method plows through naming containers you can search starting at the top of the page's control hierarchy (the default behavior) and it will still find the control nestled within the LoginView's template (assuming that the page is being requested by an anonymous visitor).
It may seem a bit superfluous to create a
FindControlRecursive method for this particular example; after all, we can reference the Label by calling the LoginView control's
FindControl method. But imagine that the LoginView control was itself within a naming container. Then in order to reference the Label you would have to first reference the LoginView using
FindControl from its parent naming container and then use
FindControl again to get the Label. Our recursive
FindControl implementation does not require this extra
A Generics-based implementation of a recursive
FindControl method can be found at Steve Smith's blog: Recursive FindControl.
Record Page Execution Times
It's helpful at times to know how long it took a particular ASP.NET page to be processed on the server, or how long a particular operation took. While ASP.NET's tracing feature provides this information and more, sometimes that blob of information is much more than is needed. A simpler approach is to have the base page optionally record and display the page's execution time.
Because we might not want to measure and record the execution time on all pages, it's a good idea to add a property to the base page class that indicates whether these measurements are to be made. The base page class available for download has a Boolean property named
MeasureExecutionTime that does just that; it defaults to false.
A Stopwatch class instance named
watch is used to measure the execution time. This object is instantiated and started in the base page's
OnInit method, which executes during the Init stage of the page lifecycle.
The base page class includes a method named
RecordTimestamp that, when called, stores the number of elapsed milliseconds and passed-in description in a
TimestampInfo objects. The
TimestampInfo class includes properties that record the elapsed time (in milliseconds) along with a human-friendly description. A page developer can call
RecordTimestamp whenever he would like to record the elapsed time. During the
PreRenderComplete event, the
Stopwatch object is stopped and the times are displayed on the page. Specifically, the times are tacked on immediately before the closing
</form> tag using a series of
Note that the
MeasureExecutionTime property defaults to
false. Therefore, to use this functionality you will need to explicitly set this property to true in your ASP.NET pages in the
Page_Init event handler. The following code shows an ASP.NET page that uses this page execution timing feature to not only track the total page load time, but also to determine how long a particular operation takes. In this case we are timing a call to
Thread.Sleep; in practice you would be interested in timing potentially long running tasks, like Web Service calls or database queries.
As the screen shot in Figure 2 shows, the output isn't pretty, but the idea is that this information is used solely for diagnostic purposes and is not intended to be displayed on a production website.
Setting the Page Title
Page class in the .NET Framework includes a
Title property that can be used to programmatically set the text in the page's
<title> element. The browser displays the text within the
<title> element in the window's title bar, it is the default text used when a page is bookmarked, and search engines typically display this title when listing search results. Consequently, it's a good idea to give your page's meaningful titles. Unfortunately, Visual Studio gives each new ASP.NET page a default title of "Untitled Page," which means if you forget to change this you'll end up with a lot of pages on your site with the same meaningless title.
Here's a fun bit of trivia: you can use Google's search filter
allintitle:"title" to search for web pages with a particular title. A search for "Untitled Page" returns over 8.1 million results! You can use the
site:domainName filter to see how many pages in Google's index are named "Untitled Page" on your site (or anyone else's). As of the time of this writing Google reports that there are 7,920 web pages titled "Untitled Page" on microsoft.com.
An easy fix is to beef up your base page class so that it sets the page's title automatically (if it was not already set). The base page class available for download has a method called
SetPageTitle that is automatically called during the
Load event. If the base page class property
AutoSetPageTitle is true (the default) and the page's
Title property has not yet been set or is set to "Untitled Page", then the page's
Title property is set based on the site map or the page's file name.
If your site is configured to use ASP.NET's site map feature then those pages that are referenced in the site map will have their title set to the value: Title (RootTitle :: GrandParentTitle :: ... :: ParentTitle)
Where Title is the title of the current page in the site map, RootTitle is the title of the root node in the site map, and GrandParentTitle down to ParentTitle are the titles of the current node's ancestors. The demo web page is located in the site map in the following hierarchy:
- Non Fiction
- Demo Page
The title of the demo page in the site map is: "Teach Yourself ASP.NET 3.5 in 24 Hours." As a result, the base page sets this page's title to: Teach Yourself ASP.NET 3.5 in 24 Hours (Home :: Books :: Non Fiction)
If the page is not in the site map, or if the site map feature is disabled, then the
Title property is set to the file name of the page (less the extension). In other words, if the page is titled
About.aspx the title will be set to About.
Scott Mitchell, author of eight ASP/ASP.NET books and founder of 4GuysFromRolla.com, has been working with Microsoft Web technologies since 1998. Scott works as an independent consultant, trainer, ...
This author has published 16 articles on DotNetSlackers. View other articles or the complete profile here.
You might also be interested in the following related blog posts
New Entity Framework Feature CTP for VS2010 Beta 2
Mapping references and collections in Telerik OpenAccess ORM (Part 1)
Telerik announces second Beta release of RadControls for Silverlight/WPF Q3 2009
Entirely unobtrusive and imperative templates with Microsoft Ajax Library Preview 6
WebAii Testing Framework Support for Extended Silverlight RadControls
Four Little Known, Helpful Methods, Properties, and Features for ASP.NET Developers
Self-reference hierarchy with Telerik TreeView for Silverlight
Comments on my recent benchmarks.
Next version of EF Code Only Design laid out by MS
Please login to rate or to leave a comment.