Click here to Skip to main content
Click here to Skip to main content

Automatically Minify, Combine, Compress, and Cache *.js and *.css Files in your ASP.NET Project

, 24 Mar 2010 CPOL
Rate this:
Please Sign up or sign in to vote.
Automatically minify, combine, compress, and cache .js and .css files in your ASP.NET project

Introduction

This article shows you how to optimize your style sheet and JavaScript files in your ASP.NET web application. More specifically, you will be shown that all of your style sheet and JavaScript files in your ASP.NET web application can be automatically minified, compressed, combined, and cached.  

Background 

Each time you have script or link tag in a web page to reference a JavaScript or style sheet file, a separate request is made by the browser to get that file. This results in much network latency. A more efficient approach would be to have just one request to get all of the JavaScript files, and another request to get all of the script files for the page. I have accomplished this by using an HTTP handler that will return the required content of each set of script or style sheet files. This content will also be minified, compressed, and cached on both the browser and the server, along with the correct file dependencies so that any changes to the files will invalidate both the client and server cache.  

I'd like to thank Moiz Dhanji for his article.

I used much of his code to develop this project. The main additions I made were the ability to handle CSS files, file dependency caching, and custom controls for easy portability to other projects. The main subtractions were the profiler feature, and the ability to handle embedded resource files. 

I am aware that the Ajax toolkit's ScriptManager control can combine script files and it may be suitable for your needs, BUT all it does is combine them. My project can do this, plus minify, compress, and cache them too. My project can also handle CSS files. Furthermore, the ScriptManager forces you to download all of the ASP.NET Ajax script files, which you may not need.  

Implementation 

Created Section for Web.config

The ScriptCombinerSection class does this.  It is basically the same code as Moiz Dhanji's, except with some unnecessary attributes removed. 

Created Custom Handler

The CssJscriptOptimizerHandler class performs the main functionality of the project.  It does the minifiying, compressing, combining, and caching of the files.

Created Custom Controls

The ScriptCombiner and StyleSheetCombiner controls are responsible for inspecting their enclosed script and link tags, respectively, and then rendering the appropriate single request URL that will point to the custom handler for processing. 

Paths, Paths, Paths

Another goal that I had for this project was to make it transparent to the script and style sheet developers. I didn't want them to have to modify the way they work to accompany me in any way. One of the things about CSS is that there is the URL attribute. This attribute has no concept of the application root (~) that ASP.NET does. So a lot of times, there are relative paths like "../Images/image1.jpg" in the files.  This won't work if the handler is in a different directory than the CSS file.  To address this issue, I implemented a FixUrlPaths method my custom handler to calculate the correct path when it sees the URL attribute.

How To Use

In the web.config file:

  1. Within the configSections element, add:
     <section name="optimizerSection" 
              type="CnCssJscriptOptimizer.ConfigurationSections.OptimizerSection,   
     CnCssJscriptOptimizer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
  2. Within the configuration element, add the optimizerSection. For example:
            <optimizerSection
              enable="true"
              enableScriptCompression="true"
              enableSheetCompression="true"
              enableScriptMinification="true"
              enableSheetMinification="true"
              fullHandlerPath="~/CnScriptResource.ashx"
              >
                <add key="1" path="~/Scripts/Script01.js" />
                <add key="2" path="~/Scripts/Script02.js" />
                <add key="3" path="~/Scripts/Script03.js" />
                <add key="4" path="~/Styles/test1.css" />
                <add key="5" path="~/Styles/test2.css" />
                <add key="6" path="~/Styles/test3.css" />
            </optimizerSection>

    where the fullHandlerPath is the path to the name of your httphandler that derives from CssJscriptOptimizerHandler and where the key is any arbitrary and URL-friendly unique key value,  and where the path is the path to the script or CSS file in your project. Note that all your script and CSS files that you desire to "C4" in your project should be listed here. Also note that all paths should start with the "~".
    Note that setting the attribute enable="false" will turn off the optimizer.

  3. Create a new handler file for your web project.  Have it derive from CssJscriptOptimizerHandler. The path to this file should be stated in the fullHandlerPath attribute of the optimizerSection.
  4. Register the controls in your *.aspx, *.ascx, and/or *.master files via:
       <%@ Register Assembly="CnCssJscriptOptimizer" 
    	Namespace="CnCssJscriptOptimizer.Controls" TagPrefix="cc1" %>
  5. In your *.aspx file, place the StyleSheetCombiner and ScriptCombiner control tags around your CSS and script declarations. For example:
    <cc1:StyleSheetCombiner ID="sheetCombiner" runat="server">
    <link rel="stylesheet" href="Styles/test1.css" />
    <link rel="stylesheet" href="Styles/test1.css" />
    <link rel="stylesheet" href="Styles/test1.css" />
    <link rel="stylesheet" href="Styles/test1.css" />
    <link rel="stylesheet" href="Styles/test1.css" />
    <link rel="stylesheet" href="Styles/test1.css" />
    <link rel="stylesheet" href="Styles/test1.css" />
    <link rel="stylesheet" href="Styles/test1.css" />
    <link rel="stylesheet" 
    	href='<%# sheetCombiner.ResolveUrl("~/Styles/test2.css")%>' />
    <link rel="stylesheet" 
    	href='<%# sheetCombiner.ResolveUrl("~/Styles/test3.css")%>' />
    	
    </cc1:StyleSheetCombiner>       
    	
    <cc1:ScriptCombiner ID="scriptCombiner" runat="server">
    
    <script src='<%# scriptCombiner.ResolveUrl("~/Scripts/Script01.js")%>' 
            type="text/javascript"></script>
    <script src='<%# scriptCombiner.ResolveUrl("~/Scripts/Script02.js")%>' 
            type="text/javascript"></script>
    <script src="Scripts/Script03.js" type="text/javascript"></script>
    
    </cc1:ScriptCombiner>

    Note: Do not use <%= controlName.ResolveUrl("~/someUrl")%>, but the data binding version <%# controlName.ResolveUrl("~/someUrl")%> instead.  controlName.DataBind() is called internally by the control.

    If any of your stylesheet links makes use of the media or title attribute, then you may not want to include those within the StyleSheetCombiner control because these attributes will be lost, resulting in improper CSS rendering.

Performance

Here is a screenshot with the optimizer enabled:

OptimizerEnabled.JPG

Notice in the picture above that there are two requests made to ResoureHandler.ashx.  The first one is to get all the style sheets. The second one is to retrieve all the JavaScript files.  Total response time (from my slow dev machine and server) for both requests is 2038 milliseconds.

And here is a screenshot with the optimizer not used:

NoOptimizer.JPG

In the above picture, notice that a separate request is made for each script and style sheet file. Total response time to get all the files is over 6000 milliseconds. Now I know that the files are not zipped in this case (no zip feature on the dev server), and that this total may also be misleading because the web server might be processing these requests on multiple threads, but I believe that most browsers can only make, at most, two simultaneous requests for a given page. Therefore, I believe it's safe to say that the optimizer still offers improved performance in most scenarios. You'll have to try it in your environment and see for yourself. The optimizer definitely will cut down on the number of times a client will have to hit your site to get each page.  

Conclusion

This article shows you how to optimize your JavaScript and CSS files in your ASP.NET application by automatically minifying, combining, compressing, and caching them. The library code along with a sample test web application is provided for you. Happy coding.  

History

  • 23rd February, 2009: Initial post
  • 2nd March, 2009: Updated download file
  • 24th March, 2010: Updated download file

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

jeff chin xyz

United States United States
No Biography provided

Comments and Discussions

 
SuggestionMicrosoft has released their Microsoft Ajax Minifier tool http://ajaxmin.codeplex.com Pinmemberdefza29-Nov-11 3:15 
QuestionExcellent! PinmemberSunasara Imdadhusen22-Nov-11 22:50 
QuestionCssMinifier bug Pinmemberalexandrem_blah27-Jul-11 5:08 
GeneralHelp with "Create a new handler file for your web project. " PinmemberMember 438358229-Apr-11 12:33 
GeneralRe: Help with "Create a new handler file for your web project. " Pinmemberjeff chin xyz1-May-11 18:40 
GeneralRe: Help with "Create a new handler file for your web project. " [modified] PinmemberMember 43835822-May-11 6:04 
GeneralThere's a problem with re-writing paths in css files. [modified] Pinmember|\/| |\/| Saffari21-Sep-10 8:31 
GeneralIntellisense! Pinmember|\/| |\/| Saffari8-Sep-10 7:38 
GeneralRe: Intellisense! PinmemberRichardHowells21-Aug-11 3:02 
GeneralRe: Intellisense! Pinmembermmsaffari1-Jan-12 4:04 
GeneralShould this work with someting like Dojo Toolkit dynamic loading of js files? EOM Pinmembericeball1225-Mar-10 0:48 
GeneralFixed 3 bugs in FixUrlPaths function to make it work with jQuery UI 1.8 css Pinmemberalaa9jo24-Mar-10 6:05 
GeneralRe: Fixed 3 bugs in FixUrlPaths function to make it work with jQuery UI 1.8 css Pinmemberjeff chin xyz24-Mar-10 11:10 
GeneralRe: Fixed 3 bugs in FixUrlPaths function to make it work with jQuery UI 1.8 css Pinmemberalaa9jo25-Mar-10 2:58 
QuestionPerfect,well done BUT PinmemberMember 247492323-Mar-10 5:55 
AnswerRe: Perfect,well done BUT Pinmemberjeff chin xyz24-Mar-10 8:58 
GeneralsheetCombiner Pinmemberfriendsterjoel3-Mar-10 20:16 
GeneralRe: sheetCombiner Pinmemberjeff chin xyz8-Mar-10 8:57 
GeneralGreat script! PinmemberImmobilis29-Nov-09 3:16 
QuestionNot able to download PinmemberAskana20-Jul-09 21:20 
AnswerRe: Not able to download Pinmemberjeff chin xyz20-Jul-09 21:28 
QuestionCan we also cache and minify the ajax's javascript? Pinmemberarbound0821-May-09 1:11 
QuestionRequire ASP.NET 2.0 version(3.5 is given) Pinmemberdev4ever16-Mar-09 21:44 
AnswerRe: Require ASP.NET 2.0 version(3.5 is given) Pinmemberjeff chin xyz17-Mar-09 7:50 
Not sure, what errors are you getting?
GeneralRe: Require ASP.NET 2.0 version(3.5 is given) Pinmemberdev4ever8-Apr-09 5:12 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.141220.1 | Last Updated 24 Mar 2010
Article Copyright 2009 by jeff chin xyz
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid