X

ASP.NET Core response compression and content encoding

ASP.NET Core supports response compression. From popular algorithms gzip and Brotli are supported. Those who like can also implement their own response compression providers. This blog post shows how to response compression works in ASP.NET Core.

With ASP.NET Core we have three options for compression:

  1. ASP.NET Core does compression
  2. Front-end web server does compression
  3. Static files are precompressed

We can skip second and third option here because we are interested in how ASP.NET Core carries out response compression. Those who don’t use Microsoft.AspNetCore.App metapackage must add reference to Microsoft.AspNetCore.ResponseCompression NuGet package to enable response compression.

Test page

I’m using simple test page for this guide. Not much content, not many files and effects of compression are easy to see and compare.

By default, without any compression page loads like shown on image below.

When read from cache the numbers are different.

I start with a table to visualize effects of response compression better.

Compression Response size (KB) %
No compression 764.99 100.00
No compression, from cache 11.25 1.47

Let’s leave these numbers here for a moment and let’s make compression work.

gzip

Let’s get started with gzip compression as it comes out-of-box. No tricks, no miracles. First we have to set option for compression and then add compression to request middleware pipeline. We do it in ConfigureServices() method of 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 Configure() method of Startup class.

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

BUG!!! I made one bad mistake in code above but let’s get to it later as it doesn’t affect what we are doing right now.

Let’s try to load the page with both compession levels. We start with fastest compression and then try optimal.

gzip with Fastest compression level

gzip with Optimal compression level

And let’s write the results to table.

Compression Response size (KB) %
No compression 764.99 100.00
No compression, from cache 11.25 1.47
gzip, fastest 652.62 85.31
gzip, optimal 652.43 85.23

Numbers are very similar for both compression levels. It should ring the alarm bell for those readers who have worked with response compression before. But we get to it later.

Brotli

Brotli is new open-source compression algorithm supported by almost all major browsers. It provides better compression that gzip. More information about browsers support for Brotli is available at Can I Use… site.

On our application side there’s nothing very much different. We have already everything configured and introducing Brotli is easy. We have to configure its options and add Brotli compression provider to response compression providers collection.

services.Configure<BrotliCompressionProviderOptions>(options =>
{
     options.Level = CompressionLevel.Optimal;
});
 
services.AddResponseCompression(options =>
{
     options.EnableForHttps = true;     options.Providers.Add<BrotliCompressionProvider>();
});

With brotli enabled let’s make also two tests – one with each compression level.

Brotli with Fastest compression level

Brotly with Optimal compression level

Let’s add these results to table.

Compression Response size (KB) %
No compression 764.99 100.00
No compression, from cache 11.25 1.47
gzip, fastest 652.62 85.31
gzip, optimal 652.43 85.23
Brotli, fastest 652.74 85.32
Brotli, optimal 651.83 85.21

Almost on the same level with gzip and it seems weird to me. Why introduce new compression algorithm if benefits are so small? Okay, time to confess…

Compressing static files

I did great on wiping some dust under carpet before and I didn’t stop on closed investigation of static files. Let’s run application and see some static file.

Not compressed, why? The question comes down to request middleware ordering in application start-up. We have to put compression before static files in Configure() method. Otherwise static files middleware finds static file and returns it immediately.

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

With static files properly managed let’s run application again to see the results.

Compression Response size (KB) %
No compression 764.99 100.00
No compression, from cache 11.25 1.47
gzip, fastest 289.92 37.90
gzip, optimal 268.92 35.15
Brotli, fastest 293.74 38.40
Brotli, optimal 252.65 33.03

When we compare the results now we can see more difference. Brotli with optimal compression is faster and it gives even more effect when responses are bigger than I had.

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> MimeTypes = new[]
     {
         // General
         "text/plain",
         "text/html",
         "text/css",
         "font/woff2",
         "application/javascript",
         "image/x-icon",
         "image/png"
     };

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

Similar way we can exclude set of MIME-types from compression.

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

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

Having type if list of allowed types doesn’t mean that compression happens. When activated then compression to use is decided based on browser Accept-Encoding header. If this header doesn’t specify any known compression algorithm then ASP.NET Core doesn’t compress the requested file.

Wrapping up

Response compression can save us a lot of traffic when applied in ASP.NET Core web application. Public interface of response compression API is simple and flexible. We can control compression level and MIME-types to be compressed. For static files we have to include response compression before static files middleware because otherwise it is not run. And as we saw then new Brotli compression is better than older gzip.

Liked this post? Empower your friends by sharing it!
Categories: ASP.NET

View Comments (6)

  • I have not seen much effect on compressing png or jpg. What works best for images is optimizing these with special software or online services. It's more effective as optimization is done once and it doesn't add any load to server later.

  • Hi Gunnar, great article!

    It would be great if you could help me:

    I have a JSON, and I am sending a byte array inside one of the JSON Properties.

    However, even when receiving the response with the Content-Encoding as gzip, the size of the payload is the same as not using the gzip compression (I am using Postman).

    Do you have any idea of what is happening?

    Cheers!

  • Hi,
    Is size exactly the same or similar? If similar then I think the problem is about byte array. Usually binary data doesn't compress very well and in some cases compressed binary can be even larger than original one.

  • Hello Sir,
    I am using ASP.net core + Angular Project, I want to use in that project could you help me out

Related Post