ASP.NET Response Compression

Programming .NET Core ASP.NET MVC

Compression is a simple and effective way to save bandwidth and speed up your site.  Here we'll cover both classic ASP.NET MVC and ASP.NET Core.  We will focus on the C# implementation.  There are other ways to enable compression, like f.e. on the web server side.

Compression in ASP.NET MVC

Out of the box ASP.NET supports both gzip and deflate response compression, supported by more or less every browser.  To implement this in ASP.NET MVC5, we can utilize ActionFilterAttribute and override either OnActionExecuting or OnResultExecuting method.

The code below is being used to check whether the current request browser can accept GZIP/DEFLATE encoding by looking at Accept-Encoding request header. If it finds GZIP encoding in this header, then we would set gzip in Content-encoding in response header and if it supports DEFLATE, then this code would set deflate in Content-encoding:

using System;
using System.Collections.Generic;
using System.IO.Compression;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace HTTPCompression.ActionFilters
{
public class CompressAttribute : ActionFilterAttribute
{
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
HttpRequestBase request = filterContext.HttpContext.Request;
string acceptEncoding = request.Headers["Accept-Encoding"];

if (string.IsNullOrEmpty(acceptEncoding))
return;

acceptEncoding = acceptEncoding.ToUpperInvariant();
HttpResponseBase response = filterContext.HttpContext.Response;

if (acceptEncoding.Contains("GZIP"))
{
response.AppendHeader("Content-encoding", "gzip");
response.Filter = new GZipStream(response.Filter, CompressionMode.Compress);
}
else if (acceptEncoding.Contains("DEFLATE"))
{
response.AppendHeader("Content-encoding", "deflate");
response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress);
}
}
}
}

Apply the filter attribute [Compress] to any action wherever you want to apply compression like:

[Compress]
public ActionResult Home()
{
ViewBag.Message = "Landing Page";
return View();
}

Compression in ASP.NET Core

gzip

Let’s get started with gzip compression as it comes out-of-box. First we have to set option for compression and then add compression to request middleware pipeline. We do this in ConfigureServices() method of our Startup class.

services.Configure<GzipCompressionProviderOptions>(options =>
{
options.Level = CompressionLevel.Optimal;
});

services.AddResponseCompression(options =>
{
options.EnableForHttps = true;
options.Providers.Add<GzipCompressionProvider>();
});

For HTTPS we have to say when we want to use compression due to CRIME and BREACH security exploits.  There are three possible values for compression level:

  • NoCompression – compression is ignored
  • Optimal – golden way between compression level and CPU resources (default)
  • Fastest – compressing with minimal effects on server load

Next we have to modify the Configure() method of our Startup class.

// Enable compression
app.UseResponseCompression();
app.UseStaticFiles();
// "UseMvc" has to come after "UseRespCompression"! app.UseMvc(routes => {      routes.MapRoute(          name: "default",          template: "{controller=Home}/{action=Index}/{id?}"); });

Please notice that you have to enable compression before enabling MVC.

Brotli

Brotli is new open-source compression algorithm supported by almost all major browsers. It provides better compression than gzip. Check here to see which browser sopports the Brotli algorithm.

In our code there’s nothing new here. We have already set everything up and introducing Brotli is easy. We have to configure its options and add Brotli compression provider to response compression providers collection, that's all.

services.Configure<BrotliCompressionProviderOptions>(options =>
{
options.Level = CompressionLevel.Optimal;
});

services.AddResponseCompression(options =>
{
options.EnableForHttps = true;
options.Providers.Add<BrotliCompressionProvider>();
});

The Configure() method of our Startup class stays exactly the same like for the GZIP compression.

Controlling compression of static files

By default, these MIME-types are compressed:

  • application/javascript
  • application/json
  • application/xml
  • text/css
  • text/html
  • text/json
  • text/plain

When configuring response compression we can specify our own list of types to compress:

services.AddResponseCompression(options =>
{
IEnumerable<string> MimeTypesToCompress = new[]
{
"text/plain",
"text/html",
"text/css",
"font/woff2",
"application/javascript",
"image/x-icon",
"image/png"
};

options.EnableForHttps = true;
options.MimeTypes = MimeTypesToCompress;
options.Providers.Add<GzipCompressionProvider>();
options.Providers.Add<BrotliCompressionProvider>();
});

Furthermore we can also configure which mime types to exclude from compression:

services.AddResponseCompression(options =>
{
IEnumerable<string> MimeTypesToInclude = new[]
{
"text/html",
"text/css",
"font/woff2",
"application/javascript",
"image/png"
};

IEnumerable<string> MimeTypesToExclude = new[]
{
"text/plain",
"image/x-icon"
};

options.EnableForHttps = true;
options.MimeTypes = MimeTypesToInclude;
options.ExcludedMimeTypes = MimeTypesToExclude;
options.Providers.Add<GzipCompressionProvider>();
options.Providers.Add<BrotliCompressionProvider>();
});

As you see we can provide both (or more) compression algorithms at the same time.  It's up to the client (browser) to pick up its current choice via request headers.

Having provided and configured the compression algorithms doesn’t mean that compression actually happens! Whether compression should be used or not is decided based on browser Accept-Encoding request header. If this header doesn’t specify any configured compression algorithm in code then ASP.NET Core doesn’t compress the requested file.