Can gzip compression be selectively disabled in ASP.NET/IIS 7?

10,064

Solution 1

@Aristos' answer will work for WebForms, but with his help, I've adapted a solution more inline with ASP.NET/MVC methodology.

Create a new filter to provide the gzipping functionality:

public class GzipFilter : ActionFilterAttribute
{
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        base.OnActionExecuted(filterContext);

        var context = filterContext.HttpContext;
        if (filterContext.Exception == null && 
            context.Response.Filter != null &&
            !filterContext.ActionDescriptor.IsDefined(typeof(NoGzipAttribute), true))
        {
            string acceptEncoding = context.Request.Headers["Accept-Encoding"].ToLower();;

            if (acceptEncoding.Contains("gzip"))
            {
                context.Response.Filter = new GZipStream(context.Response.Filter, CompressionMode.Compress);
                context.Response.AppendHeader("Content-Encoding", "gzip");
            }                       
            else if (acceptEncoding.Contains("deflate"))
            {
                context.Response.Filter = new DeflateStream(context.Response.Filter, CompressionMode.Compress);
                context.Response.AppendHeader("Content-Encoding", "deflate");
            } 
        }
    }
}

Create the NoGzip attribute:

public class NoGzipAttribute : Attribute {
}

Prevent IIS7 from gzipping using web.config:

<system.webServer>
    ...
    <urlCompression doStaticCompression="true" doDynamicCompression="false" />
</system.webServer>

Register your global filter in Global.asax.cs:

protected void Application_Start()
{
    ...
    GlobalFilters.Filters.Add(new GzipFilter());
}

Finally, consume the NoGzip attribute:

public class MyController : AsyncController
{
    [NoGzip]
    [NoAsyncTimeout]
    public void GetProgress(int id)
    {
        AsyncManager.OutstandingOperations.Increment();
        ...
    }

    public ActionResult GetProgressCompleted() 
    {
        ...
    }
}

P.S. Once again, many thanks to @Aristos, for his helpful idea and solution.

Solution 2

I found a much easier way to do this. Instead of selectively doing your own compression, you can selectively disable the default IIS compression (assuming its enabled in your web.config).

Simply remove the accept-encoding encoding header on the request and IIS wont compress the page.

(global.asax.cs:)

protected void Application_BeginRequest(object sender, EventArgs e)
{
    try
    {
        HttpContext.Current.Request.Headers["Accept-Encoding"] = "";
    }
    catch(Exception){}
}

Solution 3

What about you set the gzip compression by your self, selectivle when you wish for ? On the Application_BeginRequest check when you like to make and when you dont make compression. Here is a sample code.

protected void Application_BeginRequest(Object sender, EventArgs e)
{
    string cTheFile = HttpContext.Current.Request.Path;
    string sExtentionOfThisFile = System.IO.Path.GetExtension(cTheFile);

    if (sExtentionOfThisFile.Equals(".aspx", StringComparison.InvariantCultureIgnoreCase))
    {
        string acceptEncoding = MyCurrentContent.Request.Headers["Accept-Encoding"].ToLower();;

        if (acceptEncoding.Contains("deflate") || acceptEncoding == "*")
        {
            // defalte
            HttpContext.Current.Response.Filter = new DeflateStream(prevUncompressedStream,
                CompressionMode.Compress);
            HttpContext.Current.Response.AppendHeader("Content-Encoding", "deflate");
        } else if (acceptEncoding.Contains("gzip"))
        {
            // gzip
            HttpContext.Current.Response.Filter = new GZipStream(prevUncompressedStream,
                CompressionMode.Compress);
            HttpContext.Current.Response.AppendHeader("Content-Encoding", "gzip");
        }       
    }
}
Share:
10,064
Kirk Woll
Author by

Kirk Woll

Shouldn't you be reading something more interesting? :p Other than hanging out with my cats and flying small airplanes, in my free time I like to work on various side projects (see GitHub) Currently, I'm employed as the manager for mobile platforms at PlanGrid. If you want a job at an amazing company (who wouldn't?) then hit me up! :) Also, author of WootzJs, a C# to Javascript cross-compiler. That project was fun, but at this point, I'd highly recommend the Blazor project as the future for this sort of endeavor. Also wrote ReactiveUI.Fody, a Fody plugin that generates the necessary boiler-plate when using ReactiveUI (now integrated into the ReactiveUI repo). @kirkwoll on Twitter. I also occasionally blog.

Updated on June 05, 2022

Comments

  • Kirk Woll
    Kirk Woll almost 2 years

    I am using a long-lived asynchronous HTTP connection to send progress updates to a client via AJAX. When compression is enabled, the updates are not received in discrete chunks (for obvious reasons). Disabling compression (by adding a <urlCompression> element to <system.webServier>) does solve the problem:

    <urlCompression doStaticCompression="true" doDynamicCompression="false" />
    

    However, this disables compression site-wide. I would like to preserve compression for every other controller and/or action except for this one. Is this possible? Or am I going to have to create a new site/area with its own web.config? Any suggestions welcome.

    P.S. the code that does the writing to the HTTP response is:

    var response = HttpContext.Response;
    response.Write(s);
    response.Flush();
    
  • Kirk Woll
    Kirk Woll about 13 years
    thanks for your help. I've used your guidance to create the solution I describe in my answer.
  • Kirk Woll
    Kirk Woll over 9 years
    It's extremely bad practice to modify the request headers on the server side. You are basically hacking on the server to forge the request headers to modify server-side behavior. That's fraught, to say the least.