HttpCombiner modifications for better usability

Http­Com­biner is a HttpHan­dler allows you to gather all css and js files together which decreases amount of http requests made to server when user requests a page and also to cache the gen­er­ated files, which makes you web­sites to load faster. You can down­load http han­dler from Microsoft’s web­site by click­ing here and you can read Omar’s arti­cle on how to imple­ment the han­dler here. Orig­i­nal han­dler writ­ten by Omar Al Zabir.

It took me few min­utes to con­fig­ure the han­dler to work, it is easy to use and well doc­u­mented. So i advice you to read Omar’s post before con­tin­u­ing with modifications.

What the prob­lem with Omar’s http handler ?

  1. need­less num­ber of pareme­ters which are passed to han­dler, instead of hav­ing 1 para­me­ter ie. css or js , we got 3 para­me­ters. Why to have file type and con­tent type together when js exten­sion clearly means “javascript/text” con­tent type.
  2. gen­er­ated by han­dler out­put is cached which means old ver­sion will be used any­time you access the page which makes imposi­ble to use han­dler dur­ing devel­ope­ment process when we con­stantly mod­ify JS and CSS files. By default there is a para­me­ter in query string call to han­dler “v” which stands for ver­sion but each change you make on files you will need to update the ver­sion num­ber so there won’t be caching.
  3. each JS or CSS file must be defined in web.config which goes against my dynamic thinking

if you find these as faults in usabil­ity like i do con­tinue read­ing further …

How do we fix those issues ?

First of lets get rid of para­me­ters and just pass one that stands for file type (ie. css or js), sec­ond of all lets define folder within the appli­ca­tion where all js and css files will be stored so we can loop though folder and dynam­i­cally get all files at once with­out defin­ing each new file and last let’s define global para­me­ter which tells han­dler whether it is pro­duc­tion, devel­op­ment server or just a cache refresh to update web­site so we won’t directly deal with versioning.

I could rewrite the han­dler to work as i want it to but Omar did a great job with han­dler and all credit to him, while i don’t want to cre­ate “yet another HttpHan­dler” to com­bine css/js files.. My idea was to hack Http­Com­biner as fast as i could so i could get to work with it with­out deal­ing with it’s design.

Imple­men­ta­tion

Step I — web.config

let’s cre­ate two fold­ers inside of our assets folder css and js, because han­dler already loads css you need to move all css files from your App_Theme/ThemeName folder to Assets/Css one and Js files just keep inside Assets/Js.

impor­tant note, from now on your CSS and JS files are vir­tu­ally located on the root (where you place the HttpCombiner.ashx) and not inside real Assets/Foldername folder.

Once we have two fold­ers and we under­stood where files gonna reside and where their vir­tual loca­tion will be, let’s tweak web.config file to work with new settings.

old code

</appSettings>
<appSettings>
<add key="Set_Css" value="~/App_Themes/Default/Css1.css,~/App_Themes/Default/Css2.css"/>
<add key="Set_Javascript" value="~/Javascripts/Js1.js,~/Javascripts/Js2.js,http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"/>
</appSettings>

new code

<appSettings>
<add key="css" value="~/assets/css/"/>
<add key="js" value="~/assets/js/"/>
<add key="refreshCombiner" value="true"/>
</appSettings>

Step II — change of urls lay­out for han­dler calls

old urls

<link type="text/css"  rel="Stylesheet" href="HttpCombiner.ashx?s=Set_Css&amp;t=text/css&amp;v=1" />
<script type="text/javascript"  src="HttpCombiner.ashx?s=Set_Javascript&amp;t=type/javascript&amp;v=2" ></script>

new urls

<link type="text/css"  rel="stylesheet" href="HttpCombiner.ashx?t=css" />
<script type="text/javascript"  src="HttpCombiner.ashx?t=js" ></script>

Step III — mod­i­fi­ca­tion of HttpCombiner.ashx

old code — lines 22–24


string setName = request["s"] ?? string.Empty;
string contentType = request["t"] ?? string.Empty;
string version = request["v"] ?? string.Empty;

new code


string setName = request["t"] ?? string.Empty;
string contentType = (setName == "js") ? "text/javascript" : "text/css";

string version = "1";
if (bool.Parse(ConfigurationManager.AppSettings["refreshCombiner"]))
{
version = new Random().Next(1, 999999).ToString();
}

old code — lines 47–56


string setDefinition =
System.Configuration.ConfigurationManager.AppSettings[setName] ?? "";
string[] fileNames = setDefinition.Split(new char[] { ',' },
StringSplitOptions.RemoveEmptyEntries);

foreach (string fileName in fileNames)
{
byte[] fileBytes = this.GetFileBytes(context, fileName.Trim(), encoding);
writer.Write(fileBytes, 0, fileBytes.Length);
}

new code


string filesPath = ConfigurationManager.AppSettings[setName];
string[] fileEntries = Directory.GetFiles(HttpContext.Current.Server.MapPath(filesPath));
foreach (string fileName in fileEntries)
{
byte[] fileBytes = this.GetFileBytes(context, filesPath + fileName.Trim().Remove(0, fileName.LastIndexOf("\\")), encoding);
writer.Write(fileBytes, 0, fileBytes.Length);
}

Hope you enjoyed it !!!

Share and Enjoy:
  • Print
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • DotNetKicks
  • DZone
  • LinkedIn
  • StumbleUpon
  • Technorati
  • Live
  • PDF

Tags: http handler, optimization

One comment

Leave a comment