Contact   •   Products   •   Search

Rick Strahl's Web Log

Wind, waves, code and everything in between...
ASP.NET • C# • HTML5 • JavaScript • AngularJs

More on GZip compression with ASP.NET Content


After I posted the GZip Script Compression module code a while back, I’ve gotten a number of questions regarding GZip and compression in ASP.NET applications so I thought I show a couple of other ways you can use the new GZipStream class in ASP.NET.


The beauty of this new GZip support is how easy it is to use in your own ASP.NET code. I use the GZip functionality a bit in my WebLog code. For example the the cached RSS feed is GZip encoded which uses GZipStream on the Response.OutputStream fed to an XmlWriter():

 

Response.ContentType = "text/xml";

 

Stream Output = Response.OutputStream;

 

if (Westwind.Tools.wwWebUtils.IsGZipSupported())

{

    GZipStream gzip = new GZipStream(Response.OutputStream, CompressionMode.Compress);

    Response.AppendHeader("Content-Encoding", "gzip");

    Output = gzip;

}

 

Encoding Utf8 = new UTF8Encoding(false);  // No BOM!

XmlTextWriter Writer = new XmlTextWriter(Output,Utf8);

 

Writer.Formatting = Formatting.Indented;

 

Writer.WriteStartElement("rss");

 

 

Writer.WriteEndElement(); // rss

 

Writer.Close();

Response.End();

 

 

GZipStream is a stream acts like a stream filter so you can assign it to an existing stream like ResponseStream can intercept all inbound data then write the updated data into the actual Response stream. It’s super easy to do.

 

You should always check however if GZip is enabled which is done by this helper method IsGZipSupported() which looks like this:

 

/// <summary>

/// Determines if GZip is supported

/// </summary>

/// <returns></returns>

public static bool IsGZipSupported()

{

    string AcceptEncoding = HttpContext.Current.Request.Headers["Accept-Encoding"];

    if (!string.IsNullOrEmpty(AcceptEncoding) &&

         AcceptEncoding.Contains("gzip") || AcceptEncoding.Contains("deflate") )

        return true;

    return false;

}

 

This ensures that you don’t encode content when the client doesn’t understand GZip and would be unable to read the encoded GZip content. Note that the code checks for either gzip or deflate so this assumes before encoding you’ll pick the right encoding algorithm.

GZip in Page Content

Speaking of encoding -  above was XML and raw ResponseStream encoding, but you can also apply GZip content very, very easily to your page level or any ASP.NET level code (such as in an HTTP handler). In fact, you can use a very generic mechanism to encode any output by using a Response.Filter which the following helper method (also in wwWebUtils) demonstrates:

 

/// <summary>
/// Sets up the current page or handler to use GZip through a Response.Filter
/// IMPORTANT:  
/// You have to call this method before any output is generated!
/// </summary>
public static void GZipEncodePage()
{
    HttpResponse Response = HttpContext.Current.Response;

    if (IsGZipSupported())
    {
        string AcceptEncoding = HttpContext.Current.Request.Headers["Accept-Encoding"];
        if (AcceptEncoding.Contains("deflate"))
        {
            Response.Filter = new System.IO.Compression.DeflateStream(Response.Filter,
                                       System.IO.Compression.CompressionMode.Compress);
            Response.AppendHeader("Content-Encoding", "deflate");
        }
        else
        {
            Response.Filter = new System.IO.Compression.GZipStream(Response.Filter,
                                      System.IO.Compression.CompressionMode.Compress);
            Response.AppendHeader("Content-Encoding", "gzip");                    
        }
    }

    // Allow proxy servers to cache encoded and unencoded versions separately
    Response.AppendHeader("Vary", "Content-Encoding");
}

 

You can now take this helper function and use this in page level code. For example, the main page in my blog which is HUGE (frequently around 500k) uses it like this:

 

protected void Page_Load(object sender, EventArgs e)

{

    wwWebUtils.GZipEncodePage();

 

    Entry = WebLogFactory.GetEntry();

 

    if (Entry.GetLastEntries(App.Configuration.ShowEntryCount, "pk,Title,Body,Entered,Feedback,Location") < 0)

        throw new ApplicationException("Couldn't load WebLog Entries: " + Entry.ErrorMessage);

 

    this.repEntries.DataSource = this.Entry.EntryList;

    this.repEntries.DataBind();

}

 

That’s it. One line and the page will now conditionally GZip encode if the client supports it.

 

If you really wanted to you can take this even one step further and create a module that automatically sets the Response.Filter early in the pipeline and based on that automatically compresses all content.

 

However, remember GZip encoding applies compression on the fly so there’s some overhead in the GZip encoding – you are basically adding more CPU processing to your content to reduce the output size. If your content is not that large to start with there’s probably not that much sense in compressing in the first place so I don’t think that whole-sale compression of dynamic content is a good idea.

 

Caching

But one thing that can mitigate the overhead of GZip compression is caching.

 

Ah yes, both the RSS feed and the home page are usually heavily cached – the content doesn’t change all that frequently so there’s no reason to keep re-generating it right? If you use GZip on your content you have to be careful to cache both the GZipped content and the non-encoded content or else you’ll feed garbage to clients that don’t understand GZip.

 

So for example the default page has:

 

<%@ OutputCache Duration="60" VaryByParam="none" VaryByCustom="GZIP" %>

 

And then a custom Global.asax handler that looks like this:

 

public override string GetVaryByCustomString(HttpContext context, string custom)

{

    if (custom == "GZIP")

    {

        if (Westwind.Tools.wwWebUtils.IsGZipSupported())

            return "GZip";

        return "";

    }

 

    return base.GetVaryByCustomString(context, custom);

}

 

Which results in possibly two different versions of the GZipped page being cached.

 

And there you have it - GZipped content is easy to create now in ASP.NET 2.0/.NET 2.0 and if judiciously applied it can save some significant bandwidth. On my homepage which is close to 500k of blog text content (gotta review that <s>) the GZipped size is 55k or so – nearly a 90% reduction in size. I’d say that’s plenty of worth it, especially when caching is added.

Make Donation
Posted in ASP.NET  .NET  


Feedback for this Post

 
# re: More on GZip compression with ASP.NET Content
by Milan Negovan February 06, 2007 @ 11:18am
Yep, HTML compresses so well because it's highly repetitive.

Like yourself, I've been advocating HTTP compression for a long time and even put together a tool that measures how much bandwidth you can save with various methods and levels of compression: http://www.aspnetresources.com/tools/httpcompression.aspx

Folks in charge of Microsoft.com had better embrace compression. They could be saving ~80%!
# re: More on GZip compression with ASP.NET Content
by Rick Strahl February 06, 2007 @ 3:29pm
Thanks Milan. I just tried this out actually and am kinda curious - what are you using for compression? I tried the Web Log homepage which is now GZip compressed already. Then ran against your analyzer which claims it's reducing the page size down an additional 16% from my original compression. Wonder what's different? You using GZip stream or something else (like XCeed components which are more efficient).

BTW, your site has some great stuff on there! If you haven't gone over to Milan's site do check it out - there are a ton of great articles and a number of useful tools over there.
# Microsoft .NET Info - a tiddlywiki of .NET related information
by Pingback February 07, 2007 @ 11:01am
# A Continuous Learner's Weblog: Links (2/6/2007)
by A Continuous Learner's Weblog February 12, 2007 @ 7:44am
# re: More on GZip compression with ASP.NET Content
by PohEe.com March 01, 2007 @ 3:33pm
I tried your way of compression but my WebResource.axd still included into the compression. I gave up and try <a href = "http://www.blowery.org/code/HttpCompressionModule.html" rel="nofollow" target = "_blank" >blowery compression engine</a>. You just have to follow the describe guide at <a href="http://pohee.com/2007/02/http-compression-in-aspnet-20/" rel="nofollow">http-compression-in-aspnet-20</a> to use it. It is a very good engine but <a href = "http://www.madskristensen.dk/blog/CommentView,guid,60533e14-789d-41a1-92d2-43efddce7d8e.aspx" rel="nofollow">Mads Kristensen's engine</a> also good if it enable us to exclude the WebResource.axd compression. cheers :)<a href="" rel="nofollow"></a><a href="" rel="nofollow"></a>
# re: More on GZip compression with ASP.NET Content
by Rick Strahl March 01, 2007 @ 5:26pm
This class doesn't replace WebResource.axd or in any way changes the way that ASP.NET generates resource output. You have to explicitly request a Resource Url for script in order for the code to do any compression.
# re: More on GZip compression with ASP.NET Content
by rrraven March 05, 2007 @ 2:30am
Ummm... What's wrong with enabling gzip compression for dynamic content in IIS?
# re: More on GZip compression with ASP.NET Content
by Rick Strahl March 05, 2007 @ 11:57am
Very little control, no caching... check the comments above - somebody mentioned this above.
# re: More on GZip compression with ASP.NET Content
by Ray May 08, 2007 @ 10:21am
Why not just do Gzip compression with IIS. This can be done by editing the metabase.
http://weblogs.asp.net/owscott/archive/2004/01/12/57916.aspx
# DotNetSlackers: More on GZip compression with ASP.NET Content
by DotNetSlackers Latest ASP.NET News May 21, 2007 @ 3:59am
# Rick Strahl's Web Log
by Rick Strahl's Web Log June 23, 2007 @ 6:02pm
# re: More on GZip compression with ASP.NET Content
by Arthur September 11, 2007 @ 1:51am
We are using ICSharpCode library in Sitemap Writer Pro (.NET v1.1) for compression of big sitemap files. It's free and very simple to use.
http://www.sitemapwriter.com
# re: More on GZip compression with ASP.NET Content
by Mike Teather September 17, 2007 @ 8:54am
Great article thanks! I used this approach for one of my client's web sites and it speeds things up nicely. We did find an error with the code though, try running IE 6.0 with HTTP 1.0, IsGZipSupported() throws an error since AcceptEncoding is null.

The null check below, requires another set of parenthesis, since A and B or C is true if C is true, clearly the intention was A and (B or C).

if (!string.IsNullOrEmpty(AcceptEncoding) &&
AcceptEncoding.Contains("gzip") || AcceptEncoding.Contains("deflate"))

should be:

if (!string.IsNullOrEmpty(AcceptEncoding) &&
(AcceptEncoding.Contains("gzip") || AcceptEncoding.Contains("deflate")))

Anyway, great article, and thanks for the awesome .net website.
# re: More on GZip compression with ASP.NET Content
by Simon Weijgers September 26, 2007 @ 9:47am
I tried adding this to Application_BeginRequest to gzip everything; (I have a wildcard mapping to map every request to the ASP.NET dll)

If Request.Headers("Accept-Encoding") IsNot Nothing Then
If LCase(Request.Headers("Accept-Encoding")).Contains("gzip") Then
Response.Filter = New GZipStream(Response.Filter, CompressionMode.Compress)
Response.AddHeader("Content-Encoding", "gzip")
ElseIf LCase(Request.Headers("Accept-Encoding")).Contains("deflate") Then
Response.Filter = New DeflateStream(Response.Filter, CompressionMode.Compress)
Response.AddHeader("Content-Encoding", "deflate")
End If
End If

This works fine for the ASPX pages, but for some reason it screws up CSS, and image files. Any ideas?

(note that I can't use IIS compression features because of the wildcard mapping this doesn't seem to work)
# re: More on GZip compression with ASP.NET Content
by wow gold March 05, 2008 @ 5:10am
Cool, the post.

Thanks for the information.
# re: More on GZip compression with ASP.NET Content
by Nader Khader March 10, 2008 @ 1:09am
I know the gzip is a good prog Compression But

how can Gzip less size page like homepage with CSS File and JavaScript file

it can compression all files with same time


thanks for your Time
# More on GZip compression with ASP.NET Content
by DotNetKicks.com March 19, 2008 @ 9:25pm
You've been kicked (a good thing) - Trackback from DotNetKicks.com
# re: More on GZip compression with ASP.NET Content
by Sam March 19, 2008 @ 9:27pm
I found this post really useful and put it on my own site. I also submitted it to dot net kicks. Thanks for the info
# re: More on GZip compression with ASP.NET Content
by Mads Kristensen March 20, 2008 @ 4:24am
Great article. You should consider using deflate instead of GZip if the browser supports it first. The compression rates are exactly the same, but for some reason .NET deflates faster than it GZips. Just swap the order of which encoding you apply to start by asking for deflate support and then GZip afterwards.
# re: More on GZip compression with ASP.NET Content
by Paul Milliken April 28, 2008 @ 8:11am
Just to let you know, I just had the same issue as Mike Teather (above). Only in my case, the null check failed, so the code went on to try AcceptEncoding.Contains("deflate") on a null AcceptEncoding causing an exception to occur.

That'll teach me for not reading through all the comments before using the code in a project.

Please, can the article be updated to include the extra brackets suggested.
# re: More on GZip compression with ASP.NET Content
by Shikhar April 30, 2008 @ 4:36am
Its works fine with static pages. But I am facing issue on those pages which have asp.net validation. My validation dosn't work.
Can any one help me out here.

Thanks
Shikhar
# re: More on GZip compression with ASP.NET Content
by Sambo May 03, 2008 @ 3:09am
Does it work correctly with ASP.NET AJAX?
# re: More on GZip compression with ASP.NET Content
by Arun sharma May 20, 2008 @ 2:03am
It doesn't work with Ajax. As a matter of fact it disables all client side scripts.
# re: More on GZip compression with ASP.NET Content
by Rick Strahl June 18, 2008 @ 2:01am
@Arun - ASP.NET Ajax does all sorts of pipeline injection to generate its output so I suspect that that might not work. However, there's nothing inherent in returning AJAX data that might not work, but if a tool mucks with the content type or encoding then anything you override in this regard as this code does will not work.

For example, i use jQuery for my client output and with that I can easily encode all my output via GZip with no problems.
# re: More on GZip compression with ASP.NET Content
by Jamie July 25, 2008 @ 1:59pm
As some above have indicated, this compression should not be used for requests to WebResource.axd. This is how ASP.NET Ajax injects its javascript into your pages and for some reason compressing its output causes a 0 byte file to be sent to the browser, hence the "[Insert Ajax Method Here] is undefined" errors.

If you are just calling the code above in the Page_Init or Page_Load you shouldn't have to worry about this, but if you have the compression code wired up in Global.asax in BeginRequest or something like that, then you'll need to ensure that you skip compression for requests to WebResource.axd.

There are more elegant ways to do this, but to just hardcode an exclusion of WebResource.axd you could do something like this

public static void GZipEncodePage()

{

    if (IsGZipSupported() && 
       HttpContext.Current.Request.Path.IndexOf("WebResource.axd") == -1)
    {
        // snipped.... but do compression here
     }
}
# re: More on GZip compression with ASP.NET Content
by Rick Strahl July 26, 2008 @ 2:53am
@Jamie - I think it would be a bad idea to wholesale compress pages in your site anyway - this type of approach described here should be selectively used for content IMHO.

I haven't check with MS AJAX output - but shouldn't that be ScriptResource.axd rather than WebResource.axd? The reason that doesn't work most likely is that MS AJAX internally injects into the Http pipeline and applies its own compression so there'd be a problem.

Additional caution may have to be taken with UpdatePanel pages. I'm not sure offhand if this would break UpdatePanel results which also flow through the page pipeline - mainly because it too injects into the page nad filters the Response data.

In short anything that applies Response Filters should not use code the above code for checking whether compression can be applied because the filter order may screw up the compression (especially if another filter already applies compression).
# More on GZip compression with ASP.NET Content
by DotNetShoutout November 19, 2008 @ 6:33am
Your Story is Submitted - Trackback from DotNetShoutout
# re: More on GZip compression with ASP.NET Content
by Martin November 20, 2008 @ 1:39am
Hi I'm trying to use this GZipStream stuff

After I managed to attach with my project it worked...

however after some clicking on my site there and then the site simply crashed.. the web page became a lot of garbage text.. to give some example.

� �������`I�%&/m�{J�J��t��`$ؐ@�����iG#)�*��eVe]f@�흼 ��{���{��;�N'���?\fdl��J�ɞ!���?~|?"~� �=�]�~y���yy���E��������w�{���ݧo�����|�<��o�l�mQ-������ ��v���ݫ���սqU_�}���;������v�9������s��ݢ\6�E �>|�P�|��u�͎/�6K��"��˼.ί�/w?J�ղ͗�g��}� ����O��>�߽�{���O�|���}�^N�Ի���㝟|Y_|�Qz7��6����Yせ� ��(��)�[�.Fi�M�b���t����YN_44�6����u��2����ҫ˲X��G��k�I��3�`Z�W�4k ��Qz^�y;�m[җM���'뢜�ҫ<[U� ˲�ȗS�����:GӺ�j��� �i]�0�0�����9ƞM�1�`(�����#�^��:O��u�W�v��uE_V�i�L�٢������hf��~ [�6��8(!oD�X宀~L/�M�u~��G��X6�u��� �p���}�7s��Gi{�"�`~�r���XJ���X��6�4`Ջ��(����i��jqw]O��r��M���L��p������M?K?��x����;��o�t(_Jo$�ӷy�uG?}|W@��aX��I5����W�B�#kV˼}F|��̫�g���P���g��EѴy=���>�Ii֓EA<��~T��^���'����|�m���b�\f�%~���b^�f9q�`�����?y��͛�W�����.�rM ��7C����~

This weird text was given after around 3-4 times clicking ...

what do you think is the problem?

Am I missing something?

Thanks!
# Kostenloser WEB Space
by Kostenloser WEB Space December 25, 2008 @ 5:34am
Archiv aus Deutschland und aller Welt mit Informationen und Links zum Empfang von Webradio, Web-TV
# re: More on GZip compression with ASP.NET Content
by James Shaw January 01, 2009 @ 10:09pm
Great article Rick! It saved me a lot of time trying to compress pages and other components.

Have a question about the last comment on VaryByCustom in the OutputCache. Can't you use the VaryByContentEncodings attribute of OutputCache?

Loved your simple math captcha below too :).
# re: More on GZip compression with ASP.NET Content
by James Shaw January 02, 2009 @ 10:22am
Should GZipEncodePage() also do

Response.AppendHeader("Vary", "Accept-Encoding");

even if you don't do output cache, since proxy servers in between may cache (read from pg 33 of Steve Souder's High Performance Websites book :))?
# re: More on GZip compression with ASP.NET Content
by Rick Strahl January 02, 2009 @ 10:28am
@James - that's a very good point. I'm adding it to my routine. Thanks.
# RE: (Martin) More on GZip compression with ASP.NET Content
by Yovav February 18, 2009 @ 1:56pm
Martin, (by Martin November 20, 2008 @ 1:39 am)

You are getting garbage because your server (or hosting company) is already applying URL compression to your web site,

So your pages are getting compressed twice,

You will probably will see it when removing temp files (or refresh while holding CTRL+F5)

Here is what you probably have setup on your server: http://www.iis.net/ConfigReference/system.webServer/urlCompression


Just add this in your web config to avoid compression conflicts:
<system.webServer>
<urlCompression doStaticCompression="false" doDynamicCompression="false" dynamicCompressionBeforeCache="false" />
</system.webServer>
# re: More on GZip compression with ASP.NET Content
by Paul April 06, 2009 @ 9:05am
Martin,

Something may also be causing the page_load to occur twice. I found I could use this gzip/deflate into my sitemaster, but not in a page that didn't. For some reason, the page_load is being called twice on a single request. It may have something to do with the page using callbacks, and some asynchronous code. I had to put some extra code in, to not compress on subsequent calls for that page instance.
# re: More on GZip compression with ASP.NET Content
by RickNZ August 20, 2009 @ 4:10am
You mentioned control over caching as a benefit of this approach. Are you sure that Response.Filter is applied before the page goes into the output cache? From my testing, it seems to be applied after a page is retrieved from the output cache, and before it's sent to the client.

If you want to cache the compressed content, you might consider using IIS compression with <urlCompression dynamicCompressionBeforeCache="true" />
# re: More on GZip compression with ASP.NET Content
by Rick Strahl August 20, 2009 @ 11:29am
@Rick - you have full control over setting up the cache. Once cached a url resource won't fire again obviously including the filter until the cache expires or the app restarts.
# re: More on GZip compression with ASP.NET Content
by asp.net iis help March 03, 2010 @ 5:46am
I have a custom implementation of Application_PreRequestHandlerExecute which is applying a delate/gzip filter to the response. However, on IIS7, this is failing on my "script generator" pages. These aspx pages take in Query String values and return a custom bit of script, changing the response type to text/javascript. I think it is failing because of the way iis7 uses mime types, but I'm unsure how to fix it short of turning all compressio off.

Anyone faced this problem?
# re: More on GZip compression with ASP.NET Content
by Mike March 05, 2010 @ 11:33am
Thanks for the code.

Is there an easy way to see if its working?

Trace does not show anything I can see.

Here is the vb.net code:
Public Shared Sub GZipEncodePage()

Dim Response As HttpResponse = HttpContext.Current.Response

'If (IsGZipSupported() And HttpContext.Current.Request.Path.IndexOf(".axd") = -1) Then
If (IsGZipSupported()) Then

Dim AcceptEncoding As String = HttpContext.Current.Request.Headers("Accept-Encoding")
If (AcceptEncoding.Contains("deflate")) Then
Response.Filter = New System.IO.Compression.DeflateStream(Response.Filter, System.IO.Compression.CompressionMode.Compress)
Response.AppendHeader("Content-Encoding", "deflate")
Else
Response.Filter = New System.IO.Compression.GZipStream(Response.Filter, System.IO.Compression.CompressionMode.Compress)
Response.AppendHeader("Content-Encoding", "gzip")
End If
End If

' Allow proxy servers to cache encoded and unencoded versions separately
Response.AppendHeader("Vary", "Content-Encoding")
Response.AppendHeader("Vary", "Accept-Encoding")
End Sub

Public Shared Function IsGZipSupported() As Boolean
Dim AcceptEncoding As String = HttpContext.Current.Request.Headers("Accept-Encoding")

If (Not String.IsNullOrEmpty(AcceptEncoding) And AcceptEncoding.Contains("gzip") Or AcceptEncoding.Contains("deflate")) Then
Return True
End If

Return False
End Function
# re: More on GZip compression with ASP.NET Content
by Tasarim July 09, 2010 @ 2:26am
Thanks a million Rick. I've been searching for articles on how to enable the gzip compression on Asp.NET. Everyone seems to have an article about how to enable it on apache. Gzipping content is extremely vital nowadays since on some complex sites, you have to reduce the content size significantly.

Thanks again!
# # re: More on GZip compression with ASP.NET Content
by Sandesh July 14, 2010 @ 12:07am
Thanks for the artical, I think this link http://www.cmsstores.com/asp-net-file-compression-using-opensource-librar may help some one who is looking to create the zip file using c#.
# re: More on GZip compression with ASP.NET Content
by AlfeG December 27, 2010 @ 3:32am
Martin,
for problem with garbage encoding there is another workaround.

On Application_Error remove filter from response:

protected void Application_Error(Object sender, EventArgs e)
{
HttpApplication app = sender as HttpApplication;
app.Response.Filter = null;
}

This helps me a lot.
# re: More on GZip compression with ASP.NET Content
by oioi April 13, 2011 @ 1:36pm
Cheers Rick

Bit late to the party but this is very handy. Been trying to figure out how to compress and outputcache pages for ages.

Had a problem with the first two lines of IsGZipSupported() like a few others. I was getting an error (Object reference not set to an instance of an object.) when I was checking what was returned in a client didn't accept compressed responses (using this handy tool http://site-perf.com/)

Changed it to (i use VB)

Dim AcceptEncoding As String = HttpContext.Current.Request.Headers("Accept-Encoding") & ""
If AcceptEncoding <> "" And (AcceptEncoding.Contains("gzip") Or AcceptEncoding.Contains("deflate")) Then

Works great for me now. Thanks a lot dude.

Cheers
 


West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2014