ASP.NET Master Pages are a great way to make reusable web page templates. A Master Page template file can hold all the common HTML markup, CSS and JavaScript references, and .NET controls that appear throughout the pages of your web site. Each of your web pages injects only its own specialized content into the shell of the Master Page.
Once you start using Master Pages as shared templates it’s tempting to start putting shared functionality into them. After all, Master Pages fire their own events like regular web form pages. They can be referenced as objects from the pages that use them. So they may seem like a good place to keep common functions and properties that you need throughout the pages in your site. But there are a few Master Page gotchas that make this a poor practice.
Master Page gotchas
ASP.NET Master Pages seem like they’re base classes. You declare a Master Page in web form markup header.
<%@ Page Language="C#" MasterPageFile="~/MasterPages/SiteTemplate.master" Title="About Us Page"%>
Then you define blocks of output content in your page to insert into the Master Page template when a form loads.
<asp:Content ID="ContentBody" ContentPlaceHolderID="Main" Runat="Server">
<h1>About Us</h1>
<p>We are...</p>
</asp:Content>
And in your page you can reference the Master Page as an object, execute functions and access properties.
contentBodyHolder = (ContentPlaceHolder)Master.FindControl("ContentBody");
Though it may seem like a base class for pages, a Master Page is really more like a control that loads in the page that uses it. That may feel counterintuitive since the rendered Master Page output contains the calling page output. But the page actually loads the Master Page in much the same way it loads form controls.
For example, the Master Page page load event fires after the page load event of a page that uses the master. So with that in mind you can’t put common page setup logic into a Master Page load event and make use of the results in your page loads. The Master Page event will not fire until after the page’s load event is complete.
I mentioned that a Master Page is exposed as an object in any page that uses it. The catch is that it’s exposed as a generic System.Web.UI.MasterPage type. That means that any extra functions or properties you add to your master page will not be visible to Intellisense or to your compiler.
In order to make use of customizations you’ll have to cast the page object as the specific type of your Master Page within your web page. This means an extra bit of code crowding all of your pages. So while this might seem handy at first, it’s not the most practical approach.
((SiteTemplate)this.Master).HeaderText = "About Us Page";
Use Master Pages for templates, base classes for shared functionality
So Master Pages are great for templating, but weak for storing common logic and values. Where should you put that common stuff? Put it in a base form class.
Create a class that inherits System.Web.UI.Page. You can add a page load event handler to that class. You can also add any properties or common functions that you need there. Set your pages to inherit from this class rather than System.Web.UI.Page.
public class MyBasePage : System.Web.UI.Page
{
protected override void OnLoad(System.EventArgs e)
{
...
base.OnLoad(e);
}
}
The base class load event fires before your form load events fire. So you can put common setup logic in there. All of the properties, variables, and functions you add to the base class will be immediately available in all of the inheriting pages without any casting. The customizations will show up in page Intellisense without any extra code on the page side.