Minify and Concatenate Your Scripts and Stylesheets Part II - VB.NET

AID: 4395
  • Status: Published

2200 points

  • By
  • TypeGeneral
  • Posted on2011-01-21 at 05:32:42
Awards
  • Community Pick
Welcome my friends to the second instalment and follow-up to our Minify and Concatenate Your Scripts and Stylesheets series.

In this instalment we will be discussing another similar technique that was previously discussed in the first article.

The previous process discussed a method to do this for your .Net website automatically by parsing the outputted HTML for your stylesheets and scripts, combining them into one string each, saving the strings to server cache and finally rendering them through a gzipped output.

This is all done by utilizing a .Net HttpModule.

I thought it would be the perfect solution, but have since found out otherwise.  While the methodology involved remains the same, the delivery method is what is changing.  I have found that if you utilize Master Pages (or have developed a highly customizable CMS system like myself - shameless plug = check my bio), this method simply does not work.

Thus, I set myself the task of making something work.

What I found was that by using a Response.Filter on the IO.Stream of the HTML rendered, we can accomplish the same goals, without any modifications to your web.config file, and without the use of an HttpModule.

In my test configuration, I simply have 3 files (default.aspx, default2.aspx, and default3.aspx);

  • Default.aspx simply is an .Net HTML file with 2 references to 2 seperate stylesheet, 4 references to 4 seperate javascript files, with the filter applied on Page_Load in the code behind
  • Default2.aspx simply contains a placeholder reference for the Master Page we use for it, which happens to contain the same structure as Default.aspx
  • Default3.aspx is the same file as Default.aspx, except it does not contain the filter in the code behind.


For testing we used FireFox, and the handy dandy FireBug plugin, and the results were as such:

  • Default.aspx - Fresh Load - Non-Cached: 3 Requests = 2.25s | Cached: 3 Requests From Cache = 1.67s
  • Default2.aspx - Fresh Load - Non-Cached: 3 Requests = 2.15s | Cached: 3 Requests From Cache = 1.77s
  • Default3.aspx - Fresh Load - Non-Cached: 7 Requests = 3.32s | Cached: 7 Requests No Cache = 3.25s


The biggest thing to note here is the number of requests, and keep in mind this testing is done by VS2008's debugging.

Complete File Listing:

  • /App_Code/Common.vb
  • /App_Code/DynamicCompression.vb
  • /Scripts/custom.js
  • /Scripts/jquery_latest.js
  • /Scripts/jquery.pngFix.pack.js.js
  • /Scripts/jquery.preloadcssimages.js.js
  • /Styles/layout1.css
  • /Styles/layout2.css
  • /Default.aspx w/Code Behind
  • /Default2.aspx w/Code Behind
  • /Default3.aspx w/Code Behind
  • /MasterPage.master w/Code Behind
  • /Script.aspx w/o Code Behind
  • /Style.aspx w/o Code Behind
  • /web.config


(it should be noted that if you do not have an /App_Code/ directory, you can simply add it to your project, or add the files I list above to your class assembly)

And now, without further ado...  the code (I won't bother listing the code for the scripts, stylesheets, or the web.config file...  these will be up to you to have handy...  or just download the package at the end):

/App_Code/Common.vb
Imports Microsoft.VisualBasic

''' <summary>
''' Our common class file
''' </summary>
''' <remarks></remarks>
Public Class Common

    ''' <summary>
    ''' Let's cache this stuff
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared Sub CacheIt()
        ' Allow the browser to store resposes in the 'History' folder
        HttpContext.Current.Response.Cache.SetAllowResponseInBrowserHistory(True)
        ' Set our cacheability to Public
        HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.Public)
        ' Resource is valid until the expiration has passed
        HttpContext.Current.Response.Cache.SetValidUntilExpires(True)
        ' Set out last modified date to last year
        HttpContext.Current.Response.Cache.SetLastModified(Date.Now.AddDays(-366))
        ' We want to store and cache the resource
        HttpContext.Current.Response.AddHeader("Cache-Control", "store, cache")
        ' Set the Pragma to cache
        HttpContext.Current.Response.AddHeader("pragma", "cache")
        ' Not sure if this one really works, but it doesn't throw an error, and Google likes resources served from a cookie-less domain... eh... worth a shot
        HttpContext.Current.Response.AddHeader("Set-Cookie", "false")
        ' Make sure our cache control is Public
        HttpContext.Current.Response.CacheControl = "public" '
        'Set the expiration date of the resource until next year
        HttpContext.Current.Response.Expires = 24 * 60 * 366
        HttpContext.Current.Response.ExpiresAbsolute = DateAdd(DateInterval.Hour, 24 * 366, Date.Now)
    End Sub

    ''' <summary>
    ''' Let's check to see if the browser accepts GZip encoding
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function IsGZipEnabled() As Boolean
        Dim accEncoding As String = HttpContext.Current.Request.Headers("Accept-Encoding")
        'Does the browser accept content encoding?
        If (Not accEncoding Is Nothing) Then
            If (accEncoding.Contains("gzip") Or accEncoding.Contains("deflate")) Then
                Return True
            Else
                Return False
            End If
        Else
            Return False
        End If
    End Function

End Class
                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:

Select allOpen in new window



/App_Code/DynamicCompression.vb
Imports Microsoft.VisualBasic
Imports System.Web
Imports System.Text.RegularExpressions
Imports System.Text
Imports System.IO
Imports System.Web.Caching

Namespace ZipCM

    ''' <summary>
    ''' Our compressor class for miniying and concatenating javascript files and css files
    ''' </summary>
    ''' <remarks></remarks>
    Public Class Compressor
        Inherits System.IO.Stream

#Region " Properties "

#Region " Required Properties by the IO.Stream Interface "

        Public Overrides ReadOnly Property Length() As Long
            Get

            End Get
        End Property

        Public Overrides Property Position() As Long
            Get

            End Get
            Set(ByVal value As Long)

            End Set
        End Property

        Public Overrides ReadOnly Property CanRead() As Boolean
            Get

            End Get
        End Property

        Public Overrides ReadOnly Property CanSeek() As Boolean
            Get

            End Get
        End Property

        Public Overrides ReadOnly Property CanWrite() As Boolean
            Get

            End Get
        End Property

#End Region

#Region " Internal Properties "

        Private HTML As String, FileCSS As String, FileJS As String
        Private context As HttpContext
        Private PageID As Long
        Private Base As System.IO.Stream

#End Region

#End Region

#Region " Methods "

#Region " Public "

#Region " Required by IO.Stream "

        Public Overrides Sub Flush()

        End Sub

        Public Overrides Function Read(ByVal buffer() As Byte, ByVal offset As Integer, ByVal count As Integer) As Integer
            Return Me.Base.Read(buffer, offset, count)
        End Function

        Public Overrides Function Seek(ByVal offset As Long, ByVal origin As System.IO.SeekOrigin) As Long

        End Function

        Public Overrides Sub SetLength(ByVal value As Long)

        End Sub

#End Region

        ''' <summary>
        ''' Fire up our class passing in our Response Stream
        ''' </summary>
        ''' <param name="ResponseStream"></param>
        ''' <remarks></remarks>
        Public Sub New(ByVal ResponseStream As System.IO.Stream)
            ' Just in case it does not exist, let's throw up ;)
            If ResponseStream Is Nothing Then Throw New ArgumentNullException("ResponseStream")
            ' Set our Response to the IO.Stream
            Me.Base = ResponseStream
        End Sub

        ''' <summary>
        ''' We want to overwrite our default Write method so we can do our stuff
        ''' </summary>
        ''' <param name="buffer"></param>
        ''' <param name="offset"></param>
        ''' <param name="count"></param>
        ''' <remarks></remarks>
        Public Overrides Sub Write(ByVal buffer() As Byte, ByVal offset As Integer, ByVal count As Integer)
            ' Get HTML code from the Stream
            HTML = System.Text.Encoding.UTF8.GetString(buffer, offset, count)
            'Compress and Concatenate the CSS
            Me.CompressStyles(HTML)
            'Compress and Concatenate the JS
            Me.CompressJavascript(HTML)
            ' Send output, but replace some unneeded stuff first, like tabs, and multi-spaces
            HTML = HTML.Replace(vbTab, String.Empty).Replace("  ", String.Empty).Replace(vbCrLf, String.Empty)
            ' Set the buffer to the Bytes gotten from our HTML
            buffer = System.Text.Encoding.UTF8.GetBytes(HTML)
            ' Write It Out (not unlike 'Spit It Out - Slipknot'
            Me.Base.Write(buffer, 0, buffer.Length)
        End Sub


#End Region

#Region " Internal "

        ''' <summary>
        ''' Compress and Concatenate Our Style Sheets
        ''' </summary>
        ''' <param name="StrFile"></param>
        ''' <remarks></remarks>
        Private Sub CompressStyles(ByVal StrFile As String)
            Dim FilesM As MatchCollection, FileName As String
            ' Grab all references to stylesheets as they are in our HTML
            FilesM = Regex.Matches(StrFile, "<link.*?href=""(.*?)"".*? />")
            Dim M(FilesM.Count - 1) As String
            ' Now that we have all our files in a match collection, 
            ' we'll loop through each file and put each line together into one string
            For i As Long = 0 To M.Length - 1
                M(i) = FilesM(i).Groups(1).Value
                FileName = HttpContext.Current.Server.MapPath(M(i).Replace("/", "\"))
                FileName = FileName.Replace("\\\", "\")
                ' Make sure the file exists locally, then read the entire thing to add into our string
                If File.Exists(FileName) Then
                    Using objFile As New StreamReader(FileName)
                        FileCSS += objFile.ReadToEnd
                        objFile.Close()
                    End Using
                    ' Now that we have our concatenated string,
                    ' let's replace the unneeded stuff
                    ' Comments
                    FileCSS = Regex.Replace(FileCSS, "/\*.+?\*/", "", RegexOptions.Singleline)
                    ' 2 Spaces
                    FileCSS = FileCSS.Replace("  ", String.Empty)
                    ' Carriage Return
                    FileCSS = FileCSS.Replace(vbCr, String.Empty)
                    ' Line Feed
                    FileCSS = FileCSS.Replace(vbLf, String.Empty)
                    ' Hard Return
                    FileCSS = FileCSS.Replace(vbCrLf, String.Empty)
                    ' Tabs w/ a single space
                    FileCSS = FileCSS.Replace(vbTab, " ")
                    FileCSS = FileCSS.Replace("\t", String.Empty)
                    ' Get rid of spaces next to the special characters
                    FileCSS = FileCSS.Replace(" {", "{")
                    FileCSS = FileCSS.Replace("{ ", "{")
                    FileCSS = FileCSS.Replace(" }", "}")
                    FileCSS = FileCSS.Replace("} ", "}")
                    FileCSS = FileCSS.Replace(" :", ":")
                    FileCSS = FileCSS.Replace(": ", ":")
                    FileCSS = FileCSS.Replace(", ", ",")
                    FileCSS = FileCSS.Replace("; ", ";")
                    FileCSS = FileCSS.Replace(";}", "}")
                    ' Another comment
                    FileCSS = Regex.Replace(FileCSS, "/\*[^\*]*\*+([^/\*]*\*+)*/", "$1")
                End If
            Next
            Dim tmpCt As Long = 0
            ' One more loop to get rid of the multiple references,
            ' and replace it with a sigle reference to our new and improved stylesheet file
            For Each tmpS As Match In FilesM
                tmpCt += 1
                If tmpCt = FilesM.Count Then
                    ' If our count = the number of matches then replace
                    StrFile = StrFile.Replace(tmpS.Groups(0).ToString(), "<link type=""text/css"" rel=""stylesheet"" href=""/Style.aspx"" />")
                Else
                    ' if not, just get rid of it
                    StrFile = StrFile.Replace(tmpS.Groups(0).ToString(), String.Empty)
                End If
            Next
            FilesM = Nothing
            ' Need to put the New and Improved CSS string somewhere!
            ' What a better place for it, then the server cache
            HttpContext.Current.Cache("CSS") = FileCSS
            ' We also need to return the improved HTML
            HTML = StrFile
        End Sub

        ''' <summary>
        ''' Compress Our Scripts
        ''' </summary>
        ''' <param name="StrFile"></param>
        ''' <remarks></remarks>
        Private Sub CompressJavascript(ByVal StrFile As String)
            Dim FilesM1 As MatchCollection, FileName As String
            ' Grab all references to script files as they are in our HTML
            FilesM1 = Regex.Matches(StrFile, "<script.*?src=""(.*?)"".*?></script>")
            Dim M1(FilesM1.Count - 1) As String
            ' Now that we have all our files in a match collection, 
            ' we'll loop through each file and put each line together into one string
            For j As Long = 0 To M1.Length - 1
                M1(j) = FilesM1(j).Groups(1).Value
                FileName = HttpContext.Current.Server.MapPath(M1(j).Replace("/", "\"))
                FileName = FileName.Replace("\\\", "\")
                ' Make sure the file exists locally, then read the entire thing to add into our string
                If File.Exists(FileName) Then
                    Using objFile1 As New StreamReader(FileName)
                        FileJS += objFile1.ReadToEnd
                        objFile1.Close()
                    End Using
                    ' Now that we have our concatenated string,
                    ' let's replace the unneeded stuff
                    ' Comments
                    FileJS = Regex.Replace(FileJS, "(// .*?$)", "", RegexOptions.Multiline)
                    FileJS = Regex.Replace(FileJS, "(/\*.*?\*/)", "", RegexOptions.Multiline)
                    ' 2 Spaces with 1 Space
                    FileJS = FileJS.Replace("  ", " ")
                    ' Carriage Return
                    FileJS = FileJS.Replace(vbCr, vbLf)
                    ' Hard Return w/ Line Feed
                    FileJS = FileJS.Replace(vbCrLf, vbLf)
                    ' Tabs with a single space
                    FileJS = FileJS.Replace(vbTab, " ")
                End If
            Next
            Dim tmpCt1 As Long = 0
            ' One more loop to get rid of the multiple references,
            ' and replace it with a sigle reference to our new and improved stylesheet file
            For Each tmpS As Match In FilesM1
                tmpCt1 += 1
                If tmpCt1 = FilesM1.Count Then
                    ' If our count = the number of matches then replace
                    StrFile = StrFile.Replace(tmpS.Groups(0).ToString(), "<script type=""text/javascript"" src=""/Script.aspx""></script>")
                Else
                    ' if not, just get rid of it
                    StrFile = StrFile.Replace(tmpS.Groups(0).ToString(), String.Empty)
                End If
            Next
            FilesM1 = Nothing
            ' Need to put the New and Improved JS Somewhere!
            ' What a better place for it then the server cache
            HttpContext.Current.Cache("JS") = FileJS
            ' Also need to return the New and Improved HTML
            HTML = StrFile
        End Sub

#End Region

#End Region

    End Class

End Namespace
                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
221:
222:
223:
224:
225:
226:
227:
228:
229:
230:
231:
232:
233:
234:
235:
236:
237:
238:
239:
240:
241:
242:
243:
244:
245:
246:
247:
248:
249:
250:
251:
252:
253:
254:
255:
256:
257:
258:
259:
260:
261:
262:
263:
264:
265:
266:

Select allOpen in new window



/Default.aspx
<%@ Page Language="VB" AutoEventWireup="false" CodeFile="Default.aspx.vb" Inherits="_Default" Debug="true" %>
<!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>
        <title>Untitled Page</title>
        <meta http-equiv="Content-Script-Type" content="text/javascript" />
        <meta http-equiv="Content-Style-Type" content="text/css" />
        <link href="/styles/layout1.css" rel="stylesheet" type="text/css" />
        <link href="/styles/layout2.css" rel="stylesheet" type="text/css" />
    </head>
    <body>
        Just a test to make sure the CSS and JS works
        <a href="javascript:;" onclick="alert($('body').html());">Click Here</a>
        <script type="text/javascript" src="/scripts/jquery.js"></script>
        <script type="text/javascript" src="/scripts/jquery.pngFix.pack.js"></script>
        <script type="text/javascript" src="/scripts/jquery.preloadcssimages.js"></script>
        <script type="text/javascript" src="/scripts/custom.js"></script>
    </body>
</html>
                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:

Select allOpen in new window



/Default.aspx.vb - The Code-Behind
Partial Class _Default
    Inherits System.Web.UI.Page

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        'Enable GZip Encoding for this page
        If Common.IsGZipEnabled() Then
            Dim accEncoding As String
            accEncoding = Context.Request.Headers("Accept-Encoding")
            If accEncoding.Contains("gzip") Then
                Response.Filter = New System.IO.Compression.GZipStream(Response.Filter, System.IO.Compression.CompressionMode.Compress)
                Response.AppendHeader("Content-Encoding", "gzip")
            Else
                Response.Filter = New System.IO.Compression.DeflateStream(Response.Filter, System.IO.Compression.CompressionMode.Compress)
                Response.AppendHeader("Content-Encoding", "deflate")
            End If
        End If
        'Cache our response in the browser
        Common.CacheIt()
        'Concatenate and Minify our Scripts and Stylesheets
        Response.Filter = New ZipCM.Compressor(Response.Filter)
    End Sub

End Class
                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:

Select allOpen in new window



/Default2.aspx - Blank Code-Behind
<%@ Page Language="VB" MasterPageFile="~/MasterPage.master" AutoEventWireup="false" CodeFile="Default2.aspx.vb" Inherits="Default2" title="Untitled Page" %>

<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
Just a test to make sure the CSS and JS works
        <a href="javascript:;" onclick="alert($('body').html());">Click Here</a>
</asp:Content>
                                    
1:
2:
3:
4:
5:
6:

Select allOpen in new window



/Default3.aspx - Blank Code-Behind, contains the exact same code as /Default.aspx, except without the Code-Behind Processing

/MasterPage.master
<%@ Master Language="VB" CodeFile="MasterPage.master.vb" Inherits="MasterPage" %>
<!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>
        <title>Untitled Page</title>
        <meta http-equiv="Content-Script-Type" content="text/javascript" />
        <meta http-equiv="Content-Style-Type" content="text/css" />
        <link href="/styles/layout1.css" rel="stylesheet" type="text/css" />
        <link href="/styles/layout2.css" rel="stylesheet" type="text/css" />
    </head>
    <body>
        <asp:ContentPlaceHolder id="ContentPlaceHolder1" runat="server">
        
        </asp:ContentPlaceHolder>
        <script type="text/javascript" src="/scripts/jquery.js"></script>
        <script type="text/javascript" src="/scripts/jquery.pngFix.pack.js"></script>
        <script type="text/javascript" src="/scripts/jquery.preloadcssimages.js"></script>
        <script type="text/javascript" src="/scripts/custom.js"></script>
    </body>
</html>
                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:

Select allOpen in new window



/MasterPage.master.vb
Partial Class MasterPage
    Inherits System.Web.UI.MasterPage

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        'Enable GZip Encoding for this page
        If Common.IsGZipEnabled() Then
            Dim accEncoding As String
            accEncoding = Context.Request.Headers("Accept-Encoding")
            If accEncoding.Contains("gzip") Then
                Response.Filter = New System.IO.Compression.GZipStream(Response.Filter, System.IO.Compression.CompressionMode.Compress)
                Response.AppendHeader("Content-Encoding", "gzip")
            Else
                Response.Filter = New System.IO.Compression.DeflateStream(Response.Filter, System.IO.Compression.CompressionMode.Compress)
                Response.AppendHeader("Content-Encoding", "deflate")
            End If
        End If
        'Cache our response in the browser
        Common.CacheIt()
        'Concatenate and Minify our Scripts and Stylesheets
        Response.Filter = New ZipCM.Compressor(Response.Filter)
    End Sub
End Class
                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:

Select allOpen in new window



/Script.aspx
<%@ Page Language="VB" %>
<% 
    'Enable GZip Encoding
    If Common.IsGZipEnabled() Then
        Dim accEncoding As String
        accEncoding = Context.Request.Headers("Accept-Encoding")
        If accEncoding.Contains("gzip") Then
            Context.Response.Filter = New System.IO.Compression.GZipStream(Context.Response.Filter, System.IO.Compression.CompressionMode.Compress)
            Context.Response.AppendHeader("Content-Encoding", "gzip")
        Else
            Context.Response.Filter = New System.IO.Compression.DeflateStream(Context.Response.Filter, System.IO.Compression.CompressionMode.Compress)
            Context.Response.AppendHeader("Content-Encoding", "deflate")
        End If
    End If
    'Cache our response in the browser
    Common.CacheIt()
    'Set the content type to output true javascript
    Response.ContentType = "text/javascript"
    If Not (Cache("JS") Is Nothing) Then
        'write out the javascript string from our cache
        Response.Write(Cache("JS").ToString())
    End If
    %>
                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:

Select allOpen in new window



/Style.aspx
<%@ Page Language="VB" %>
<% 
    'Enable GZip Encoding
    If Common.IsGZipEnabled() Then
        Dim accEncoding As String
        accEncoding = Context.Request.Headers("Accept-Encoding")
        If accEncoding.Contains("gzip") Then
            Context.Response.Filter = New System.IO.Compression.GZipStream(Context.Response.Filter, System.IO.Compression.CompressionMode.Compress)
            Context.Response.AppendHeader("Content-Encoding", "gzip")
        Else
            Context.Response.Filter = New System.IO.Compression.DeflateStream(Context.Response.Filter, System.IO.Compression.CompressionMode.Compress)
            Context.Response.AppendHeader("Content-Encoding", "deflate")
        End If
    End If
    'Cache our response in the browser
    Common.CacheIt()
    'Set the content type to output true CSS
    Response.ContentType = "text/css"
    If Not (Cache("CSS") Is Nothing) Then
        'Write it out from the cache
        Response.Write(Cache("CSS").ToString())
    End If
    %>
                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:

Select allOpen in new window



Here's the complete un-compiled project
make sure you run this in a dev environment so you can tweak it to your needs before deploying.
Test-Project.zip
  • 60 KB
  • Our Test Project
Test-Project.zip
    Asked On
    2011-01-21 at 05:32:42ID4395
    Tags

    .net

    ,

    vb.net

    ,

    minification

    Topic

    .NET

    Views
    1093

    Comments

    Author Comment

    by: kevp75 on 2011-02-02 at 09:41:32ID: 23418

    Just wanted to post a little side note on this.  I recently ran into an issue with this in a production environment with a site, that did a ton of heavy processing in the Page_Load event.

    What I found was that even though there would be no Exceptions thrown, the Script.aspx, and Style.aspx would have no response.

    To cure the issue, I simply moved the heavy processing into the Page_Init event, and kept the Response.Filter in the Page_Load event, and it worked perfectly...

    So, What I would suggest is a slight change to the first Default.aspx page above.

    Copy everything from Page_Load event except the Response.Filter line and paste it into Page_Init event.

    ~ Happy Coding!

    Add your Comment

    Please Sign up or Log in to comment on this article.

    Join Experts Exchange Today

    Gain Access to all our Tech Resources

    Get personalized answers

    Ask unlimited questions

    Access Proven Solutions

    Search 3.2 million solutions

    Read In-Depth How-To Guides

    1000+ articles, demos, & tips

    Watch Step by Step Tutorials

    Learn direct from top tech pros

    And Much More!

    Your complete tech resource

    See Plans and Pricing

    30-day free trial. Register in 60 seconds.

    Loading Advertisement...

    Top .NET Programming Experts

    1. CodeCruiser

      588,856

      Sage

      6,000 points yesterday

      Profile
      Rank: Genius
    2. kaufmed

      377,702

      Wizard

      10 points yesterday

      Profile
      Rank: Genius
    3. BuggyCoder

      268,007

      Guru

      1,600 points yesterday

      Profile
      Rank: Sage
    4. TheLearnedOne

      232,552

      Guru

      4,900 points yesterday

      Profile
      Rank: Savant
    5. Idle_Mind

      193,005

      Guru

      0 points yesterday

      Profile
      Rank: Savant
    6. JamesBurger

      156,812

      Guru

      2,000 points yesterday

      Profile
      Rank: Sage
    7. wdosanjos

      124,308

      Master

      2,000 points yesterday

      Profile
      Rank: Genius
    8. Dhaest

      115,720

      Master

      0 points yesterday

      Profile
      Rank: Genius
    9. sedgwick

      112,918

      Master

      1,600 points yesterday

      Profile
      Rank: Genius
    10. nepaluz

      101,325

      Master

      0 points yesterday

      Profile
      Rank: Sage
    11. MlandaT

      95,921

      Master

      2,100 points yesterday

      Profile
      Rank: Genius
    12. navneethegde

      74,442

      Master

      0 points yesterday

      Profile
      Rank: Wizard
    13. Masteraco

      70,367

      Master

      0 points yesterday

      Profile
      Rank: Wizard
    14. binaryevo

      70,365

      Master

      0 points yesterday

      Profile
      Rank: Guru
    15. ambience

      69,104

      Master

      0 points yesterday

      Profile
      Rank: Sage
    16. emoreau

      68,230

      Master

      0 points yesterday

      Profile
      Rank: Genius
    17. PaulHews

      49,486

      0 points yesterday

      Profile
      Rank: Genius
    18. AndyAinscow

      45,290

      0 points yesterday

      Profile
      Rank: Genius
    19. Chinmay_Patel

      43,411

      0 points yesterday

      Profile
      Rank: Genius
    20. ged325

      41,700

      2,600 points yesterday

      Profile
      Rank: Genius
    21. RolandDeschain

      41,317

      0 points yesterday

      Profile
      Rank: Sage
    22. nishantcomp2512

      39,486

      0 points yesterday

      Profile
      Rank: Wizard
    23. tommyBoy

      36,550

      0 points yesterday

      Profile
      Rank: Genius
    24. mroonal

      35,000

      0 points yesterday

      Profile
      Rank: Sage
    25. santhimurthyd

      34,650

      0 points yesterday

      Profile
      Rank: Wizard

    Hall Of Fame