Customizing Application Master Pages – part 5 of 6

Introduction

This is the fith article in a six-part series on ASP.NET Master Pages and SharePoint.

  1. Introduction to Master Pages.
  2. Examining the out of the box Master Pages in SharePoint.
  3. Developing a custom Master Page for SharePoint.
  4. Deploy a Master Page for a production ready system.
  5. Customizing the Application.master Page.
  6. Incorporating a Master Page into a SharePoint site definition

In this series we have discussed master pages and we have shown how to customize a master page. Before we finish up the process (i.e.: incorporating master pages into a SharePoint site definition), I would like to diverge and talk about a frustrating subject – application master pages. Customizing application master pages is a little different than other master pages within SharePoint. Thus, I wanted to break this out into its own article to describe the subtle complexities of them and why they exist.

What is the application master page?

The application master page is the master page for application pages (also called layout pages). Thus, to answer the question “what is the application master page?”, we will discuss what an application page is. In previous articles we discussed how SharePoint web pages are a mix of templates and content data from the database. This combination is merged behind the scene and the end user sees the page. This gives us the ability to create custom pages on the fly. However, there are some pages in SharePoint that are static and used across all web applications, site collections and sites. These pages are stored in the 12 hive and are not dynamically generated with content from the database (even though they might have webparts or user controls on them). These pages are usually used for setting or admin pages. A good example is the site setting page of your site. There is an easy way to tell if a page is an application page: it will contain the word “_layouts” in the url.

Most articles or posts on how to customize SharePoint web pages ignore the fact that these application pages exist. The reason is that the argument can be made that only adminstrators can access these pages. Well… that can be true in certain situations, but it is all about how the site is set up out of the box. If you don’t take the necessary steps to make sure that application pages don’t show up, then they will. A good example of this is the search page (I am talking about the site search page, not the Search Center). When you do a search in SharPoint and the search scope is set to the current site, then SharePoint will display the results on a search page that is an application page. Thus, the end user will see an application page in this instance. So, as you can see, it is important to customize the application master page unless you remove all references to all application pages that the end user of the system might see. This is very important if you are trying to customize an entire portal to change the look so it doesn’t look like a SharePoint site.

The out of the box application master page can be found at: %Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS.

Microsoft’s recommendations for customizing application.master

According to this support site: http://support.microsoft.com/kb/944105 – there is two ways to modify/customize the application.master page.

  • Modify the application.master page in the 12 hive – Now… if you have been following this series of articles (or any other best practice article about SharePoint), then you will know you are NEVER suppose to modify files in the 12 hive. Other than the obvious issues this causes, including breaking the best practices Microsoft lays out, it also means we have to have the same application.master page for all web applications of a server. This means we can’t have two web applications on a server that have different look and feels.
  • Create a custom layouts folder – In my opinion this is a maintenance nightmare. You are copying your entire layouts folder to do this – not just the things that deal with application master pages. This seems like an extreme way to do something that I do not recommend.

For the reasons listed above, I don’t particularly agree with either of these recommendations.

Luckily others in the SharePoint community agree with my thoughts here and a common solution has been introduced throughout the SharePoint community. The solution is to implement custom HttpModules.

This approach is a non-supported approach, but the SharePoint framework leaves us little options. And, the “supported” approaches above seem to do more damage than good, so I can live with non-supported for now.

HTTP Modules

Http modules intercept page requests and allow custom code to run before the page actually renders. Thus, we can intercept the request and check if it is an application page. Then we can change the master page reference dynamically as the page renders.

Note: I originally learned the steps below from this blog by David Wise – http://www.sharepointblogs.com/dwise/archive/2007/01/08/one-master-to-rule-them-all-two-actually.aspx . I would like to thank David to allow me to use his steps in this article posting. David would also like to give credit to K. Scott Allen whom he originally got the dynamic replacement of master pages idea for regular asp.net applications.

Step 1 – build the project

  1. Open Visual Studio
  2. Create a New Project
  3. Choose a Class Library project (for this walkthrough I am referring to a C# class library, but the steps are the same for other types)
  4. Call it ApplicationHttpModule
  5. Rename Class1 to ApplicationMasterModule
  6. Change the code in ApplicaitonMasterModule to look like this:
  7. using System;
    using System.Web;
    using System.Web.UI;
    using System.IO;

    namespace ApplicationHttpModule
    {
    public class ApplicationMasterModule: 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 = “/_layouts/MasterPages/Custom.master”;
    }
    }
    }
    }

    public void Dispose()
    {
    }
    }
    }

  8. Sign the project – this is needed to add the dll to the GAC
    • Right click on the ApplicationHttpModule project and go to the properties
    • Go to the “Signing” link on the right side
    • Click the checkbox to “Sign the assembly”
    • In the “Choose a strong name key file” dropdown, choose “<New…>”
    • Enter a “Key file name”.
    • Uncheck the “Protect my key with a password” checkbox
    • Click “Ok”
  9. Build the project
  10. Place the dll in the GAC
    • If you built in Debug mode then the dll will be at: <project path>/bin/debug/ApplicationHttpModule.dll
    • Drag the dll (do not copy and paste) into the GAC: C:\Windows\assembly

Step 2 – Register the module

  1. Find the web config for your site. If you did not specify a path when you created your web application then this is located at C:\Inetpub\wwroot\wss\VirtualDirectories\<port>. If you did specify a different path and don’t remember where it is, the best way to figure it out is to go into IIS, find your website, go to the properties, click on the “Home Directory” tab. Your path will be in the “Local path” text box.
  2. Add this into the web.config file within the “httpModules” section

<add name=”CustomApplicationHttpModule” type=”ApplicationHttpModule.ApplicationMasterModule, ApplicationHttpModule, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e04811459cf7ea00″ />

Note a few things:

  • Type=<class name including namespace>, <name of assembly>
  • PublicKeyToken – this can be found by going to the dll in the GAC (C:\Windows\assmebly), then right click and look at the properties of the dll.

Step 3 – Put a custom master page in the layouts folder

In Step 1 we told the code to look for the master page in /_layouts/MasterPages/Custom.master. Thus, we need to actually have a master page there.

  1. Copy the application.master from %Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS
  2. Create a new folder called “MasterPages” under %Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS
  3. Paste the application.master page in the newly created MasterPages folder
  4. Rename the application.master page in the MasterPages folder to Custom.master

Step 4 – Make changes to the Custom.master

Now that you have built an HttpModule to redirect to the Custom.master page you can customize your Custom.master page however you want. But, you still have to be careful about keeping the content place holders around per the articles I have been writing in this series.

Be Careful

Just like the regular SharePoint master pages you must still be careful when you start modifying application master pages. Here are a couple of things to make sure you do:

  • Don’t remove content place holders. The pages that implement the application master page assume these content place holders are there. So, any content place holder from application.master must be in your custom application master page. If you are sure you have a content place holder that is not needed, then don’t remove it – just wrap it in a tag and turn the visible property to false.
  • You can’t have a search control on the application master pages. I am not sure of the reason for this, but you can’t have the out of the box search control on the application master pages.
  • Some of the application pages are actually formatted incorrectly. Thus, when you build a custom application master page you could inadvertently mess up an out of the box application page. This can happen even if your application master page is formatted perfectly. Please read my blog post on this subject for more information: http://greggalipeau.wordpress.com/2008/07/30/custom-applicationmaster-working-around-microsoft-bugs/
  • Do not use this method if your install has the SSP on the same server as the main SharePoint application. There has been reported issues of the SSP having issues with this approach because the system master pages they use have a different setup.

Conclusion

This is not as much of a conclusion, as it is a plea to the developers at Microsoft who are creating the next version of SharePoint. Please make sure we have a clear path to change application master pages. Hopefully the highly anticipated 14 hive will help with the current situation.

Twitter Digg Delicious Stumbleupon Technorati Facebook Email
  • lovemossnot
    Thank you, great post...

    ps: SharePoint love baby!!
  • fengji
    this is very good article,

    however, when I follow all the instruction and run VS debugging model by attaching to W3WP process, I have the following issues

    1. page always return to null from HttpContext.Current.Handler

    2. VS doesn't always catch the code hitting when IE is launched

    any suggestions will be very appreciated

    thanks,

    Michael
  • arpug8
    I am having the same issues as fengji. The page object comes as null or it doesn't hit the breakpoint at all. I did deploy the assemply to GAC & updated the web.config file too. Is there anything else which I am missing?
  • Very good explanation and post. Unfortunately I was not able to get it working with the shown example of code here.

    It took me some time to figure out the GAC copy of DLL to this c:\windows\assembly folder. After struggling for two hours I worked through code and server configuration.

    My development Sharepoint 2007 is ready and the http module working fine. This is very good solution to solve the application.master issue. My masterpages were so custom that users are confused when uploading or change settings without the correct application.master template.

    Thank you for showing me the way to a solution ;-)
  • httprab
  • Brian
    I used your http module concept and it seemed to work great. But now I am noticing an object failing to initialize error when using the people picker. The validate user check throws a javascript error too.
  • manu
    Hi Greg,
    Will such customization void warranty on MOSS?

    Regards,
    Manu
  • ggalipeau
    That is an interesting question Manu. In the reference I gave to the Microsoft "suggestions" on how to customize the application master page (which I do not support), they say that one way is to modify the file in the 12 hive. In my mind, that should void the warranty because you are not suppose to modify 12 hive files.
    So, the approach I am suggesting is to avoid doing that. Thus, I believe this is a safter approach to still stay in the guidelines of your SharePoint warranty. Because, you are not modifying anything out of the box, you are leveraging the code to change the master page.
    Anyways, I don't know of any official statement from Microsoft about this, but I think this is the safest approach to modify the application master while still staying in the guidelines of how Micorosoft tells us we can customize SharePoint.
  • Mike
    I've spent the the past 2 months architecting and preparing for our Moss implementation. To this point, I've relied on a custom theme/css because of this issue alone. This is by far the best solution I've seen for addressing this headache. Thank you for posting this article.
  • SP Techie
    Excellent Article and your whole series of 6 Part is very nice.... But one concern for current article had you find any work around to apply master pages on applications if one have SSP and SP Server on same webapplication....
  • Some issues with search controls on application.master:

    Their OnPrerender events register search.js, which overrides the ShoWhideGroups JS function used on ViewEdit pages (that one was fun to debug...)

    They apparently may break Workflows: http://clintcherry.spaces.live.com/Blog/cns!AEC...
  • Dhawal Mehta
    Hi Greg,
    Thanks for the such a wonderfull article.

    We have implemented this for our application, but it is giving us an error for some of the pages
    -on the people.aspx
    -it also give us the errors while we are trying to create new column in the lists
    etc.
    Appreciate your any suggestions.

    Thanks,
    Dhawal
  • Deepanshu
    Hi Greg,
    Really good article, which I was searching.
    Just one issue I have faced, when I have used Sharepoint Designer to edit the content of CustomApplication Master.

    At the last I have found that this is the issue, and use Visual Studio to edit the master page.
  • FArrukh
    Hi Greg, Very good article, as it helps me a lot. I am just trying to replace the simple.master(default master for error.aspx) with my custom master. Do you have any idea that is it possible. If yes then can you please guide me with some thing related to that.
  • ggalipeau
    Hi FArrukh,
    I think you could implement the same technique as this article. Build a module that checks for that particular master page and switch it out. I haven't tried it with simple.master, but that should work just fine.
  • panoone
    With regards to registering the module at "Step 2 - Register the module" it's worth mentioning which particular box in the farm people should be on. As a newbie I remember tearing my hair out making changes to the config file (there are dozens and they exist in several locations) only discover it was the wrong one. Small wonder my chanegs weren't taking effect. :)

    In the case of front-end web applications (as opposed to Central administration) the changes are made on _any_ Web Front End. SharePoint then picks these changes up and will migrate them to other front ens (if they exist). This is also true for registering safe controls or any other customisations you might need to register.
  • Thanks for the info, Ive been wanting to change these.

    I do have a problem, Im not all that great with Visual Studios, and am using 2008 version

    When I try to build the project, I get several errors around line 30 and 32

    Unexpected character and several otheres revolving around these lines.

    Do you think you can help?
  • ggalipeau
    Hey David,
    It is hard to say without more information. I don't know what line 30 and 32 are in your code. I might be able to help out, but I would need to know the exact error and what line of code it is happening on.
  • richl
    I really like this approach but I would like a little more clarification. I'm not sure I understand the issues with the SSP. I think that you might instead be refering to the SSP being installed on the same web application. Http Modules are deployed per web aplication so if you have a separate web application for your SSP you would simply not install the Http Module there. Would this alleviate the issue?
  • ggalipeau
    Yes Ricl, you are correct. I don't know why I typed same server. I should have said the SSP shouldn't be on the same web application.
  • Hi Greg,

    Excellent article, as always!

    If we had multiple web applications running, could we not check the top-level domain programatically and then use the appropriate customised master page? Would that get around the SSP issue?
  • ggalipeau
    I think that would work Peter. I'll have to give it a shot. Good suggestion.
  • Jamie
    Excellent article, thanks Greg!

    I have seen this question come up many times and there was never a clear direction given by MS. This is by far the most elegant way to customize application.master.
blog comments powered by Disqus