The AlternateCssUrl and saving a site as a template

Two weeks ago on a customer project we ran into a weird problem. We created a site, modified it a little bit, saved it as a template and created a new site based on it.
Everything seemed to work fine, but in the newly created site the application pages in the _layouts directory weren’t displayed properly.

The error that we found in the ULS logs was:

System.Web.HttpException: No http handler was found for request type 'GET'  
at System.Web.HttpApplication.MapIntegratedHttpHandler(HttpContext context, String requestType, VirtualPath path, String pathTranslated, Boolean useAppConfig, Boolean convertNativeStaticFileModule)   
at System.Web.HttpServerUtility.Execute(String path, TextWriter writer, Boolean preserveForm)

The only customization on the site was a custom design (master page and stylesheet) so we figured that it had to have something to do with that design. We did some debugging (to be honest, my colleague Robbie Coenmans did the debugging) and found out that the problem had to do with the AlternateCssUrl property. In our solution the AlternateCssUrl was defined in the ONET.XML file of the site definition.
It turns out that during the provisioning of the site the stored procedure proc_UpdateTpWebMetaData gets fired four times. If the AlternateCSSUrl value is stored in the ONET.XML file, when the proc_UpdateTpWebMetaData stored procedure fires for the fourth time the AlternateCssUrl value gets copied to the AlternateHeaderUrl property as well. Because of this the header starts displaying the contents of the stylesheet.

The solution is simple: don’t store the AlternateCssUrl in the ONET.XML file. There are two straight forward alternatives:

  • Setting the AlternateCssUrl in for instance a feature receiver by assigning a value to the SPWeb.AlternateCssUrl property. If you choose this approach you will have to get the SPWeb.AlternateHeader to an empty string in the feature receiver.
  • Setting the value of your own stylesheet in the CssUrl property of the master page

What’s the best solution depends on your scenario. Using the SPWeb’s AlternateCssUrl property gives you more flexibility, while using the master page’s CssUrl property means that you only have to set it once and you don’t have to run any code to set it.