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.
Follow these steps to apply a master page to a device channel:
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.
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.
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:
Microsoft.SharePoint.dll
and Microsoft.SharePoint.Publishing.dll
assemblies into the PowerShell session.[Reflection.Assembly]::LoadFrom("C:Program FilesCommon Filesmicrosoft sharedWeb Server Extensions15ISAPIMicrosoft.SharePoint.Publishing.dll") [Reflection.Assembly]::LoadFrom("C:Program FilesCommon Filesmicrosoft sharedWeb Server Extensions15ISAPIMicrosoft.SharePoint.dll")
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")
$consMappingFileParams = ($typeWeb, $typeBool, $typeWeb)
MasterPageMappingsFile
object.$consMappingFile = $typeMappingFile.GetConstructor($consMappingFileParams)
MasterPageMappingsFile
object.$mappingFileParams = [System.Array]::CreateInstance([System.Object], 3) $mappingFileParams[0] = (Get-SPSite http://sharepoint/sitecollection).RootWeb $mappingFileParams[1] = $false $mappingFileParams[2] = $null
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 is System.Object[]
, when calling the Invoke
method on the class constructor, it will see it as a PSObject
object instead. The same goes for the SPWeb
object we are passing as the first parameter. .NET will see the object as a PSObject
object instead of a SPWeb
object if we use Get-SPWeb
. However, if we get the SPWeb
object from the SPSite
object, it will not get treated as a PSObject
object.
MasterPageMappingsFile
object.$mappingFile = $consMappingFile.Invoke($mappingFileParams)
MasterPageUrl
property for the device channel on the MasterPageMappingsFile
object.$mappingFile["PowerShell"].MasterPageUrl = "/_catalogs/masterpage/oslo.master"
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:
using
statement.using (var site = new SPSite("http://sharepoint/sitecollection"))
using
statement.using (var web = site.RootWeb)
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");
MasterPageMappingsFile
object.var consMappingFile = typeMappingFile.GetConstructor(new Type[] { typeof(SPWeb), typeof(bool), typeof(SPWeb) });
MasterPageMappingsFile
object.var mappingFile = consMappingFile.Invoke(new object[] { web, false, null });
mappings
field of the MasterPageMappingsFile
object, and cast the field as an IDictionary
.var mappings = (IDictionary)typeMappingFile.GetField("mappings", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(mappingFile);
MasterPageUrl
property for the device channel on the mappings
field.mappings["PowerShell"].GetType().GetProperty("MasterPageUrl", BindingFlags.Instance | BindingFlags.Public).SetValue(mappings["PowerShell"], "/_catalogs/masterpage/seattle.master", null);
mappings
field of the MasterPageMappingsFile
object.typeMappingFile.GetField("mappings", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(mappingFile, mappings);
UpdateSingleChannel
method from the type of the MasterPageMappingsFile
object.var updateMethod = typeMappingFile.GetMethod("UpdateSingleChannel", BindingFlags.Instance | BindingFlags.Public, null, new Type[] { typeof(string) }, null);
UpdateSingleChannel
method.updateMethod.Invoke(mappingFile, new object[] { "Code" });
3.145.179.85