When you think ASP, think...
Recent Articles
All Articles
ASP.NET Articles
ASPFAQs.com
Message Board
Related Web Technologies
User Tips!
Coding Tips
Search

Sections:
Book Reviews
Sample Chapters
Commonly Asked Message Board Questions
JavaScript Tutorials
MSDN Communities Hub
Official Docs
Security
Stump the SQL Guru!
Web Hosts
XML
Information:
Advertise
Feedback
Author an Article
Jobs

ASP ASP.NET ASP FAQs Message Board Feedback ASP Jobs
 
Print this Page!
Published: Wednesday, June 24, 2009

ASP.NET Master Page Advice, Tips, and Tricks

By Scott Mitchell


Introduction


Master pages are an important part of any ASP.NET website. In a nutshell, a master page allows the page developer to define a website template, indicating what portions of the template are to remain fixed across pages that use the template and what regions of the template are customizable on a page-by-page basis. Having the site design and layout centralized in one (or more) master pages makes it easy to add new pages to the site that inherit the same look and feel and greatly simplifies changing the site design or adding or removing content that is common to all pages, such as content in the <head> element, footers, and references to CSS and JavaScript files.

This article presents advice for using master pages, along with assorted tips and tricks that I've picked up over the years in using master pages. Read on to learn more! And if you have additional recommendations and advice on using master pages, please don't hesitate to drop me a line and I'll be happy to add your insight to this article.

- continued -

When Starting a New Website Create a Master Page Before Creating Any Other Web Pages


Because the master page defines the look and feel for the site, it is only natural to think that the master page need not be created until the site's design has been completed. For many projects, the site's design is created by a graphic artist, either within the company or outsourced to another firm. Consequently, it's not uncommon for development work to begin prior to the site design being completed, leading ASP.NET developers to not create the master page until the site design is ready.

When starting a new ASP.NET website the very first thing I do is create a master page, regardless of whether the site design is ready. If the site design is ready, then the master page can be implemented with the design. If it's not yet complete, then just use the master page's default markup. Don't worry about having an ugly or incomplete master page - you can always come back and update it once the site design is ready. The reasoning for creating a master page right off the bat, regardless of whether the site design is ready, is because Visual Studio makes it very easy to add a new content page to the site, but requires that you jump through more hoops to take an ASP.NET page that does not use a master page and convert it into a content page.

When using the Web Site Project model (WSP), adding a new content page to the website is simply a matter of checking the "Select master page" checkbox; for Web Application Projects (WAPs) it's as easy as adding an item of type Web Content Form. Both approaches display a dialog box that prompts you to select the new content page's master page. If you have an existing ASP.NET page that does not use a master page, converting it into a content page involves removing the markup in the content page that is defined in the master page, adding appropriately named Content controls, and moving the page-specific markup into the appropriate Content controls. It's not rocket science, but it is certainly more work and not as quick or easy as checking a checkbox or selecting the Web Content Form item type.

Web Site Projects (WSPs) vs. Web Application Projects (WAPs)
Visual Studio supports two styles of ASP.NET projects: Web Site Projects (WSPs) and Web Application Projects (WAPs). WSPs are created by going to the File menu and choosing to create a New Website. They use automatic compilation (by default), meaning that the code in the pages' code-behind classes is automatically compiled when the page is first visited from a browser. Furthermore, the website project's files are defined by the files that exist within the website's folder structure.

WAPs are created by going to the File menu, choosing New Project, and creating a project of type ASP.NET Web Application Project. For a WAP, the code in the pages' code-behind classes is compiled explicitly from within Visual Studio by going to the Build menu. Also, the files that makeup the project are defined by a project file.

There are some subtle and not so subtle differences for the developer experience depending on the project model being used. For instance, creating a content page from a WSP entails checking the "Select master page" checkbox, whereas with a WAP you must choose a different item type, Web Content Form, as there is no "Select master page" checkbox to be found. For more background on these two project types check out the "Taking a Trip Down Memory Lane" section in Determining What Files Need To Be Deployed tutorial, which is one of 16 tutorials in my ASP.NET Hosting Tutorials on www.asp.net.

Do Not Name Your Master Page MasterPage.master


When creating a master page in a website that uses the Web Site Project model Visual Studio will suggest the name MasterPage.master. If you create a the master page using this suggested name then the master page's code-behind class will also be named MasterPage and will have the following definition:

Partial Class MasterPage
   Inherits System.Web.UI.MasterPage

End Class

Note that the master page's code-behind class derives from the MasterPage class in the System.Web.UI namespace. These two identical names do not cause a conflict because the master page's code-behind class and the MasterPage class in the System.Web.UI namespace are in two difference namespaces. However, it can lead to some difficulties if you need to get a strongly-typed reference to the master page from one of the content pages. While this annoyance is a minor one, I find it best to name the master page something else, like Site.master, and to avoid this confusion altogether. (Coincidentally, Visual Studio suggests the name Site.master when adding a new master page to a WAP. Why this same convention isn't used for WSPs is beyond me.)

Supply Default Content in the Master Page's ContentPlaceHolder Controls


The master page defines the markup that is fixed across all content pages along with what regions can be customized on a page-by-page basis. The ContentPlaceHolder control is what indicates a region that can be customized by a content page, and a master page can include zero to many such controls. When a new content page is added to the site, Visual Studio adds a Content control in the content page for each ContentPlaceHolder defined in the master page, inviting us (the page developer) to define the page-specific content for each region.

Did you know that these Content controls in the content page are optional? A content page need only define Content controls for the ContentPlaceHolders it wants to provide custom content for. What's more, the ContentPlaceHolder control in the master page can include content within it, as well, and this default content is used if the content page does not provide a Content control that overrides it.

The last paragraph may be a bit confusing, as I used the word "content" nine times! A simple example should clear things up. Consider a master page with two ContentPlaceHolder controls, FirstContentPlaceHolder and SecondContentPlaceHolder. Typically, the ContentPlaceHolder controls are defined without specifying any inner content, like so:

<%@ Master Language="VB" CodeFile="Site.master.vb" Inherits="Site" %>
... Some markup removed for brevity ...

<asp:ContentPlaceHolder id="FirstContentPlaceHolder" runat="server">

</asp:ContentPlaceHolder>

<p>Blah blah blah</p>

<asp:ContentPlaceHolder id="SecondContentPlaceHolder" runat="server">

</asp:ContentPlaceHolder>

With the idea being that a content page would define two Content controls that define the page-specific content for these regions. For example, a content page might contain the following markup:

<%@ Page Title="" Language="VB" MasterPageFile="~/Site.master" AutoEventWireup="false" CodeFile="Default.aspx.vb" Inherits="_Default" %>

<asp:Content ID="Content1" ContentPlaceHolderID="FirstContentPlaceHolder" Runat="Server">
   I have nothing interesting to say.
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="SecondContentPlaceHolder" Runat="Server">
   I should start a blog!
</asp:Content>

Note that there are two Content controls, Content1 and Content2, which define the content that is injected into the master page's FirstContentPlaceHolder and SecondContentPlaceHolder ContentPlaceHolder controls, respectively. The screen shot below shows this content page when viewed through a browser.

The content page defines the content for the two ContentPlaceHolders.

However, we could alter the master page to define default content for these two ContentPlaceHolders. The following updated master page markup illustrates this:

<%@ Master Language="VB" CodeFile="Site.master.vb" Inherits="Site" %>
... Some markup removed for brevity ...

<asp:ContentPlaceHolder id="FirstContentPlaceHolder" runat="server">
   <h1>This is the first content place holder!</h1>      
</asp:ContentPlaceHolder>

<p>Blah blah blah</p>

<asp:ContentPlaceHolder id="SecondContentPlaceHolder" runat="server">
   <h1>This is the second content place holder!</h1>      
</asp:ContentPlaceHolder>

If we visit the content page through a browser again the output is the same as shown in the above screen shot. However, if we remove one of the Content controls from the content page then its output is replaced by the default content defined in the corresponding ContentPlaceHolder. For example, if we remove the Content2 Content control that references the SecondContentPlaceHolder ContentPlaceHolder our content page markup will look like the following:

<%@ Page Title="" Language="VB" MasterPageFile="~/Site.master" AutoEventWireup="false" CodeFile="Default.aspx.vb" Inherits="_Default" %>

<asp:Content ID="Content1" ContentPlaceHolderID="FirstContentPlaceHolder" Runat="Server">
   I have nothing interesting to say.
</asp:Content>

Now when this page is viewed through a browser we see, "I have nothing interesting to say" at the top of the page - the content defined within the content page - but we see the default markup for the SecondContentPlaceHolder ContentPlaceHolder, "This is the second content place holder!"

The content page only defines the content for one ContentPlaceHolders; the default content in the ContentPlaceHolder is rendered in place of the missing Content control.

This default markup functionality of the ContentPlaceHolder control is useful in scenarios where virtually every page in the site has fixed content in one area, but there are one or two pages that need to customize the content in that region. In such a case you would do the following:

  1. Add a ContentPlaceHolder to the master page to indicate the region that is fixed for the majority of the pages, but needs to be customized for a small subset of pages.
  2. Enter the markup that is common to the majority of the pages within the ContentPlaceHolder.
  3. In those ASP.NET pages that use the same, default content, remove the corresponding Content control from the page's markup.
  4. For those pages where the content is unique, create a corresponding Content control and define the unique content within.
For more information on this technique, refer to the Multiple ContentPlaceHolders and Default Content tutorial, which is one of 10 Master Page Tutorials I've published on www.asp.net.

Use Web Controls and the Tilde Character (~) for Specifying URLs for Links and Images


When adding images or links to the master page, you may be tempted to use vanilla HTML elements, like the <a> element or <img> element. For example, to add a link to the homepage from the master page you might use HTML like so:

<a href="Default.aspx">Return To Homepage</a>

While this markup will work fine for content pages in the same folder as the master page, things do not work as expected for content pages in different folders. Consider what would happen if the master page was in the root folder of the site, but one of its content pages was in a subfolder named Folder1. The HTML rendered in the content page in Folder1 would be exactly the same markup shown above, namely: <a href="Default.aspx">Return To Homepage</a>. Consequently, if a user clicked that link they would be taken to the page Folder1/Default.aspx and not to the Default.aspx page in the root directory, which was the intent. To remedy this we can use a HyperLink control in place of the <a> HTML element along with the tilde character (~) to "root" the URL.

<asp:HyperLink runat="server" ID="lnkHome" NavigateUrl="~/Default.aspx">Return To Homepage</asp:HyperLink>

The NavigateUrl value of ~/Default.aspx causes the HyperLink control to generate a URL that is relative to the folder of the content page. A content page in the root directory of the site will render HTML like <a href="Default.aspx">Return To Homepage</a>, whereas a content page in a subfolder (such as Folder1) will render HTML like: <a href="../Default.aspx">Return To Homepage</a>.

This same issue applies with <img> elements. Rather than using <img>, use an <asp:Image> Web control and root the URL to the image via the ImageUrl property.

Use the @MasterType Directive To Get a Strongly-Typed Master Page Reference


All content pages have a loosely-typed reference to their master pages via the Page.Master property. If you have defined public methods or properties in your master page and want to access them from a content page you'll need to get a strongly-typed reference to your master page from the content page. One option is to cast the loosely-typed reference to a strongly-typed one. The following code snippet shows how to cast the Page.Master property to the master page type MasterPageType:

' VB
Dim myMasterPage as MasterPageType = CType(Page.Master, MasterPageType)

// C#
MasterPageType myMasterPage = Page.Master as MasterPageType;

An even better approach is to use the @MasterType directive. The @MasterType directive is a directive you add to the content page's .aspx file that indicates it's master page. The presence of this directive instructs the ASP.NET compiler to add a strongly-typed property named Master to the page. The following snippet from the declarative portion of a content page shows the @MasterType directive in action:

<%@ Page Language="VB" MasterPageFile="~/Site.master" AutoEventWireup="false" CodeFile="..." Inherits="..." %>
<%@ MasterType VirtualPath="~/Site.master" %>

With this directive in place the Page.Master property remains a loosely-typed reference to the master page, but the Master property (without the Page.) is a strongly-typed reference. (Confusing, I know.) But with this directive and the Master property you can access the public methods and properties of your master page without having to cast the Page.Master property.

For more information on content and master page interaction, see the tutorials Interacting with the Master Page from the Content Page and Interacting with the Content Page from the Master Page. Also refer to Scott Allen's article, Master Pages: Tips, Tricks, and Traps.

Prefer Using Nested Master Pages Over Separate Master Pages


Most of the websites I've worked on have had an overarching site design with various sections of the site that differ slightly from one another. I've worked on an eCommerce site that had a common layout among all pages - a menu at the top, information about the user and their cart in the upper right corner, legalese at the bottom, section-specific links on the left, and so on - but had minor customizations for the various sections. There were a total of four logical sections: general, non-product-specific pages; general products; logoed merchandise; and order fulfillment pages. The background image used at the top of the page differed among the four sections, and there were different links and slight layout differences in the upper right corner.

One approach to managing these differences would be to have four master pages in the project, one for each section. The problem with this approach is that it involves a lot of repeated markup and code, as more than 90% of the site design and layout markup between the sections was identical. As a result, any changes to the overarching design would require modifying the markup in all four master pages.

A better approach is to use nested master pages. Much like how an ASP.NET page can have a master page, a master page may also be assigned a master page. Such master pages are said to be nested. With nested master pages you could define a "root" master page that defines the markup and layout that is common to all sections and then create a nested master page for each of the four sections. The content pages in each section would then use the appropriate nested master page. The net benefit of this approach is that the overarching site design markup is consolidated into one "root" master page and the nested master pages contain only the variations among the sections. This makes it much easier to modify the site-wide design and have those changes instantaneously applied to all sections.

For more information on using nested master pages, check out Scott Guthrie's blog entry, Visual Studio 2008 Nested Master Page Support. Also reference the tutorial Nested Master Pages.

Conclusion


Master pages offer ASP.NET page developers an easy way to define a site-wide design and to have it apply to all content pages. All ASP.NET websites should include a master page and that master page should be the first thing added to the project. This article dispensed some master pages advice along with some tips and tricks. If you have additional advice or tips regarding master pages, please share them with your fellow readers by sending them to me. I'll happily add such recommendations to this article.

Happy Programming!

  • By Scott Mitchell


    Further Readings:

  • Master Pages Tutorials (10 tutorials in C# and VB covering an array of master page topics!)
  • ASP.NET Master Pages (technical docs)
  • ASP.Net 2.0 - Master Pages: Tips, Tricks, and Traps
  • Visual Studio 2008 Nested Master Page Support


  • ASP.NET [1.x] [2.0] | ASPMessageboard.com | ASPFAQs.com | Advertise | Feedback | Author an Article