Are Master Pages too complex?

MasterLockMaster Pages are a wonderful concept that as developers we highly value. It’s the sort of pattern that just looks like the right thing to do (to our twisted, concept hungry developer minds) and that even makes you wonder why we haven’t done it that way since the beginning of time (1990). For the record, master pages were invented by David Ebbo, who is behind a lot of the smartest things in ASP.NET.

Just in case you have no idea, what are Master Pages? Before master pages, sharing layout between pages was done using includes (or user controls). For example, your typical hello world page might have looked like this:

<%@ Page Language="C#" %>
<%@ Register TagPrefix="include" TagName="header"
Src="~/HelloHeader.ascx" %> <%@ Register TagPrefix="include" TagName="footer"
Src="~/HelloFooter.ascx" %> <!DOCTYPE html> <html> <head> <title>Hello world with includes</title> </head> <body> <div> <include:header runat="server" />
Hello world! <include:footer runat="server" /> </div>
</body> </html>

Notice that the page does contain markup that is not specific to the page (boilerplate markup mainly that you could put into includes as well, but only at the cost of breaking beginnings and ends of semantic blocks into separate includes).

As a side note, I’ve always thought the user control syntax above was overly verbose when all you want is a plain include. It has the one advantage of enabling the Visual Studio designer but having a separate registration and declaration seems overkill. The #include directive still exists but I personally prefer to use a simple helper extension method to Page that brings the code down to this (MVC gives you Html.RenderPartial, which is roughly equivalent):

<%@ Page Language="C#" %>
<!DOCTYPE html>
<html>
<head>
    <title>Hello world with includes</title>
<meta name="keywords" content="hello world" /> </
head> <body> <div>
<% this.Include("HelloHeader.ascx"); %> Hello world!
<% this.Include("HelloFooter.ascx"); %> </div>
</body> </html>

With master pages, you can get rid of all common markup and really limit what you put into the page to just what varies from page to page. for example, the above hello world page might be written like this:

<%@ Page Language="C#" MasterPageFile="~/MasterPage.master"
Title="Hello world!" %> <asp:Content ContentPlaceHolderID="head" Runat="Server"> <meta name="keywords" content="hello world" /> </asp:Content> <asp:Content ContentPlaceHolderID="content" Runat="Server"> Hello from the content page! </asp:Content>

That is clean, but pretty puzzling the first time you see it. To understand where the markup comes from, you need to track that @Page directive and understand that you need to look into the corresponding master page file:

<%@ Master Language="C#" %>
<!DOCTYPE html>
<html>
<head runat="server">
    <title>Master page</title>
    <asp:ContentPlaceHolder id="head" runat="server">
    </asp:ContentPlaceHolder>
</head>
<body>
    <h1>Hello from a master page</h1>
    <div>
        <asp:ContentPlaceHolder id="content" runat="server">
        </asp:ContentPlaceHolder>
    </div>
    Footer says hi.
</body>
</html>

You need to understand that those content place holder ids correspond to other controls that are in the master page and that the framework will make the match.

Master pages also come with the price of mangled ids, but that’s an implementation detail (one could imagine an implementation that wouldn’t suffer from that problem). The price we pay for master pages also comes in the form of a weird control tree: master pages are really implemented as user controls that get included by the page, a concept that is the inverse of the model they seem to promote; in other words, the implementation is the reverse of the concept, in a way. There are also complications about putting contents in the head section (head must be runat=server, script tags are tricky, setting the title, etc.).

So are master pages worth the price? It depends on who your audience is and on how your pages are built.

By audience, I mean the person who is going to write the views. If it’s just you and you are a developer, they might actually be a pretty solid choice. But if external designers are going to build the views, maybe you need to pause and try not to think as a developer for a moment.

The main problem with the include approach (and the reason why master pages were invented) is that the outer markup for the page needs to be on all pages. So if you decide to change that markup, you need to do so on all pages.

But in more and more applications, in particular CMS, this problem becomes moot. If your application decouples the content from the view code, and if the layout or view to use for a given content can be determined at runtime by a themeing engine, you might end-up with templates that look like this:

<%@ Page Language="C#" %>
<!DOCTYPE html>
<html>
<head>
    <title><%= Title %></title>
</head>
<body>
    <div>
    <% this.RenderZone("Header"); %>
    <% this.RenderZone("Contents"); %>
    <% this.RenderZone("Footer"); %>
    </div>
</body>
</html>

This is actually no different in concept from master pages (there are place holders in generic markup and no specific contents) but the contents do not come from a content page. Instead, they are dynamically inserted by the application.

The template file then becomes no more than layout. It is easy to understand and easier to assign a different layout to any given contents.

So in general there is no perfect answer on whether you should use master pages or not, but if you are able, in your application, to decouple page layout from contents, there is an opportunity to have clean and easy to understand markup that also maximizes re-use.

13 Comments

  • I have a love hate relationship with MasterPages. The functionality they provide is great, but the naming container mangling really is the biggest bummer.

    I really wish that all ASP.NET controls/Masters/UserControls could have a switch to turn off the name mangling and leave the full control over all naming up to the developer (ie. ensuring no name conflicts across controls) and assign control IDs to the page (ie. no prefixes). I haven't checked but I think the master scenario won't be addressed by the new Client ID features of ASP.NET 4.0?

    It's interesting how perception of these issues change once you start building more client centric apps. With server centric apps these issues don't matter much, but when dealing with script driven apps this becomes somewhat important.

    BTW it'd also be nice if there could be a strongly typed master page definition in the page (Page kind of like an MVC ViewPage that can take the model).

  • @Rick: nice idea, I'll forward that. About the control over ids, there are no reasons why it wouldn't work in a content or master page. As you can act at the naming container level, you should be able to get control back for any id with minimal effort. I'll check with Scott Galloway.

  • I like how this article gives the impression that ASP.NET master pages were the dawn of templates -- I'm pretty sure I was using includes within perl scripts in early cgi days :).

    Seriously though, one quick less than 30 minute intro to ASP.NET for a new developer should make Master pages clear -- if someone has difficulty comprehending Master pages, they shouldn't be writing ASP.NET code anyway.

  • Dude, your final example is exactly what I was doing 10 years ago in ASP 3. IT SUCKED @$$! It's not any better today. Let the freaking framework render the HTML, that's what it's there for. Would you want to manually render all of your GDI+ on a WinForms app? Of course not! This whole fascination with ASP.Net MVC is mind boggling as it's literally setting ASP.Net back 10 years for the sake of unit testing.

  • I'd second the notion of optionally eliminating the naming container mangling. I thought I had heard somewhere that AJAX 4.0 was going to do something like that too with some of their controls, so you could set the Id yourself and take the responsibility if you had a naming collision. I think this would work great here too.

  • Would you share the code for the Include() extension method?

  • I'm not sure when David Ebbo invented master pages, I had an implementation with basic design time support in Visual Studio for Asp.Net 1.1 and there was at least one other implementation on the web that used the same approach as me. This was before I ever heard an announcement of the feature in Asp.Net. I abandoned the code when it was annonced.

    I'm sure it was thought of and being worked on long before it was anounced but I remain curious: Could you clarify what was invented? Was it the specific implementation?


    If taking 30 minutes to understand something is elitist, we are all in big trouble :P

    I don't have a problem using master pages and I've never had to work with anyone who couldn't deal with them. That being said, there are some things that are counter intuitive and unexpected.(eg The way a master page treats css links in the head seems to confuse almost everybody.)

  • @Andrew: with David's help, I was able to trace it back to that June 2002 sample:
    http://www.asp.net/community/control-gallery/Item.aspx?i=69
    It was later extended by Paul Wilson:
    http://authors.aspalliance.com/PaulWilson/Articles/?id=13
    http://authors.aspalliance.com/PaulWilson/Articles/?id=14
    Was your implementation before that? If so, I'll plead ignorance :) Even David had trouble remembering the whole thing...
    My arrogance comment was more aimed at the "if someone has difficulty comprehending Master pages, they shouldn't be writing ASP.NET code anyway" comment, not at the 30 minutes comment. I'm not really saying that people couldn't deal with the concept if you could explain it to them, more that you usually don't have the luxury to do that, and even if you did, what is the benefit to them that justifies them doing things differently whereas what they know works perfectly well as far as they are concerned? You have got to provide a justification for asking people to forget about what they know and learn something completely different.

  • I'm pretty sure it was after that, maybe in the fall. I remember finding Paul Wilson's demo not long after I had mine working and wishing I had found it earlier.

  • Amen. Use the right tool for the job. If you're a dev and you need reusable layout, use master pages (yes, some devs also do the implementing of UI that designers designed). However, it is a completely valid point that if you want non-devs to implement UI in your app and they have a choice not to, it doesn't make sense to use master pages.

    That said, I personally believe there are better ways to do templating so you don't have to repeat a bunch of markup in each file. Nobody's implemented it yet. ;)

    The real "problem" with master pages is that they're backwards. Includes have the same problem really. The page shouldn't decide what layout should be used to render. The site should. The page should just render its content and not "decide" anything else and whatever is handling the rendering of the url being request should handle what template gets used to wrap the content of the page. It gets tricky when you have multiple content areas. Master pages solves that issue while creating another. I am SURE there's a better answer. I have some ideas, just not enough hours in the day. :(

  • Good to hear about the inventor of the MasterPage.

    I love master page. It changed the way we develop older asp.net application with more effort.

  • what should i do ?
    I am making a website in Asp 2008 and I want to specify two buttons on the master page which are back page(should be going on back page)and Next page(should be going to next page)in all aspx page of my web site so please help me ang tell me the exact code which can easily work on my whole website by masterpage.

  • @Aejaz: I recommend you ask this question on the ASP.NET forums: http://forums.asp.net/139.aspx

Comments have been disabled for this content.