This release of ASP.NET builds upon the substrate for building Web applications introduced in version 1.0. All of the architectural features of the ASP.NET 1.x runtime are still present in 2.0, but elements were added to make development of Web applications more intuitive and efficient. One of the most significant additions is the partial class codebehind model, in which instead of manually declaring control
It is very common in Web site design to define a standard "look and feel" for all pages. This may include common headers, footers,
Figure 2-1. Sample templated site
This particular page has a header at the top, a footer at the bottom, a navigation bar on the left, and an area for page-specific content filling out the remainder. Ideally, the header, footer, and navigation bar should be defined only once and somehow propagated to all pages in the site.
This is precisely the problem that master pages in ASP.NET 2.0 solve simply and cleanly. By defining one master page and then creating many content pages based on that one master page, you can very easily create sites with a common look and feel driven by a single template (the master page).
Master pages in ASP.NET 2.0 are a general solution to site templating. They provide site-level page templates, a mechanism for fine-grained content replacement, programmatic and declarative control over which template a page should use, and perhaps most compelling of all, integrated designer support. Figure 2-2 shows the conceptual relationship between a master page and content pages that are tied to the master page.
Figure 2-2. Master page concept
The implementation of master pages in ASP.NET 2.0 consists of two conceptual elements: master pages and content pages.
act as the templates for content pages, and
provide content to populate pieces of master pages that require "filling out." A master page is
Listing 2-1. Sample master pageSiteTemplate.master
Content pages, in contrast, are just ordinary .aspx files that specify an associated master page in their page directive using the MasterPageFile attribute. These pages must contain only instances of the Content control, as their sole purpose is to supply content for the inherited master page template. Each Content control must map to a specific ContentPlaceHolder control defined in the referenced master page, the contents of which will be inserted into the master page's placeholder at rendering time. The content page in Listing 2-2 provides content for the SiteTemplate.master master page shown earlier.
Listing 2-2. Sample content pageDefault.aspx
Note that with this mechanism we are able to specify content to be placed at very specific locations in the master page template. The example in Listing 2-2 shows how the subtle problem of generating unique page titles with templates is
With the fundamental mechanics of master pages in place, we can now
Figure 2-3. Page rendering with a master page
Even more compelling is the fact that master pages are
Figure 2-4. Designer support for master pages in Visual Studio 2005
The implementation of master and content pages is quite similar to the approach taken by many developers building their own custom templating mechanism in ASP.NET 1.x. In particular, the MasterPage class derives from UserControl and thus inherits the same generic container functionality that
Figure 2-5 shows a sample content page with an associated master page and the resulting merged control hierarchy that is created just prior to the Init event during the page processing.
Figure 2-5. Master page/content page merged hierarchy
One of the implications of this implementation is that the master page itself is just another control in your Page class' hierarchy, and you can perform any of the
Listing 2-3. Programmatic access to master page controls
Working with Master Pages
It is a
Listing 2-4. Master page exposing a property
A particular page could then access the master page via the Master property of the Page class, cast the result to the master page type, and set the ShowNavigationLinks property of the master page to true or false. Listing 2-5 shows a sample content page that disables the links via the exposed property.
Listing 2-5. Content page accessing master page property
You can take this one step further and eliminate the cast by using the MasterType directive in the content page. Adding a MasterType directive causes ASP.NET to generate a
Listing 2-6. Strongly typed access using the MasterType directive
The MasterType directive also supports a TypeName attribute that you can use instead of the VirtualPath attribute if, for example, you don't want to create a hard-coded
Listings 2-7, 2-8, and 2-9 show a sample common base class, a master page that inherits from that base class, and a content page that uses the TypeName attribute to strongly type the Master property to the shared base class, respectively.
Listing 2-7. Common master page base class
Listing 2-8. Master page inheriting from a common master page base class
Listing 2-9. Strongly typed access to a common master page base class in a content page
Using a common base class for a master page makes the most sense if you plan on having multiple master pages that could be affiliated with a page and then adding the ability to change the affiliation at runtime. To change the master page affiliation, you can use the MasterPageFile property, which is exposed as a public property on the Page class and can be modified in the code for any page. Any modifications to this property must be made in a handler for the PreInit event of the Page class for it to take effect, since the creation of and merging with the master page happens just prior to the Init event firing. Keep in mind that if you do change the master page programmatically, the new master page must have the same set of ContentPlaceHolder controls with matching identifiers as the original master page;
The override of the OnPreInit method in Listing 2-10 could be added to any Page class using a master page to programmatically change the master page affiliation.
Listing 2-10. Changing the master page at runtime
Details of Usage
As you begin to use master pages in your site design, you will run into some issues that may not have occurred before if you have never used a site-level templating mechanism. The first issue is that of relative paths in referenced resources like images or stylesheets. When you are creating a master page, you must keep in mind that the directory from which relative paths are going to be evaluated may very well change based on the page being accessed. Consider the directory structure of the site shown in Figure 2-6.
Figure 2-6. Sample Web site directory structure
If you were to add a reference to the Check.gif image in the images directory from the Site.master in the masterpages directory, you might be tempted to add a simple image element like this:
<img src="../images/check.gif" />
Unfortunately, this would only work for pages that were in a similar relative directory location to the image as the master page was (like page1.aspx). Any other page (like default.aspx) would not correctly resolve the relative path. One solution to this problem is to use the root
<img src="~/images/check.gif" runat="server" />
Another option is to rely on the fact that relative path references in server-side controls are evaluated relative to the master page in which they are placed. This means that it would also be sufficient to change the image reference to:
<img src="../images/check.gif" runat="server" />
Server-side path references in pages that reference master pages are still relative to the page itself, so you should not have to change any techniques you may already have in place to deal with relative references in pages.
Another common request when ASP.NET developers first encounter master pages is to somehow enforce that all pages in an application be required to be content pages referencing a specific master page. While there is no "must use" attribute, you can
<configuration> <pages masterPageFile="~/sitetemplate.master" /> </configuration>
Like any settings specified at the application level, individual pages can elect to override the default masterPageFile attribute, but adding this to your configuration file will guarantee that no pages will be added to your application
Finally, you may find that it is useful to have a "meta" master page, that is, a master page for a set of master pages. Master pages support arbitrarily deep nesting, so you can create whatever level of master pages you decide makes sense for your application. Just like pages that have master pages, master pages that have master pages must consist exclusively of Content controls. Within these Content controls, master pages can then add additional ContentPlaceHolder controls for the actual pages to use. Note that pages that reference a master page which itself has a master page can only provide Content elements for ContentPlaceHolder controls on the immediate parent master page. There is no way to directly populate placeholders on a master page two or more levels up from a particular page. As an example, consider the master page definition (in a file called MetaTemplate.master) in Listing 2-11.
Listing 2-11. Master page for other master pages (MetaTemplate.master)
We can now define another master page, which in
Listing 2-12. Master page using another master page
You may also find it useful to create alternate master pages based on the user agent string (browser type) sent by the client. If you want to leverage some browser-specific features in your master page, it may make sense to create multiple versions of the master page for the variations across browser types. ASP.NET 2.0 supports device filters to do this
Listing 2-13. Using device filters to declaratively select a master page