OK, so, at my current client, I ran into a problem: I wanted to be able to switch up themes based on a user’s profile, but the user’s profile is based on a proprietary security system. When a new Theme for the site was set, it needed to change the logo at the top of the page, some text in the footer, and the items that appear in the top nav. Here’s how I went about doing it:

Project Setup

In the App_Themes directory, I created several theme directories, and each theme directory contained three files: a .css file, a .skin file, and .sitemap file.
– App_Themes
– 0
– Default.css
– Default.skin
– Default.sitemap
– 1
– Theme1.css
– Theme1.skin
– Theme1.sitemap

My project contained a BasePage.cs file that served as a base class for my Page objects, a Master.master page that served as the master page, and various content pages that inherited from the BasePage class, and were connected to the master. My project also contained the necessary global.asax and web.config files, as well as a default Web.sitemap.

Setting the Theme

First, I had to retrieve the theme from the user’s profile. I did this by retrieving the user’s information from the header/server variables, that had been put there when the user logged on. I figured out which theme I should use, and put it in a session variable. I did this in the global.asax’s Session_Start event handler. So, my code looked like this:

void Session_Start(object sender, EventArgs e)
{
  string myTheme = HttpContext.Current.Request.ServerVariables["USERINFO"];
  HttpContext.Current.Session.Add("Theme", myTheme);
}

Although it might seem intuitive that you could set a site’s theme in the Master page, it’s actually not possible. You have to set the theme of the page in the Page class itself. So I didn’t have to put the same logic in every page on my site, I created a base class that all the pages in my site inherit from. Because the Theme of the site needs to get set before the PageLoad event fires, you have to set the page theme in the Page_PreInit event handler. My base class looked like this:

public class BasePage : Page
{
  protected void Page_PreInit(object sender, EventArgs e)
  {
    this.Theme = Session["Theme"].ToString();
  }
}

You have to make sure that theme you’re setting really exists as a Theme on your site. (For instance, my site only has Theme’s called “0” and “1”. If I tried to set my Theme to “Becky”, it would throw an error.)

When I created new content pages based on the page master, I had to make sure their class inherited from my base class, not the default Page class, in the page behind:

public partial class _Default : BasePage

Skinning the Site

Now that I have my code set up to apply the appropriate theme to the site when the user logs in, what exactly was going to change in the site?

My first step was to create the master page, and to create web controls on that page that were “skinnable”. For instance, at the top of the page, I created a logo control that looked like this:

<asp:image id="LogoImage" skinid="Logo" runat="server"/>

And at the bottom of the page I created a footer control that looked like this:

<asp:label id="FooterText" skinid="Footer" runat="server" />

Inside my .skin file in my Theme, I decided what those controls should look like for that particular theme:

<asp:image skinid="Logo" runat="server" imageurl="~/Images/Logo1.gif"/>
<asp:label runat="server" cssclass="label"&gt;(c)2006 Becky VanBruggen</asp:label>

I also applied my site colors to the classes in my .css file for that theme.

Changing the SiteMap

Not only did I need to change the theme for the site based on the user’s credentials, but which pages were to appear in the nav also needed to change based on the site’s theme. (Page B shoud be available for Theme 1 but not Theme 0.) This was slightly more difficult to execute since .sitemaps don’t automatically change with themes.

First, I added a node to the siteMap providers section of the application’s web.config file, one for each theme:

<sitemap defaultprovider="0">
  <providers>
    <add sitemapfile="~/App_Themes/0/Default.sitemap" type="System.Web.XmlSiteMapProvider" name="0">
    <add sitemapfile="~/App_Themes/1/Theme1.sitemap" type="System.Web.XmlSiteMapProvider" name="1">
  </providers>
</sitemap>

Then, inside my BasePage class, I added code to the Page_Load event handler:

if (WebConfigurationManager.GetSection("system.web/siteMap") != null)
{
  SiteMapSection siteMap = (SiteMapSection)WebConfigurationManager.GetSection("system.web/siteMap");
  if (siteMap.Providers[Session["Theme"].ToString()] != null)
  {
    SiteMapDataSource smds = (SiteMapDataSource)master.FindControl("SiteMapDataSource1");
    smds.SiteMapProvider = Session["Theme"].ToString();
  }
}

FYI… in the pages that inherit from the base page, you need to make sure you explicitly call base.Page_Load(sender, e) and base.Page_PreInit(sender, e) inside the respective event handlers if you want to add your own Page_Load or Page_PreInit event handlers to them.

And… voila! Now, when a user logs in and has been assigned Theme 1, they will see Theme 1’s logo, Theme 1’s CSS styling, and Theme 1’s site map.