Mike Hodnick's Blog

Setting SharePoint Web Master Pages Programmatically

For "Publishing" sites In Microsoft Office SharePoint Server, you have the ability to specify a master page that all pages in the web should use:

SelectMaster

Optionally, you have the ability to inherit the master page of the parent web (if a parent exists):

InheritMaster

Setting these two values programmatically is easy, but not necessarily intuitive.

First, to set the master page, it is as easy as setting the value of an SPWeb object's CustomMasterUrl property to the server-relative path of the master page:

SPSite site = new SPSite("http://myserver");
SPWeb web = site.OpenWeb("/some/web/path");
web.CustomMasterUrl = "/_catalogs/masterpage/MyCustomMasterPage.master";
web.Update();

There is also a property named MasterUrl on an SPWeb object. MasterUrl will set the master page of all system pages in the web (e.g. list pages, administrative pages, etc). You can basically accomplish the same thing for system pages by setting this property's value to a master page path.

The "inheritance" setting is a little more tricky. There is no property on an SPweb object where you can set whether or not the web should inherit its master page from the parent. Using Reflector, I chose to reverse-engineer the system web page in SharePoint where these properties are set. The system page is located at /_layouts/ChangeSiteMasterPage.aspx and inherits from Microsoft.SharePoint.Publishing.Internal.CodeBehind.AreaChromeSettingsPage, which is in the Microsoft.SharePoint.Publishing.dll assembly.

In the "OK" button click event handler, eventually a call is made to update the inheritance value on a class named InheritableStringProperty, which is a public, abstract class. There are three classes that derive from it - one of which we are interested in, named CustomMasterUrlProperty:

hierarchy

CustomMasterUrlProperty is marked as internal, so we can't use it directly. But upon inspecting it further in Reflector, I came across a property that returns the name of an entry stored in an SPWeb property bag:

reflector

If you've worked a lot with SPWeb property bags, then you'll probably guess that the name "__InheritsCustomMasterUrl" looks like a typical "Property Bag" entry in an SPWeb.

If we open up an SPWeb's property bag in PowerShell, we can see that the __InheritsCustomMasterUrl entry exists:

C:\> $s = new-object microsoft.sharepoint.spsite("http://lyra")
C:\> $w = $s.OpenWeb("/sub")
C:\> $w.AllProperties

Name                           Value
----                           -----
vti_defaultlanguage            en-us
vti_associateownergroup        3
vti_associatevisitorgroup      4
__InheritsMasterUrl            True
vti_associatemembergroup       5
__DocumentsListId              5134728e-a8a5-40bb-adc7-08a60f01ec2a
__PagesListId                  9aacb3d7-f4db-4874-b51b-9ab31cb7c286
__PublishingFeatureActivated   True
__InheritWebTemplates          True
vti_associategroups            5;4;3;7;8;9;10;11;12
__NavigationShowSiblings       True
vti_approvallevels             Approved Rejected Pending\ Review
NavigationPropertiesSet        True
__ImagesListId                 bd76f653-c89f-4d91-b10e-740daff56750
__IncludeSubSitesInNavigation  True
vti_extenderversion            12.0.0.4518
__InheritsCustomMasterUrl      True
__PageLayouts                  __inherit
__WebTemplates
__InheritsAlternateCssUrl      True

Note that you'll need to access the SPWeb's AllProperties property (rather than the "Properties" property) in order to find the "hidden" property bag entries.

So, to finish things off, setting the master page inheritance value is as simple as updating the property bag entry's value. Note that the value of __InheritsCustomMasterUrl is a string:

SPSite site = new SPSite("http://myserver");
SPWeb web = site.OpenWeb("/some/relative/path");
web.AllProperties["__InheritsCustomMasterUrl"] = "False";
web.Update();

Enjoy.