Adding Variables To Style Sheets in Asp.Net

in #utopian-io8 years ago (edited)

What Will I Learn?

You will learn Adding Variables To Style Sheets in Asp.Net

Requirements

ASP.NET Core

Difficulty

Intermediate

Tutorial Contents

  • An Http Handler Refresher
  • Implementing a Configuration Section Handler
  • Implementing an HTTP Handler
  • Configuring IIS

Adding Variables To Style Sheets in Asp.Net

Even though the spec defines CSS as a style sheet language, this language is missing one of the essential features: variables. Every time I've seen people in newsgroups ask how to implement variables in CSS a typical advice was to build the style sheet on the server. Luckily, it is easy to do in ASP.NET with the help of HTTP Handlers.

An Http Handler Refresher

An HttpHandler is a class that implements the IHttpHandler interface. This class can be associated with pretty much any file extension. Once you request a resource with a certain extension a corresponding HttpHandler processes your request and sends back a response. For example, when you request an ASP.NET page with the .aspx extension the System.Web.UI.Page handler processes the request and responds with an HTML page.We're going to write a custom handler and associate it with .css files. This handler will allow us to add variables to our style sheets. For example, we'll define variables and their values in a configuration file (how about web.config?):

<DynamicCss>
 <variables>
 <variable name="$main_color" substitute="#fff" />
 <variable name="$bkg_color" substitute="gray" />
 </variables>
</DynamicCss>

and then use the variables in a style sheet:

body
{
 background: $bkg_color;
 color: $main_color;
}

When a .css file is requested our HttpHandler will replace the variables on the fly. To make this happen we'll need to implement two pieces:

  1. A handler of configuration settings to help us initialize variables, and
  2. An HttpHandler to substitute these variables in real time

Implementing a Configuration Section Handler

You may extend the standard set of settings in web.config with your own settings. This is great news because you may add any configuration settings you want as long as you also write a handler to digest these settings. A configuration section handler is a class which implements the IConfigurationSectionHandler interface:

using System;
using System.Configuration;
using System.Xml;
using System.Xml.Serialization;

namespace DynamicCSS
{
 public class SettingsHandler : IConfigurationSectionHandler
 {
  private XmlSerializer _ser = new XmlSerializer (typeof (Settings));

   public object Create (object parent, object configContext,
                         System.Xml.XmlNode section)
   {
      Settings cfg = (Settings)
               _ser.Deserialize (new XmlNodeReader (section));
       return cfg;
   }
 }
}

To put this handler to good use you need to register it in web.config:

<configSections>
 <section name="DynamicCss" type="DynamicCSS.SettingsHandler,
  DynamicCSS" />
</configSections>

The Settings class in a listing above is going to handle variable names and their values:

using System;
using System.Collections;
using System.Xml;
using System.Xml.Serialization;

namespace DynamicCSS
{

[XmlRoot("DynamicCss")]
public class Settings
{
private Variable[] _variables;

[XmlArray ("variables")]
[XmlArrayItem ("variable", typeof (Variable))]
public Variable[] Variables
{
  get { return _variables; }
  set { _variables = value; }
}
}

/// <summary>
/// This class represents a variable and its substituted value
/// </summary>
public class Variable
{
 string _name;
 string _substitute;

 public Variable () {}

 [XmlAttribute ("name")]
 public string Name
 {
   get { return _name; }
   set { _name = value; }
 }

 [XmlAttribute ("substitute")]
 public string Substitute
 {
   get { return _substitute; }
   set { _substitute = value; }
 }
}
}

Variable is a painfully simple class that represents a variable and its value (declared in web.config, as we agreed), while the Settings class is another painfully simple class which simply implements a collection of these variables in an array. You might've noticed the use of an XML serializer and XML attributes in both Settings and Variable. XML serialization is outside the scope of this article, but suffice it to say you only need to carefully match serialization attributes with XML elements and attributes in your configuration section. The XML serializer will take care of the rest! This is both elegant and powerful!

Implementing an HTTP Handler

Now that we've defined variables, their values, put them in web.config and wrote a handler to read them, we'll implement the final and most important piece: an HttpHandler itself. Please, download the source code of the handler and poke around. I will only outline the steps our handler is supposed to take:

  1. A request for a .css file is received. The handler looks for the file on the hard drive. If it's missing or ASP.NET is not authorized to read it for whatever reason, we send an appropriate HTTP code along with an error message.
  2. Otherwise, we check if the file has been modified since we served it last. If it has been intact and the browser is willing to use it from its cache, we serve the HTTP code 304 ("Not Modified") and leave.
  3. If we've come this far, we read the style sheet and replace every variable occurrence (if any) with its value.

Since we've discussed a configuration section handler in great detail here's how you iterate over variables in the HttpHandler:

Settings cfg = (Settings) System.Configuration.«
              ConfigurationSettings.GetConfig ("DynamicCss");

foreach (Variable var in cfg.Variables)
{
   // ------------------------------------
   // Search for the variable

   // NOTE: The search is case-sensitive
   // ------------------------------------
   Regex re = new Regex (string.Concat (
                           "\\$\\b", var.Name.Substring (1), "\\b"));
   css = re.Replace (css, var.Substitute);
}

I use a simple regular expression to replace variable occurrences.

NOTE: Variable names are case sensitive. If you want to "relax" this condition you need to add RegexOptions.IgnoreCase to the Regex constuctor.At this point we've got all bits and pieces in place. One last thing is to configure IIS to cooperate with us and we're truly done.

Configuring IIS

When you install the .NET Framework a number of file extensions are associated with the ASP.NET ISAPI. For example, IIS hands requests for .aspx, .asmx and .ashx files to aspnet_isapi.dll. On the other hand, .css files are not mapped to .NET and therefore IIS handles them on its own, and our HttpHandler won't be even invoked. We need to remap .css files to the ASP.NET ISAPI so the handler will get a piece of the action.

To do so launch the Internet Information Manager applet from Administration Tools, find your web app, righ click and go to Properties. On the Virtual Directory tab click Configuration. On the Mappings tab click Add and configure extension mapping as shown below:

The ISAPI path is quite long, so simply copy and paste it from another extension. Done and done.

Application Notes

A good fit for this technique is branding web applications. For example, you have to configure color schemes of your web app for different instances. We do it with our main product. Making a separate style sheet for each instance is painful enough as the customer base grows. Introducing variables makes matters much easier since you don't have to tweak CSS once you make it variable-oriented.

Using this technique would be wrong if you plan on changing variables often. Remember we store them in web.config? Each time you edit web.config you cause your web app to restart. Often restarts will degrade performance among other things. Therefore you might want to configure variables and leave them alone for a while.

If you do need to change variables often I'd recommend you move them out of web.config into a separate XML file, for example. In fact, you won't need a configuration section handler any more. All you need to do is to somehow feed variables to the HTTP handler. 



Posted on Utopian.io - Rewarding Open Source Contributors

Sort:  

Your contribution cannot be approved because it does not follow the Utopian Rules.

You can contact us on Discord.
[utopian-moderator]

Coin Marketplace

STEEM 0.05
TRX 0.33
JST 0.082
BTC 62530.03
ETH 1633.28
USDT 1.00
SBD 0.44