ASP.NET has improved dramatically with v2.0, to the point of making ASP.NET v1.x look like a bit of a hack job. One of the great improvements covered in this entry is the addition of Master Pages.
Master Pages allows you to define a template layer (and coupled back-end code) to be used on content pages using that master page. For instance a master page might define all linked scripts, CSS, and script blocks, along with a navigation header and footer that exist on all pages on the site (or at least those pages using the master page). An ugly example sits a subdirectory away -- at the root pages for yafla, where the navigation header and footer exist in a master page.
ex. MasterPage.Master
<%@ Master Language="C#" AutoEventWireup="true" CodeFile="MasterPage.master.cs" Inherits="MasterPage" %>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>My Master Page - This Title Will Be
Overridden
By the Title Element
In Content
Pages</title>
<link rel=stylesheet type="text/css"
href="stylesheet_in_all_pages.css" />
</head>
<body>
<h3>This is my universal
header!</h3>
<form id="form1" runat="server">
<div>
<asp:contentplaceholder id="ContentPlaceHolder1"
runat="server">
</asp:contentplaceholder>
</div>
</form>
<h3>© 2015 Robot
Inc.</h3>
</body>
</html>
You can also define code for the various events in the master page,
which will run on the pertinent content pages.
Content pages then define what will fill the content block (or multiple content blocks as the case may be), and of course implement their own back-end code.
<%@ Page
Language="C#" MasterPageFile="~/MasterPage.master"
AutoEventWireup="true" CodeFile="Default2.aspx.cs"
Inherits="Default2"
Title="This is my overridden title" %>
<asp:Content ID="Content1"
ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
This is my content for this content page
</asp:Content>
Very trivial.
Of course this isn't the only way that this result could be achieved -- I could derive from a page object that imperatively creates all of the common elements, or I could use multiple user controls that defined the basics, but neither of those solutions, or similar workarounds, seem as elegant as master pages to me. There are equal or superior solutions in other platforms, however I'm sticking to the topic of ASP.NET in this entry so they are irrelevant.
The one hiccup I faced in the use of master pages was my desire to have meta keywords (which exist in the header) vary by page, despite the fact that the meta keyword is basically dead. I want the keywords to vary, similar to the way I can declaratively override the title in content pages. Unfortunately this required some code workarounds, which in my case included adding a public property on the master page, MetaKeywords, with a default keyword list, which I then added to the header in the PreRender stage of the master page (the following example is simplified for demonstrations sake, however a real implementation would scan the headers to ensure that the pertinent header doesn't already exist before adding it).
public string MetaKeywords = "default keywords";
protected void Page_PreRender(object
sender, EventArgs e)
{
SetMetaValues(this.Page.Header,
"keywords", MetaKeywords);
}
public static void
SetMetaValues(System.Web.UI.HtmlControls.HtmlHead head, string
name, string content)
{
HtmlMeta metaValue =
null;
metaValue = new
HtmlMeta();
metaValue.Attributes.Add("name",
name);
metaValue.Attributes.Add("content",
content);
head.Controls.Add(metaValue);
return true;
}
Any content page could access its Master property to set the property, and the meta keywords would be appropriately set when the page was rendered. By using the MasterType directive the Master property of the page automatically resolves to the proper type.
Unfortunate that a declarative mechanism wasn't added for arbitrary header elements in the content pages.
The goal of master pages, of course, is to avoid the scourge of copy/paste coding: Unnecessarily having a single line of code in multiple places is an evil in software development, yet it's often the easy, thoughtless solution, yielding volumes of redundant code that invariably diverges and causes maintenance problems for years to come, reducing the quality and agility of the codebase.
I despise copy/pasted code. It truly is a peeve of mine.
When analyzing the quality of code bases, one of the first checks I usually perform is to use one of the automated code duplication checkers (available for most languages). There is a remarkable correlation between code duplication rates and code quality.
The benefit of master pages isn't limited to a single master template, however, but instead you can actually layer multiple master pages. For instance on the yafla site the services category pages use the Services master page, adding additional service specific back-end code and layout, while it uses the web site wide master page. It mirrors the templated way in which many websites are developed.
The downside of layered master pages is that the GUI team apparently didn't have time to build multiple level parsing into the web designer -- wherever you're working on content pages that have more than one level of master pages above them, you are limited to the source view. To attempt otherwise yields a "Design view does not support creating or editing nested master pages. To create or edit nested master pages, use the Source view." Unfortunate, but not deadly.
As an aside, one of the big improvements with ASP.NET v2 is better support of per-page development, similar to classic ASP and competitors such as PHP. This solves one of the primary problems many had with ASP.NET, which is that they didn't prefer to work within the "web site as a monolithic application" model that ASP.NET v1 pretty much enforced. Strangely the improvements bringing these benefits has been met with little fanfare, and few are even aware of it. I do plan on doing a feature on it shortly.
Tagged: [Software Development], [Programming], [Software-Development]