MOSS 2007 – Implementing the Custom Application.Master Page using HTTPModule

One of the first question you may ask is why we need to customize the application.master. In many cases, organizations would like to have common branding experience while browsing the SharePoint sites regardless of end users are accessing the colloboration list pages, content pages, or system pages. Personally I would love to keep both application.master and custom default.master page separate to easily differentiate system pages with the user pages. But, in the real world, it may not be possible.

Before we start customizing the application.master, it is important to note that Microsoft has published the KB article for the application.master customization best practices – http://support.microsoft.com/kb/944105

I would not recommand to use this method because both methods will clutter the 12-Hive directory with multiple copies of LAYOUTS directory. Here is the blog entry raising same concerns as I have customizing the LAYOUTs directory. http://greggalipeau.wordpress.com/2008/06/19/customizing-applicationmaster/

Recently I was involved in the customizing the application.master and I have found one of the excellent SharePoint tricks to customize application.master using HTTPModule. Simply loved the idea of intercepting the aspx call in the ASP.NET pipeline and replace the MasterPageFile property of the file with the custom application master page. This is not only slick method but will make future SharePoint environment upgrade more smoother process.

My step by step solution is based on this blog. Although I have added and clarified many more steps to document complete solution, full credit goes to this blog author. http://vspug.com/dwise/2007/01/08/one-master-to-rule-them-all-two-actually/

Step – 1: Organize Visual Studio Project Structure
Creat a Visual Studio Project Structure based on Class Library template – “MyOrg.SharePoint” and create the 12-Hive directory structure. Create a Feature Directory – “CustomApplicationMasterPage”. Please note that this will be used as a feature name.

Step – 2: Create Custom Application Master Page
Create custom application master page (e.g. CustomApplication.master in following sample code) based on the OOB Application.Master page in the feature directory. OOB master page is located at the 12\TEMPLATE\LAYOUTS. While working on the custom application master page, make sure to keep all the content placeholdrs as they are required by most of the system pages. If you don’t need any content place holders, wrap the place holders in the hidden ASP.NET panel control.

Step – 3: Add the Features.xml and Elements.xml in the “CustomApplicationMasterPage” feature

Add in Features.xml

   1:  <?xml version="1.0" encoding="utf-8"?>
   2:  <Feature Id="2CA62995-55B3-43bd-AED4-7777577ED5F8"
   3:           Title="Custom Application Master Page"
   4:           Scope="Site"
   5:           Version="1.0.0.0"
   6:           Hidden="FALSE"
   7:           DefaultResourceFile="core"
   8:           xmlns="http://schemas.microsoft.com/sharepoint/">
   9:    <ElementManifests>
  10:      <ElementManifest Location="Element.xml" />
  11:      <ElementFile Location="CustomApplication.master" />
  12:    </ElementManifests>
  13:  </Feature>

Add in Elements.xml

   1:  <?xml version="1.0" encoding="utf-8"?>
   2:  <Elements Id="8C18368A-D697-4c2c-A57A-4D8E50785D3C" xmlns="http://schemas.microsoft.com/sharepoint/">
   3:    <Module Name="CustomApplicationMasterPage"
   4:          Url="_catalogs/masterpage"
   5:          Path=""
   6:          RootWebOnly="False">
   7:      <File Url="CustomApplication.master"
   8:            Type="GhostableInLibrary" IgnoreIfAlreadyExists="FALSE" >
   9:        <Property Name="ContentType"
  10:                  Value="$Resources:cmscore,contenttype_-9masterpage_name;" />
  11:        <Property Name="PublishingPreviewImage"
  12:                  Value="" />
  13:        <Property Name="Description"
  14:                  Value="Custom Application Master Page"/>
  15:      </File>
  16:    </Module>
  17:  </Elements>

Step – 4: Create a new HTTP Module
Add the new class in the class library – ApplicationMasterPageHTTPModule.cs

   1:  using System;
   2:  using System.Web;
   3:  using System.Web.UI;
   4:  using System.IO;
   5:  using Microsoft.SharePoint;
   6:  
   7:  namespace MyOrg.SharePoint.HTTPModules
   8:  {
   9:      /// <summary>
  10:      /// Application Master Page HTTP Module to intercept the system master pages and replace the
  11:      /// out of box sharepoint application master page with the custom application master page
  12:      /// </summary>
  13:      public class ApplicationMasterPageHTTPModule : IHttpModule
  14:      {
  15:          /// <summary>
  16:          /// Init method
  17:          /// </summary>
  18:          /// <param name="context"></param>
  19:          public void Init(HttpApplication context)
  20:          {
  21:              context.PreRequestHandlerExecute += new EventHandler(context_PreRequestHandlerExecute);
  22:          }
  23:   
  24:          /// <summary>
  25:          /// 
  26:          /// </summary>
  27:          /// <param name="sender"></param>
  28:          /// <param name="e"></param>
  29:          void context_PreRequestHandlerExecute(object sender, EventArgs e)
  30:          {
  31:              Page page = HttpContext.Current.CurrentHandler as Page;
  32:              if (page != null)
  33:              {
  34:                  page.PreInit += new EventHandler(page_PreInit);
  35:              }
  36:          }
  37:   
  38:          /// <summary>
  39:          /// Swap the master page in the page preinit method to override SharePoint processing
  40:          /// </summary>
  41:          /// <param name="sender"></param>
  42:          /// <param name="e"></param>
  43:          void page_PreInit(object sender, EventArgs e)
  44:          {
  45:              Page page = sender as Page;
  46:              if (page != null)
  47:              {
  48:                  // Is there a master page defined?
  49:                  if (page.MasterPageFile != null)
  50:                  {
  51:                      // only change the application.master files as those are the offenders
  52:                      if (page.MasterPageFile.Contains("application.master"))
  53:                      {
  54:                          //Application Master Page Swapping
  55:                          // Method - 1 - change the page's master page file property to the master page gallery.
  56:                          // This method works fine but somehow not working for the User's Personal Sites..
  57:                          //page.MasterPageFile = "/_catalogs/masterpage/CustomApplication.master";
  58:  
  59:                          // Method - 2 - retrieve the current site relative URL and then append the master page gallery URL
  60:                          using (SPSite site = new SPSite(SPContext.Current.Site.Url))
  61:                          {
  62:                              using (SPWeb web = site.RootWeb)
  63:                              {
  64:                                  string strUrl = web.ServerRelativeUrl + "/_catalogs/masterpage/CustomApplication.master";
  65:                                  page.MasterPageFile = strUrl;
  66:                              }
  67:                          }
  68:                      }
  69:                  }
  70:              }
  71:          }
  72:  
  73:          /// <summary>
  74:          /// Dispose Method
  75:          /// </summary>
  76:          public void Dispose()
  77:          {
  78:              // Do nothing but it is required for the HTTP module...
  79:          }
  80:      }
  81:  }

Step – 5: Deploy the Custom Application Master Page and HTTP Module
Deploy both Visual Studio Project as Solution Packagess to deploy the master page to the file system as a feature and HTTPModule to the GAC. Make sure Visual Studio assembly is compiled with the signed key because we need to deploy the HTTPModule to the GAC. I typically use the WSP Builder to deploy the solution package. You are free to use the different methods to deploy the masterpage as a feature and HTTPModule in the GAC.

Step – 6: Update Web.Config file to specify HTTPModule
Chnage the web.config file for the web application where you want to activate the custom master page.
Remember that type is in the format of “namespace.classname, assemblyname, version, culture, publickeytoken”

   1:  <httpModules>
   2:        <clear />
   3:        <add name="ApplicationMasterPageHandler" type="MyOrgName.SharePoint.HTTPModules.ApplicationMasterPageHTTPModule, MyOrgName.SharePoint, Version=1.0.0.0, Culture=neutral, PublicKeyToken=930fd3b11e8621be"/>
   4:  </httpModules>

Step – 7: Activate the feature on the root site collection

   1:  C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\BIN>stsadm.exe -o activatefeature -name "CustomApplicationMasterPage" -url http://TeamSite/ -force

Please remember to test all the links on the site settings page and as many as OOB system pages to verify that custom application master page works as intended.

Enjoy…

Advertisements
This entry was posted in SP2007 DEV. Bookmark the permalink.

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s