Here are the steps,
Step 1: Create Provider Hosted App using Visual Studio as in the following,
Go to Visual Studio, Office/SharePoint Tab, Apps and select App for SharePoint. Give some unique name “SharePointBranding”.
![SharePointBranding]()
Select Hosting option as “Provider Hosted” as in the following,
![Provider Hosted]()
Select Web Application type “ASP.NET Web Form Application” as in the following screenshot,
![Certificate]()
Select Authentication Type as “Certificate” as in the following,:
![ASP.NET Web Form Application]()
Step 2: Solution Structure looks like the following,
- Add folder named “CustomJS” with new custom JavaScript file named “App.js”.
-
- function getQueryStringParameter(urlParameterKey)
- {
- var params = document.URL.split('?')[1].split('&');
- var strParams = '';
- for (var i = 0; i < params.length; i = i + 1)
- {
- var singleParam = params[i].split('=');
- if (singleParam[0] == urlParameterKey) return singleParam[1];
- }
- }
-
- function Branding()
- {
- console.log("Branding");
- }
- $(document).ready(function ()
- {
-
- var spHostUrl = decodeURIComponent(getQueryStringParameter('SPHostUrl'));
-
- var layoutsRoot = spHostUrl + '/_layouts/15/';
-
- $.getScript(layoutsRoot + 'SP.Runtime.js', function ()
- {
- $.getScript(layoutsRoot + 'SP.js', function ()
- {
-
-
- $.getScript(layoutsRoot + 'SP.UI.Controls.js', renderSPChrome);
- });
- });
- });
- Add folder named “Resources” with two files “NewCustom.spcolor” and “NewCustombg.jpg”
![Resources]()
Step 3: Default.aspx page
- <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="SharePointBrandingWeb.Default" %>
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <html xmlns="http://www.w3.org/1999/xhtml">
-
- <head runat="server">
- <title></title>
- <script src="../Scripts/jquery-1.9.1.min.js" type="text/javascript"></script>
- </head>
-
- <body>
- <form id="form1" runat="server">
- <asp:ScriptManager ID="ScriptManager1" runat="server" EnableCdn="True" />
- <div id="divSPChrome"></div>
- <div style="left: 40px; position: absolute;">
- <table>
- <tr>
- <td>Set Out Of Box theme to host site </td>
- <td>
- <asp:DropDownList runat="server" ID="drpThemes" Width="100px">
- <asp:ListItem Text="Orange" Value="Orange" Selected="True"></asp:ListItem>
- <asp:ListItem Text="Green" Value="Green"></asp:ListItem>
- <asp:ListItem Text="Nature" Value="Nature"></asp:ListItem>
- <asp:ListItem Text="Blossom" Value="Blossom"></asp:ListItem>
- <asp:ListItem Text="Office" Value="Office"></asp:ListItem>
- <asp:ListItem Text="Breeze" Value="Breeze"></asp:ListItem>
- <asp:ListItem Text="Immerse" Value="Immerse"></asp:ListItem>
- </asp:DropDownList>
- </td>
- <td>
- <asp:Button runat="server" ID="btnSetThemeForHost" Text="Set out of the box theme" OnClick="btnSetThemeForHost_Click" /> </td>
- </tr>
- <tr>
- <td colspan="3"> </td>
- </tr>
- <tr>
- <td colspan="3">
- <asp:Label ID="lblStatus1" runat="server" /> </td>
- </tr>
- </table>
- <br />
- <table>
- <tr>
- <td>Deploy a new theme and apply to host site </td>
- <td colspan="2">
- <asp:Button runat="server" ID="btnDeployTheme" Text="Deploy a custom theme" OnClick="btnDeployTheme_Click" /> </td>
- </tr>
- <tr>
- <td colspan="3"> </td>
- </tr>
- <tr>
- <td colspan="3">
- <asp:Label ID="lblStatus2" runat="server" /> </td>
- </tr>
- </table>
- </div>
- <script src="../CustomJS/App.js" type="text/javascript"></script>
- </form>
- </body>
-
- </html>
Above code render UI as shown below:
Step 4: Register Script on page.
On page load we are going to register script named “
BasePageScript” into page as shown below.
- protected void Page_Load(object sender, EventArgs e)
- {
-
-
- var spContext = SharePointContextProvider.Current.GetSharePointContext(Context);
- using(var clientContext = spContext.CreateUserClientContextForSPHost())
- {
- clientContext.Load(clientContext.Web, web => web.Title);
- clientContext.ExecuteQuery();
- Response.Write(clientContext.Web.Title);
- }
-
- string script = @ "
-
- function chromeLoaded()
- {
- $('body').show();
- }
-
- function renderSPChrome()
- {
-
- var options = {
- 'appTitle': document.title,
- 'onCssLoaded': 'chromeLoaded()'
- };
- console.log('renderSPChrome ...');
-
- var chromeNavigation = new SP.UI.Controls.Navigation('divSPChrome', options);
- chromeNavigation.setVisible(true);
- }
- ";
-
- Page.ClientScript.RegisterClientScriptBlock(typeof (Default), "BasePageScript", script, true);
- }
Step 5: Apply Existing Theme to SharePoint Site as follows:
- Select any theme from dropdown menu and click on button “Set out Of Box Theme”.
- On button click “btnSetThemeForHost_Click()” method get called, which in turn call “SetThemeBasedOnName()” method.
- public void SetThemeBasedOnName(Web web, string themeName)
- {
-
- List themeList = web.GetCatalog(124);
- web.Context.Load(themeList);
- web.Context.ExecuteQuery();
-
- CamlQuery query = new CamlQuery();
- string camlString = @ " < View > < Query > < Where > < Eq > < FieldRef Name = 'Name' / > < Value Type = 'Text' >
- {
- 0
- } < /Value> < /Eq> < /Where> < /Query> < /View>";
-
- camlString = string.Format(camlString, themeName);
- query.ViewXml = camlString;
- var found = themeList.GetItems(query);
- web.Context.Load(found);
- web.Context.ExecuteQuery();
- if (found.Count > 0)
- {
- Microsoft.SharePoint.Client.ListItem themeEntry = found[0];
-
- string spColorURL = null;
- if (themeEntry["ThemeUrl"] != null && themeEntry["ThemeUrl"].ToString().Length > 0)
- {
- spColorURL = MakeAsRelativeUrl((themeEntry["ThemeUrl"] as FieldUrlValue).Url);
- }
- string spFontURL = null;
- if (themeEntry["FontSchemeUrl"] != null && themeEntry["FontSchemeUrl"].ToString().Length > 0)
- {
- spFontURL = MakeAsRelativeUrl((themeEntry["FontSchemeUrl"] as FieldUrlValue).Url);
- }
- string backGroundImage = null;
- if (themeEntry["ImageUrl"] != null && themeEntry["ImageUrl"].ToString().Length > 0)
- {
- backGroundImage = MakeAsRelativeUrl((themeEntry["ImageUrl"] as FieldUrlValue).Url);
- }
-
- web.ApplyTheme(spColorURL, spFontURL, backGroundImage, false);
-
- if (themeEntry["MasterPageUrl"] != null && themeEntry["MasterPageUrl"].ToString().Length > 0)
- {
- web.MasterUrl = MakeAsRelativeUrl((themeEntry["MasterPageUrl"] as FieldUrlValue).Url);
- }
-
- web.Context.ExecuteQuery();
- }
- }
- private string MakeAsRelativeUrl(string urlToProcess)
- {
- Uri uri = new Uri(urlToProcess);
- return uri.AbsolutePath;
- }
- protected void btnSetThemeForHost_Click(object sender, EventArgs e)
- {
- var spContext = SharePointContextProvider.Current.GetSharePointContext(Context);
- using(var clientContext = spContext.CreateUserClientContextForSPHost())
- {
- if (clientContext != null)
- {
- Web web = clientContext.Web;
- string selectedTheme = drpThemes.SelectedValue;
- SetThemeBasedOnName(web, selectedTheme);
- lblStatus1.Text = string.Format("Theme '{0}' has been applied to the <a href='{1}'>host web</a>.", selectedTheme, spContext.SPHostUrl.ToString());
- }
- }
- }
- Existing theme resides inside ‘Composite Look Gallery’, so we first need to get access to composite look gallery for that the following line of code is used.
- List themeList = web.GetCatalog(124);
-
- web.Context.Load(themeList);
-
- web.Context.ExecuteQuery();
- Using CAML Query object, get list item corresponding to selected theme.
- Let’s find “ThemeURL”, “ImageURL”, “MasterPageURL” which is needed to apply theme to the site.
-
-
- web.ApplyTheme(spColorURL, spFontURL, backGroundImage, false);
![MasterPageURL]()
Step 6: Output of applying existing theme to SharePoint Site.
![ThemeURL]()
Step 7: Deploy Custom Theme
- In order to create custom theme, we need some resources like SPColor and Image to set background for site.
![SharePoint Site]()
- Click on “Deploy Custom Theme”, it call “btnDeployTheme_Click()” method.
- protected void btnDeployTheme_Click(object sender, EventArgs e)
- {
- var spContext = SharePointContextProvider.Current.GetSharePointContext(Context);
- using(var clientContext = spContext.CreateUserClientContextForSPHost())
- {
- if (clientContext != null)
- {
- Web web = clientContext.Web;
- string CustomColor = HostingEnvironment.MapPath(string.Format("~/{0}", "Resources/NewCustom.spcolor"));
- string CustomBackground = HostingEnvironment.MapPath(string.Format("~/{0}", "Resources/NewCustombg.jpg"));
-
- DeployContosoThemeToWeb(web, "NewCustomTheme", CustomColor, string.Empty, CustomBackground, string.Empty);
-
- SetThemeBasedOnName(web, "NewCustomTheme");
- lblStatus2.Text = string.Format("Custom theme called 'NewCustomTheme' has been uploaded and applied to the <a href='{0}'>host web</a>.", spContext.SPHostUrl.ToString());
- }
- }
- }
Theme Gallery gets modified, two new entry get added here as shown below for color and background image.
![background image]()
- New Theme getting deploy into "Composite Look Gallery" as shown below.
![Site setting]()
Step 8: Source Code
- using Microsoft.SharePoint.Client;
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using System.Web;
- using System.Web.Hosting;
- using System.Web.UI;
- using System.Web.UI.WebControls;
- namespace SharePointBrandingWeb
- {
- public partial class Default: System.Web.UI.Page
- {
- protected void Page_PreInit(object sender, EventArgs e)
- {
- Uri redirectUrl;
- switch (SharePointContextProvider.CheckRedirectionStatus(Context, out redirectUrl))
- {
- case RedirectionStatus.Ok:
- return;
- case RedirectionStatus.ShouldRedirect:
- Response.Redirect(redirectUrl.AbsoluteUri, endResponse: true);
- break;
- case RedirectionStatus.CanNotRedirect:
- Response.Write("An error occurred while processing your request.");
- Response.End();
- break;
- }
- }
- protected void Page_Load(object sender, EventArgs e)
- {
-
-
- var spContext = SharePointContextProvider.Current.GetSharePointContext(Context);
- using(var clientContext = spContext.CreateUserClientContextForSPHost())
- {
- clientContext.Load(clientContext.Web, web => web.Title);
- clientContext.ExecuteQuery();
- Response.Write(clientContext.Web.Title);
- }
-
- string script = @ "
-
- function chromeLoaded()
- {
- $('body').show();
- }
-
- function renderSPChrome()
- {
-
- var options = {
- 'appTitle': document.title,
- 'onCssLoaded': 'chromeLoaded()'
- };
- console.log('renderSPChrome ...');
-
- var chromeNavigation = new SP.UI.Controls.Navigation('divSPChrome', options);
- chromeNavigation.setVisible(true);
- }
- ";
-
- Page.ClientScript.RegisterClientScriptBlock(typeof (Default), "BasePageScript", script, true);
- }
- public void SetThemeBasedOnName(Web web, string themeName)
- {
-
- List themeList = web.GetCatalog(124);
- web.Context.Load(themeList);
- web.Context.ExecuteQuery();
-
- CamlQuery query = new CamlQuery();
- string camlString = @ " < View > < Query > < Where > < Eq > < FieldRef Name = 'Name' / > < Value Type = 'Text' >
- {
- 0
- } < /Value> < /Eq> < /Where> < /Query> < /View>";
-
- camlString = string.Format(camlString, themeName);
- query.ViewXml = camlString;
- var found = themeList.GetItems(query);
- web.Context.Load(found);
- web.Context.ExecuteQuery();
- if (found.Count > 0)
- {
- Microsoft.SharePoint.Client.ListItem themeEntry = found[0];
-
- string spColorURL = null;
- if (themeEntry["ThemeUrl"] != null && themeEntry["ThemeUrl"].ToString().Length > 0)
- {
- spColorURL = MakeAsRelativeUrl((themeEntry["ThemeUrl"] as FieldUrlValue).Url);
- }
- string spFontURL = null;
- if (themeEntry["FontSchemeUrl"] != null && themeEntry["FontSchemeUrl"].ToString().Length > 0)
- {
- spFontURL = MakeAsRelativeUrl((themeEntry["FontSchemeUrl"] as FieldUrlValue).Url);
- }
- string backGroundImage = null;
- if (themeEntry["ImageUrl"] != null && themeEntry["ImageUrl"].ToString().Length > 0)
- {
- backGroundImage = MakeAsRelativeUrl((themeEntry["ImageUrl"] as FieldUrlValue).Url);
- }
-
- web.ApplyTheme(spColorURL, spFontURL, backGroundImage, false);
-
- if (themeEntry["MasterPageUrl"] != null && themeEntry["MasterPageUrl"].ToString().Length > 0)
- {
- web.MasterUrl = MakeAsRelativeUrl((themeEntry["MasterPageUrl"] as FieldUrlValue).Url);
- }
-
- web.Context.ExecuteQuery();
- }
- }
- private string MakeAsRelativeUrl(string urlToProcess)
- {
- Uri uri = new Uri(urlToProcess);
- return uri.AbsolutePath;
- }
- protected void btnSetThemeForHost_Click(object sender, EventArgs e)
- {
- var spContext = SharePointContextProvider.Current.GetSharePointContext(Context);
- using(var clientContext = spContext.CreateUserClientContextForSPHost())
- {
- if (clientContext != null)
- {
- Web web = clientContext.Web;
- string selectedTheme = drpThemes.SelectedValue;
- SetThemeBasedOnName(web, selectedTheme);
- lblStatus1.Text = string.Format("Theme '{0}' has been applied to the <a href='{1}'>host web</a>.", selectedTheme, spContext.SPHostUrl.ToString());
- }
- }
- }
- protected void btnDeployTheme_Click(object sender, EventArgs e)
- {
- var spContext = SharePointContextProvider.Current.GetSharePointContext(Context);
- using(var clientContext = spContext.CreateUserClientContextForSPHost())
- {
- if (clientContext != null)
- {
- Web web = clientContext.Web;
- string CustomColor = HostingEnvironment.MapPath(string.Format("~/{0}", "Resources/NewCustom.spcolor"));
- string CustomBackground = HostingEnvironment.MapPath(string.Format("~/{0}", "Resources/NewCustombg.jpg"));
-
- DeployContosoThemeToWeb(web, "NewCustomTheme", CustomColor, string.Empty, CustomBackground, string.Empty);
-
- SetThemeBasedOnName(web, "NewCustomTheme");
- lblStatus2.Text = string.Format("Custom theme called 'NewCustomTheme' has been uploaded and applied to the <a href='{0}'>host web</a>.", spContext.SPHostUrl.ToString());
- }
- }
- }
- public void DeployContosoThemeToWeb(Web web, string themeName, string colorFilePath, string fontFilePath, string backgroundImagePath, string masterPageName)
- {
-
- if (!string.IsNullOrEmpty(colorFilePath))
- {
- DeployFileToThemeFolderSite(web, colorFilePath);
- }
- if (!string.IsNullOrEmpty(fontFilePath))
- {
- DeployFileToThemeFolderSite(web, fontFilePath);
- }
- if (!string.IsNullOrEmpty(backgroundImagePath))
- {
- DeployFileToThemeFolderSite(web, backgroundImagePath);
- }
-
- AddNewThemeOptionToSite(web, themeName, colorFilePath, fontFilePath, backgroundImagePath, masterPageName);
- }
- private void DeployFileToThemeFolderSite(Web web, string sourceAddress)
- {
-
- string file = sourceAddress;
-
- List themesList = web.GetCatalog(123);
- web.Context.Load(themesList);
- web.Context.ExecuteQuery();
- Folder rootfolder = themesList.RootFolder;
- web.Context.Load(rootfolder);
- web.Context.Load(rootfolder.Folders);
- web.Context.ExecuteQuery();
- Folder folder15 = rootfolder;
- foreach(Folder folder in rootfolder.Folders)
- {
- if (folder.Name == "15")
- {
- folder15 = folder;
- break;
- }
- }
-
- FileCreationInformation newFile = new FileCreationInformation();
- newFile.Content = System.IO.File.ReadAllBytes(file);
- newFile.Url = folder15.ServerRelativeUrl + "/" + System.IO.Path.GetFileName(sourceAddress);
- newFile.Overwrite = true;
- Microsoft.SharePoint.Client.File uploadFile = folder15.Files.Add(newFile);
- web.Context.Load(uploadFile);
- web.Context.ExecuteQuery();
- }
- private void AddNewThemeOptionToSite(Web web, string themeName, string colorFilePath, string fontFilePath, string backGroundPath, string masterPageName)
- {
-
- List themesOverviewList = web.GetCatalog(124);
- web.Context.Load(themesOverviewList);
- web.Context.ExecuteQuery();
-
- if (!ThemeEntryExists(web, themesOverviewList, themeName))
- {
-
- if (!web.IsObjectPropertyInstantiated("ServerRelativeUrl"))
- {
- web.Context.Load(web);
- web.Context.ExecuteQuery();
- }
-
- ListItemCreationInformation itemInfo = new ListItemCreationInformation();
- Microsoft.SharePoint.Client.ListItem item = themesOverviewList.AddItem(itemInfo);
- item["Name"] = themeName;
- item["Title"] = themeName;
- if (!string.IsNullOrEmpty(colorFilePath))
- {
- item["ThemeUrl"] = URLCombine(web.ServerRelativeUrl, string.Format("/_catalogs/theme/15/{0}", System.IO.Path.GetFileName(colorFilePath)));
- }
- if (!string.IsNullOrEmpty(fontFilePath))
- {
- item["FontSchemeUrl"] = URLCombine(web.ServerRelativeUrl, string.Format("/_catalogs/theme/15/{0}", System.IO.Path.GetFileName(fontFilePath)));
- }
- if (!string.IsNullOrEmpty(backGroundPath))
- {
- item["ImageUrl"] = URLCombine(web.ServerRelativeUrl, string.Format("/_catalogs/theme/15/{0}", System.IO.Path.GetFileName(backGroundPath)));
- }
-
- if (string.IsNullOrEmpty(masterPageName))
- {
- item["MasterPageUrl"] = URLCombine(web.ServerRelativeUrl, "/_catalogs/masterpage/seattle.master");
- }
- else
- {
- item["MasterPageUrl"] = URLCombine(web.ServerRelativeUrl, string.Format("/_catalogs/masterpage/{0}", Path.GetFileName(masterPageName)));
- }
- item["DisplayOrder"] = 11;
- item.Update();
- web.Context.ExecuteQuery();
- }
- }
- private bool ThemeEntryExists(Web web, List themeList, string themeName)
- {
- CamlQuery query = new CamlQuery();
- string camlString = @ " < View > < Query > < Where > < Eq > < FieldRef Name = 'Name' / > < Value Type = 'Text' >
- {
- 0
- } < /Value> < /Eq> < /Where> < /Query> < /View>";
-
- camlString = string.Format(camlString, themeName);
- query.ViewXml = camlString;
- var found = themeList.GetItems(query);
- web.Context.Load(found);
- web.Context.ExecuteQuery();
- if (found.Count > 0)
- {
- return true;
- }
- return false;
- }
- private string URLCombine(string baseUrl, string relativeUrl)
- {
- if (baseUrl.Length == 0) return relativeUrl;
- if (relativeUrl.Length == 0) return baseUrl;
- return string.Format("{0}/{1}", baseUrl.TrimEnd(new char[]
- {
- '/',
- '\\'
- }), relativeUrl.TrimStart(new char[]
- {
- '/',
- '\\'
- }));
- }
- }
- }
Step 9: Final Output
![Final Output]()