The abundance and easy availability of CPU at the expense of network bandwidth can be a good reason to use content compression in Web API for faster responses and improved performance Web API is the technology of choice for building RESTful web services in .Net. It supports many media types, with application/json the one that’s widely used. JSON is text based and lightweight and has already become a popular data exchange format for transmitting data over the wire. Compression is an easy way to reduce the network traffic and increase the speed of communication between a resource residing on a web server and a client or a consumer. The two popular algorithms available to achieve this include GZip and Deflate. Both of these algorithms are recognized by the modern day browsers. Since JSON is text-based, it can be compressed using Gzip or Deflate compression to reduce the payload even further. This article presents an overview on how Web API responses can be compressed to reduce network traffic. Reducing the payload There are many ways in which you can compress content that is sent over the wire from your Web API. One way to compress content is by using IIS compression. Using IIS compression, you can perform compression of both static and dynamic content. I’ll discuss IIS compression and its caveats in a post sometime later. For now, you can take a look at this nice article on IIS compression. Another way to compress content in Web API is by using the Microsoft.AspNet.WebApi.MessageHandlers.Compression package. You can install it via NuGet and use it to compress content. To do this, you should add the following statement in the Register method of the WebApiConfig class. GlobalConfiguration.Configuration.MessageHandlers.Insert(0, new ServerCompressionHandler(new GZipCompressor(), new DeflateCompressor())); You can implement a custom delegating handler and attach it to the processing pipeline to compress content but I’ve used an action filter in the next section to demonstrate a simpler way of compressing content in Web API. Implementing a custom action filter to compress content in Web API It’s quite easy to implement GZip encoding using the inbuilt GZipStream and DeflateStream classes. In this section, we will learn how we can use a custom ActionFilter to compress content. To create a custom action filter, create a class that extends the ActionFilterAttribute class as shown in the code snippet below. public class CustomCompressionAttribute : ActionFilterAttribute { public override void OnActionExecuted(HttpActionExecutedContext actionContext) { //Write the custom implementation here } } The next step is to implement the OnActionExecuted method and specify the compression strategies based on the value of the accept-encoding in the request header. public override void OnActionExecuted(HttpActionExecutedContext actionContext) { bool isCompressionSupported = CompressionHelper.IsCompressionSupported(); string acceptEncoding = HttpContext.Current.Request.Headers["Accept-Encoding"]; if (isCompressionSupported) { var content = actionContext.Response.Content; var byteArray = content == null ? null : content.ReadAsByteArrayAsync().Result; MemoryStream memoryStream = new MemoryStream(byteArray); if (acceptEncoding.Contains("gzip")) { actionContext.Response.Content = new ByteArrayContent(CompressionHelper.Compress(memoryStream.ToArray(), false)); actionContext.Response.Content.Headers.Remove("Content-Type"); actionContext.Response.Content.Headers.Add ("Content-encoding", "gzip"); actionContext.Response.Content.Headers.Add ("Content-Type", "application/json"); } else { actionContext.Response.Content = new ByteArrayContent(CompressionHelper.Compress (memoryStream.ToArray())); actionContext.Response.Content.Headers.Remove("Content-Type"); actionContext.Response.Content.Headers.Add("Content-encoding", "deflate"); actionContext.Response.Content.Headers.Add("Content-Type", "application/json"); } } base.OnActionExecuted(actionContext); } Refer to the implementation of the OnActionExecuted method shown above. Note that we first checked if compression is supported using the IsCompressionSupported method of the CompressionHelper class. Here’s how the IsCompressionSupported method looks: public static bool IsCompressionSupported() { string AcceptEncoding = HttpContext.Current.Request.Headers["Accept-Encoding"]; return ((!string.IsNullOrEmpty(AcceptEncoding) && (AcceptEncoding.Contains("gzip") || AcceptEncoding.Contains("deflate")))); } Next, we check if the value of “Accept-Encoding” in the request header and based on its value, we apply the compression logic and the assign the compressed content to the Response.Content property of the “HttpActionExecutedContext” instance named “actionContext”. To compress the content, we take advantage of the Compress method of the CompressionHelper class. You can also use the DotNetZip library available via NuGet to perform the compression, but I’ve used the in-built compression GZipStream and DeflateStream classes available in the System.IO.Compression namespace. Here’s the complete code of the CompressionHelper class for your reference: public class CompressionHelper { public static byte[] Compress(byte[] data, bool useGZipCompression = true) { System.IO.Compression.CompressionLevel compressionLevel = System.IO.Compression.CompressionLevel.Fastest; using (MemoryStream memoryStream = new MemoryStream()) { if(useGZipCompression) { using (System.IO.Compression.GZipStream gZipStream = new System.IO.Compression.GZipStream(memoryStream, compressionLevel, true)) { gZipStream.Write(data, 0, data.Length); } } else { using (System.IO.Compression.GZipStream gZipStream = new System.IO.Compression.GZipStream(memoryStream, compressionLevel, true)) { gZipStream.Write(data, 0, data.Length); } } return memoryStream.ToArray(); } } public static bool IsCompressionSupported() { string AcceptEncoding = HttpContext.Current.Request.Headers["Accept-Encoding"]; return ((!string.IsNullOrEmpty(AcceptEncoding) && (AcceptEncoding.Contains("gzip") || AcceptEncoding.Contains("deflate")))); } } Once the custom action filter has been implemented, you can apply the filter at the controller or the action level based on your needs. The following code snippet illustrates how this attribute can be applied at the action level in your controller class. public class DefaultController : ApiController { [CustomCompression] public HttpResponseMessage Get() { var result = new List<string>(); for (int i = 0; i < 50; i++) result.Add("Hello World"); return Request.CreateResponse(result); } } You can now execute your Web API controller’s action method to see the compression at work! Related content feature 14 great preprocessors for developers who love to code Sometimes it seems like the rules of programming are designed to make coding a chore. Here are 14 ways preprocessors can help make software development fun again. By Peter Wayner Nov 18, 2024 10 mins Development Tools Software Development feature Designing the APIs that accidentally power businesses Well-designed APIs, even those often-neglected internal APIs, make developers more productive and businesses more agile. By Jean Yang Nov 18, 2024 6 mins APIs Software Development news Spin 3.0 supports polyglot development using Wasm components Fermyon’s open source framework for building server-side WebAssembly apps allows developers to compose apps from components created with different languages. By Paul Krill Nov 18, 2024 2 mins Microservices Serverless Computing Development Libraries and Frameworks news Go language evolving for future hardware, AI workloads The Go team is working to adapt Go to large multicore systems, the latest hardware instructions, and the needs of developers of large-scale AI systems. By Paul Krill Nov 15, 2024 3 mins Google Go Generative AI Programming Languages Resources Videos