Applying a master page to a device channel
Once a device channel has been created, it can be configured to use as a different site master page rather than the default site master page. For instance, browsers targeted by a mobile device channel could display the content using the oslo master page whereas all other browsers could display the same content using the seattle master page.
The System Master Page is configured for all device channels and cannot be configured for individual device channels.
How to do it...
Follow these steps to apply a master page to a device channel:
- Navigate to the site in your preferred web browser.
- Select Site settings from the Settings menu.
- Select Master page from the Look and Feel section.
- Specify which Site Master Page to use for each device channel.
- Click on Save.
How it works...
The master page to device channel mappings are stored in the _catalogs/masterpages/__DeviceChannelMappings.aspx
file as XML within the root site of a site collection. For each incoming browser web request, this file is used by SharePoint to determine which master page to use with the content returned to the browser.
There's more...
A device channel mapping may also be configured with PowerShell or with code using the server-side object model. In this recipe, these two methods are similar. However, the .NET reflection methods used are slightly different. When an object is instantiated with reflection in PowerShell, its public properties and methods become available to the command line. However, when an object is instantiated with reflection in the .NET code, each property and method needs to be searched for before being able to access them.
Tip
The methods that provide the functionality to configure the device channel mappings are not publicly exposed in the SharePoint assemblies. As a result, we will use the .NET reflection to instantiate the objects required. It is important to note that non-public classes in the SharePoint assemblies can change between SharePoint versions and updates without notice. Using reflection tools, such as .NET Reflector (http://www.red-gate.com/products/dotnet-development/reflector/) and dotPeek (http://www.jetbrains.com/decompiler/), we can browse the assemblies to adjust the references accordingly.
Follow these steps to apply a master page to a device channel using PowerShell:
- Load the
Microsoft.SharePoint.dll
andMicrosoft.SharePoint.Publishing.dll
assemblies into the PowerShell session.[Reflection.Assembly]::LoadFrom("C:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.Publishing.dll") [Reflection.Assembly]::LoadFrom("C:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.dll")
- Get the object types for the parameters that will be used when getting the class constructor for the
MasterPageMappingsFile
object and later instantiating the object.$typeWeb = [Microsoft.SharePoint.SPWeb] $typeBool = [System.Boolean] $typeMappingFile = [System.Type]::GetType("Microsoft.SharePoint.Publishing.Mobile.MasterPageMappingsFile, Microsoft.SharePoint.Publishing, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c")
- Create an array of the object types.
$consMappingFileParams = ($typeWeb, $typeBool, $typeWeb)
- Get the class constructor for the
MasterPageMappingsFile
object.$consMappingFile = $typeMappingFile.GetConstructor($consMappingFileParams)
- Create an array of the parameters required to instantiate the
MasterPageMappingsFile
object.$mappingFileParams = [System.Array]::CreateInstance([System.Object], 3) $mappingFileParams[0] = (Get-SPSite http://sharepoint/sitecollection).RootWeb $mappingFileParams[1] = $false $mappingFileParams[2] = $null
Tip
When invoking a constructor to create an instance of a .NET object in PowerShell, we have to create a
System.Object
array rather than using a PowerShell array. Even though the base class for a PowerShell array isSystem.Object[]
, when calling theInvoke
method on the class constructor, it will see it as aPSObject
object instead. The same goes for theSPWeb
object we are passing as the first parameter. .NET will see the object as aPSObject
object instead of aSPWeb
object if we useGet-SPWeb
. However, if we get theSPWeb
object from theSPSite
object, it will not get treated as aPSObject
object. - Invoke the class constructor to create an instance of the
MasterPageMappingsFile
object.$mappingFile = $consMappingFile.Invoke($mappingFileParams)
- Set the
MasterPageUrl
property for the device channel on theMasterPageMappingsFile
object.$mappingFile["PowerShell"].MasterPageUrl = "/_catalogs/masterpage/oslo.master"
- Save the changes using the
UpdateSingleChannel
method.$mappingFile.UpdateSingleChannel("PowerShell")
Follow these steps to apply a master page to a device channel with code using the server-side object model:
- Get the site collection in a
using
statement.using (var site = new SPSite("http://sharepoint/sitecollection"))
- Get the root site of the site collection in a
using
statement.using (var web = site.RootWeb)
- Get the object type that will be used when getting the class constructor for the
MasterPageMappingsFile
object and later instantiating the object.var typeMappingFile = Type.GetType("Microsoft.SharePoint.Publishing.Mobile.MasterPageMappingsFile, Microsoft.SharePoint.Publishing, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c");
- Get the class constructor for the
MasterPageMappingsFile
object.var consMappingFile = typeMappingFile.GetConstructor(new Type[] { typeof(SPWeb), typeof(bool), typeof(SPWeb) });
- Invoke the constructor to create an instance of the
MasterPageMappingsFile
object.var mappingFile = consMappingFile.Invoke(new object[] { web, false, null });
- Get the
mappings
field of theMasterPageMappingsFile
object, and cast the field as anIDictionary
.var mappings = (IDictionary)typeMappingFile.GetField("mappings", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(mappingFile);
- Set the
MasterPageUrl
property for the device channel on themappings
field.mappings["PowerShell"].GetType().GetProperty("MasterPageUrl", BindingFlags.Instance | BindingFlags.Public).SetValue(mappings["PowerShell"], "/_catalogs/masterpage/seattle.master", null);
- Set the
mappings
field of theMasterPageMappingsFile
object.typeMappingFile.GetField("mappings", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(mappingFile, mappings);
- Get the
UpdateSingleChannel
method from the type of theMasterPageMappingsFile
object.var updateMethod = typeMappingFile.GetMethod("UpdateSingleChannel", BindingFlags.Instance | BindingFlags.Public, null, new Type[] { typeof(string) }, null);
- Save the changes by invoking the
UpdateSingleChannel
method.updateMethod.Invoke(mappingFile, new object[] { "Code" });
See also
- The SharePoint 2013 Design Manager device channels article on MSDN at http://msdn.microsoft.com/en-us/library/jj862343.aspx
- The Reflection in the .NET Framework article on MSDN at http://msdn.microsoft.com/en-us/library/f7ykdhsy.aspx
- The SPWeb class topic on MSDN at http://msdn.microsoft.com/en-us/library/Microsoft.SharePoint.SPWeb.aspx
- The SPSite class topic on MSDN at http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spsite.aspx
- The Get-SPSite topic on TechNet at http://technet.microsoft.com/en-us/library/ff607950.aspx