in

SharePoint Blogs

The Best Place for SharePoint-related Blogs

David Wise's Sharepoint blog

One .Master to Rule Them All (Two, actually)

One of the biggest annoyances with Sharepoint 2007 is the quirky things you have to do in order to customize a site.  This is especially true when it comes to custom master pages.  You create a stunning master page in Designer, configure the site to use it, then load the page and wait to bask in the glory. Lo and Behold!  It worked!  Job done, go grab a beer ... but you better drink it fast because Sharepoint has a nasty surprise in store for you.  That master page only works on the content pages in your site.  System pages  (i.e. viewlists.aspx) will refuse to use your amazing Master page.  All that work is wasted on a half complete user experience.  Or is it?

Why is it not doing what I tell it to do?
This is because those system pages are hard-wired to use a different master page (application.master) .  To make matters worse, you only get one application.master for everywhere.  You could go modify this file, but be careful: changes to this will affect ALL pages based on that master, everywhere.   It's not something that can be customized on a site-by-site basis.  To make matters still worse, Microsoft *will* update this file in upcoming patches, so odds are good that it will break on you sometime in the future, and likely with little warning.

Ok, so what's the skinny?
Create a custom httpModule and install it on your Sharepoint site that remaps which .Master pages your pages use.  If you aren't familiar with httpModules, fear not, they are extremely simple.

The httpModule sits in the middle of the http request processing stream and can intercept page events when they initialize.  The pages load up and say "I'm going to use application.master", to which your module replies "not on my watch, buddy" and not so gently forces the page to use the Master page of your choice.

The Gory Details
(this assumes that you already have the aforementioned Nifty Master Page created.  If not, please search Google for any of the hundreds of tutorials on how to do this)

Prepare your Master Pages
You will need two .Master pages.  One to replace default.master and the other to replace application.master.  It is very important that when you are creating these pages that you include all of the ContentPlaceHolders that exist in the .Master page you are replacing.    Throw any ContentPlaceHolders that you are not using in a hidden DIV at the bottom of the page - but before the closing FORM tag (the only exception to this seems to be "PlaceHolderUtilityContent" which goes in after the closing form tag).  Once in place, you can use the normal Master Page options in the UI to select the default.master replacement.

Second, be sure to remove the Search Control from your Application.Master replacement.  The reason for this is that the search box does not normally appear on system pages and will cause an error during rendering.  

You can probably simplify this a bit by using nested master pages, but I haven't had a chance to look into that yet.

Step 1 - Create the httpModule
Create a new Class Library project in Visual Studio and start with the code below.  So simple, even a manager could do it (maybe).  Obviously, you will have to change the path to match your environment.  Oh, and sign the assembly as well.

using System;
using System.Web;
using System.Web.UI;
using System.IO;

public class MasterPageModule : IHttpModule
{
   public void Init(HttpApplication context)
   {
      context.PreRequestHandlerExecute +=
new EventHandler(context_PreRequestHandlerExecute);
   }
   void context_PreRequestHandlerExecute(object sender, EventArgs e)
   {
      Page page = HttpContext.Current.CurrentHandler as Page;
      if (page != null)
      {
         page.PreInit +=
new EventHandler(page_PreInit);
      }
    }
    void page_PreInit(object sender, EventArgs e)
   {
      Page page = sender as Page;
      if (page != null)
      {
         // Is there a master page defined?
         if (page.MasterPageFile != null)
         {
            // only change the application.master files as those are the offenders
            if (page.MasterPageFile.Contains("application.master"))
            {
               page.MasterPageFile =
"/_catalogs/masterpage/MyCustom.master";
            }
         }
      }
   }

   public void Dispose()
   {
   }
}

Note the path above: that is required so that all pages can find the Master page as not all pages are running from the site context

This is a simplified example but you can see the potential here.  With this in place, YOU control the horizontal and YOU control the vertical.  Or, for a more modern reference, YOU decide who gets the red pill and who gets the blue pill.

Build it and then throw the DLL in the /bin folder in your Sharepoint site root (usually something like \Inetpub\wwwroot\wss\VirtualDirectories\80\bin).  You may have to create the \bin folder if one is not there.  Once you have it working the way you want, you will need to sign it and move it to the GAC, but this works for getting started.

Step 2 - Register the httpModule
Another easy step - throw in the bolded line below in your web.config file at the bottom of the httpModules section.  This section should already be there.

<httpModules>
... stuff you dont care about ...

<add name="MyHandlerTest" type="MasterPageModule, MasterPageHandlerModule, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6bdb1331dfc11306"/>
</
httpModules>

Step 3 - Load the Page
Navigate to the home page of your site.  That should work normal as it is using the normal Sharepoint Master page logic.  Now go to a System page, like 'Documents' , 'Lists' or 'Pictures'.  These should now be using your Master page

If you've followed the this tip you will actually be able to see the real error, if any, when you load the page.

Step 4 - Go get that beer
Do you really need instructions for this?

Special  thanks to K. Scott Allen for his post showing how to change the .Master page using an httpModule.  You will notice that the code above bears an amazing resemblance to his.

 

3/1/2007 - UPDATE!
In response to comments, I have updated these instructions, in particular, I have added the "Prepare your Master Pages" section that addresses most of the issues encountered in the comments.

Also, do not use this method if your sharepoint install has the shared Service Provider (SSP) installed on the same web application as your main sharepoint environment.  The system pages used by the SSP do not work properly when their master page is replaced like this.  I'm sure there is a logical reason why, I simply haven't had the time to dive into it.

Comments

 

Dreamrift » Useful SharePoint References said:

Pingback from  Dreamrift &raquo; Useful SharePoint References

July 19, 2007 11:39 AM
 

jason swan said:

Daniel:

Any idea why I might be getting "could not load file or assembly" errors no matter what?

I have followed your instructions above several times and used sn.exe to dig out the public key of my dll.  I have also copied the dll to every bin folder related to WSS I can find, and dragged the dll into the GAC....

*sigh*.  I'm lost.  Any help would be appreciated.

August 3, 2007 3:41 PM
 

jason swan said:

follow-up to my post of despair above ... especially since I did not remember my original fix when I had to install the switcher all over again in a new VM instance.

My problem was that I had not renamed "MasterPageHandlerModule" to match the name of my .dll and had been attempting to refer to "MasterPageHandlerModule" rather than "wss_redirect".

September 18, 2007 5:45 PM
 

DavidWise said:

Jason,

Glad to hear you got it working!

October 4, 2007 6:44 PM
 

Mirrored Blogs said:

Corps: Après plusieurs discussions entre collègues et lectures sur le net sur les cas pratiques d&#39;utilisation

February 6, 2008 7:25 PM
 

Arnie Lugo said:

Hi,

I created my own custom application.master page and placed it in the /_catalog/masterpage directory as stated above, however my code continues to break on the following line:

page.MasterPageFile = "/_catalogs/masterpage/MyCustom.master";

SharePoint continues to come back with a "file not found" error.  I have tried changing the path several times to no avail.  What am I doing wrong?  By the way my class has been compiled, placed in the GAC, and I have made the proper entries in the application's web.config file.  Thank You.

April 22, 2008 4:37 PM
 

DavidWise said:

Arnie, first off, I'd suggest that you verify that your master page has been properly approved through the Content Approval mechanism.

It may also be related to how your site is authenticating.  If you have anonymous on a site but require authentication at the root, you might be seeing this as well.

You might also want to enable debugging to help ensure that the "file Not Found" error you are seeing is actually where you think it is  (http://tinyurl.com/4k3e6y).

April 23, 2008 9:27 AM
 

Arnie Lugo said:

Hi David,

I tried your suggestion and I am still getting the same error (File Not Found).  Thank You for providing the information on how to turn on Asp.NET debugging for the site, unfortunately it did not provide me with any additional information.  I am open to suggestions.  My code is as follows:

using System;

using System.Web;

using System.Web.UI;

using System.IO;

namespace HPI_Http_Intercept

{

   public class MasterPageModule : IHttpModule

   {

       public void Init(HttpApplication context)

       {

           context.PreRequestHandlerExecute += new EventHandler(context_PreRequestHandlerExecute);            

       }

       void context_PreRequestHandlerExecute(object sender, EventArgs e)

       {            

           Page page = HttpContext.Current.CurrentHandler as Page;

           if (page != null)

           {

               page.PreInit += new EventHandler(page_PreInit);

           }

       }

       void page_PreInit(object sender, EventArgs e)

       {

           Page page = sender as Page;

           if (page != null)

           {

               if(page.MasterPageFile != null)

               {

                   if (page.MasterPageFile.Contains("application.master"))

                   {

                       page.MasterPageFile = "/_catalogs/masterpage/HPhilips_Application.master";                                                                          

                   }

               }

           }

       }

       public void Dispose()

       {

       }

   }

}

Thank You,

Arnie Lugo

April 25, 2008 8:54 AM
 

Siam Sunshine said:

Nice one dave, are you planning to link Sharepoint with your photography ??

May 25, 2008 6:25 AM
 

DavidWise said:

Sorry Siam, you must have me confused with someone else.  The extent of my photography skills is creating blurry photos of family vacations.

May 28, 2008 5:10 PM
 

DavidWise said:

Arnie,  the only time I've seen this behavior was on a system that was using Content Management and required full approval for the master pages.

Just out of curiousity, what happens when you manually set a site to use your new master page via the SharePoint UI?

May 28, 2008 5:14 PM
 

James Watson said:

Hello:

This is a very good article, I am a new SharePoint developer and I did the same steps as you mentioned.

Created a Class Library Project

Use your code

Build Dll and copied it at inetput/wwwroot/.../bin

when I go back and create a site or anything, it does not change the master page with mine. It does not give any error or anything.

What do I have to do to make this http module execute? I dont think this code is being hit when I am browing the SharePoint site.

Your help is appreciated

June 4, 2008 1:32 PM
 

DavidWise said:

James,

There are a number of things it could be.  First off, is your DLL strong-named.  Secondly, did you modify the web.config for the site as mentioned in Step 2?  Lastly, are you certain you are changing the right Site?  SharePoint will create lots of sites and sometimes it may look like one directory is for the site you are working with but it is actually a different one.

Also, have you checked both the Event log and the 12\LOGS folder for errors when loading a page.  Both of those may provide additional clues.

June 4, 2008 6:09 PM
 

James said:

Hello:

You were right, I was modifying the wrong webconfig file, thanks for your help.

Now atleast I can see that its being called, i do get the following error though:

----------------------------------------------------------------------------------

File Not Found.   at Microsoft.SharePoint.ApplicationRuntime.SPRequestModuleData.GetWebPartPageData(HttpContext context, String path, Boolean throwIfFileNotFound)

  at Microsoft.SharePoint.ApplicationRuntime.SPVirtualFile.GetVirtualPathProviderCacheKey(String virtualPath)

  at Microsoft.SharePoint.ApplicationRuntime.SPVirtualPathProvider.GetCacheKey(String virtualPath)

  at Microsoft.SharePoint.Publishing.Internal.CmsVirtualPathProvider.GetCacheKey(String virtualPath)

  at System.Web.Hosting.VirtualPathProvider.GetCacheKey(VirtualPath virtualPath)

  at System.Web.Compilation.BuildManager.GetCacheKeyFromVirtualPath(VirtualPath virtualPath, Boolean& keyFromVPP)

  at System.Web.Compilation.BuildManager.GetVPathBuildResultFromCacheInternal(VirtualPath virtualPath)

  at System.Web.Compilation.BuildManager.GetVPathBuildResultInternal(VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile)

  at System.Web.Compilation.BuildManager.GetVPathBuildResultWithNoAssert(HttpContext context, VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile)

  at System.Web.Compilation.BuildManager.GetVPathBuildResult(HttpContext context, VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile)

  at System.Web.UI.MasterPage.CreateMaster(TemplateControl owner, HttpContext context, VirtualPath masterPageFile, IDictionary contentTemplateCollection)

  at System.Web.UI.Page.get_Master()

  at System.Web.UI.Page.ApplyMasterPage()

  at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

Troubleshoot issues with Windows SharePoint Services.

---------------------------------------------------------------------------------------------

It seems like it can not find the file

"_catalogs/masterpage/TestSolution.master";

When I deployed my solution, I can see this master page in master page gallery but I am not able to find any virtual directory _catalogs under any site.

How can I tell if my new master page is at its right location i.e. _catalogs/masterpage direcotry.

I have a solution, which creates a site definition template and when i use this template I can see that its using my master page and when i browse to another area within same site it was using application.master but now its giving me error.

Thanks

June 5, 2008 8:10 AM
 

DavidWise said:

the catalogs folder should be off of the root of the site collection as '/_catalogs' not a subfolder of a particular web.

Also, this folder does not appear in the 'Content and Structure' view but does appear when you are working on the site collection in SharePoint Designer.  As long as your page is getting in there and it appears in the Master Page Gallery, that should be good enough.

While you are in the Master Page Gallery, make sure that the 'Approval Status' for your new master page is set to 'Approved'.

Also, make sure you don't have a Search Control on that Master Page as it will cause errors.  That's why I recommend 2 master pages.  One for normal content pages and one for system pages (i.e. if you see '_layouts' in the url, that means it is a system page)

June 5, 2008 5:01 PM
 

Peter said:

David,

This is a great article. This is the exact problem I have with our portal site

AS you mentioned, do not use this method if your sharepoint install has the shared Service Provider (SSP) installed on the same web application as your main sharepoint environment. Most of the companies use small farm for SharePoint. We have one server for sql database and the other server for everything else.

Do you have any suggestions on how to make application master page works in this situation (SSP and web application on the same box)?

Thanks,

Peter

June 11, 2008 8:22 PM
 

Jimmy said:

Hi David!

Great stuff, if I just would get it to work. Have copied the code exactly as it says, Signed the assembly and Build the project. Transferred my .dll to the bin-folder of my site, and altered the web.config (should you use the key that you get when signing the assembly or can I use the original key from the code here?)

The error i get in eventviewer after changing the web.config is this:

Exception information:

   Exception type: ConfigurationErrorsException

   Exception message: Could not load file or assembly 'MasterPageHandlerModule, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6bdb1331dfc11306' or one of its dependencies. The system cannot find the file specified. (C:\Inetpub\wwwroot\wss\VirtualDirectories\80\web.config line 149) (C:\Inetpub\wwwroot\wss\VirtualDirectories\80\web.config line 149)

PS. The dll is named MasterPageModule.dll DS

What am I doing wrong?  Please Help!

Regards

/Jimmy

June 12, 2008 6:03 AM
 

James said:

Hi Jimmy:

The httpModule entry in webconfig shold be as follows:

<add name=<Any tag name e.g. "Test"> type=<class name, if you have a namepace as well make sure its namespace.classname>, <DLL file name>, Version=<version>, Culture=neutral, PublicKeyToken=<key that you get from DLL u created for httpModule"/>

June 12, 2008 12:41 PM
 

Peter said:

Hi David,

I followed your instruction, created a new class library. I copied the new build DLL into the bin folder under the site collection c:\Inetpub\wwwroot\wss\VirtualDirectories\mysitecollectname\bin\ folder instead of c:\Inetpub\wwwroot\wss\VirtualDirectories\80\bin folder. It looks like application.master page changed to my customized master page only for that site collection. My Central Administration Tool and other site collections still use the application.master page. That is great.

Now the system pages switched to my customized master page instead of application.master page, but it does not pick the changes in ItemStyle.xsl file I modified.

Is there any way I can force the system pages not only using customized master page but also to use ItemStyle.xsl?

Thanks,

Peter

June 12, 2008 2:44 PM
 

Jimmy said:

Thanks a lot David!

Realised that my DLL file name was wrong, changed it and the error disappeared, but when I went to a System page I got an Unknown error. After some thinking and looking at the original application.master, I realised that it was a lot diffrent than default.master (which I just took a copy of, deleted the search-field and renamed) Took a copy of the original application.master and changed it instead, and voila! .. Works like a charm now!

June 13, 2008 3:30 AM
 

Customizing Application.master « Greg Galipeau’s Weblog said:

Pingback from  Customizing Application.master &laquo; Greg Galipeau&#8217;s Weblog

June 18, 2008 8:26 PM
 

abi said:

We followed everything what you mentioned in yoru document and it worked all great problem is when we click on mysite we get error. it could be bcoz we have SSP on same server,, But is there any way to solve this problem ?? even other sites on same server also have thsi problem too.

June 25, 2008 11:58 AM
 

Peter said:

David,

I  followed everything what you mentioned in your document and it worked all great.

the problem is when I try to upload documents to document library I got the following error

The security validation for this page is invalid. Click Back in your Web browser, refresh the page, and try your operation again.

I checked the log file under 12\logs directory, there is no related entry logged there.

When I commented out the following line of code in web.config. the problem is gone.

<!--

<add name="MasterPageHandler" type="MasterPageModule, SPSMasterPageHandler, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5c0b2f6acfaf6191" />

-->  

Any idea?

Thanks,

Peter

July 7, 2008 4:50 AM
 

Mirrored Blogs said:

Corpo: Olá pessoal, Estou escrevendo este post em resposta a uma série de dúvidas relacionadas ao modelo

July 22, 2008 12:31 PM
 

Mark Dorison said:

Thanks for the great tip! I am having one problem however. The master page loads correctly on the pages it is supposed to but when I try to add a column to a list there are errors on the page. The page renders but when I fill out the form and click the 'OK' button to submit nothing happens. Disabling the module in the web.config temporarily removes the issue.

August 6, 2008 11:14 AM
 

Michael Alicea said:

David,

Great article, just one question...do i need to make a copy of application.master and default.master or do I use my customdefault.master as both?  At one point in the article it seems to read as needing 2 different master pages and at another it seems like I am using one master in 2 different locations.  Thanks.

August 6, 2008 12:46 PM
 

Hiral Shah said:

I have created the master pages and its working fine. Now, I want this to be installed on my site as an feature which can be activated / deactivated by the user. Can it be achievable ? Please reply soon

August 8, 2008 12:21 AM
 

Dn said:

Thanks! For me it works on _Layouts only (not on other application sites like List and Documents etc.)

Any ideas?

August 14, 2008 9:00 AM
 

suzana said:

Best Hotels of 5 star hotel istanbul hotel and airport hotels istanbul, which lists more than 150 quality 4 & 3 star hotels istanbul, special hotels ...

September 2, 2008 8:19 AM

Leave a Comment

(required )  
(optional )
(required )  
Add

About DavidWise

I have been writing software for over 16 years and web applications for 11 years. I have been also been elbow deep in SharePoint 2007 since Beta 2 and loving it! Currently, I work for Bennett Adelson Consulting (a Microsoft Gold Partner) based in Cleveland, Ohio.

Need SharePoint Training? Attend a SharePoint Bootcamp!

Posts (c) their respective authors. Everything else (c) 2007 SharePoint Experts