Mvc WebApi Optimization - Accept Compressed Response

Recently I was developing a MVC application that consumes REST services from a third party. One of the methods in the service was returning over 20,000 records as collection of JSON objects. It was taking decent amount of time receive response and then save the data in the database. Most of the time the request will time out because of the time it took for whole operation to complete.

So it was time to optimize how MVC application was consuming this REST service. After contacting the developers of REST service, I found out that service was capable of returning compressed response. This is exactly the answer I was looking for. There was only one issue that MVC methods like ReadAsSync etc. are not able to handle compressed response out of the box. I had to implement some utility methods to plug into the pipeline to get this working.

Here are things that you can do to receive compressed (gzip, deflate etc.) response and then consume it to deserialize JSON response into your strongly typed objects.

  • The most important step in this optimization process is that you have let the service know that your client is capable of accepting compressed response. This is accomplished by sending appropriate values in Accept-Encoding http header.

    httpClient.DefaultRequestHeaders.Add("Accept-Encoding", "deflate,gzip");
                

    The value for this header is comma separated list of media formats that your client is capable of handling. The entries in the list should be in order of preference that your client would like to accept. This is just suggestion to the server. The server can ignore this header if it can not send compressed response or the format that you are requesting. This means when your client receives response, it should check the format. In a little bit I will show this is done.

  • Once header is set, send request to server to get response.

    var resp = httpClient.GetAsync(requestUrl).Result;
    resp.EnsureSuccessStatusCode();
                
  • Now you have fun part of handling response. First you will have to check Content-Encoding header. This header will have value of format type for response stream. If the format type if one of the values that you have sent in Accept-Encoding header then you uncompress the response into string format. Next you will deserialize this response into strongly typed object using Json.Net. Following code snippet shows utility methods that I have put together to handle compressed response.

    public static class WebApiHelper
    {
      public static T ReadResponse<T>(HttpResponseMessage responseMessage)
      {
          var contentEncoding = responseMessage.Content.Headers.GetValues("Content-Encoding");
          if (!contentEncoding.Any())
          {
             return responseMessage.Content.ReadAsAsync<T>().Result;
          }
          var encoding = contentEncoding.Single().ToLower();
          if (string.Compare(encoding, "gzip", true) == 0)
          {
             var responseStream = responseMessage.Content.ReadAsStreamAsync().Result;
             var response = DecompressResponse(responseStream);
             return JsonConvert.DeserializeObject<T>(response);
           }
           else
           {
             throw new ApplicationException("Invalid response content encoding: " + encoding);
           }
      }
    
      public static string DecompressResponse(Stream responseStream)
      {
         var gzipStream = new GZipStream(responseStream, CompressionMode.Decompress);
         var destinationStream = new MemoryStream();
         gzipStream.CopyTo(destinationStream);
         return Encoding.ASCII.GetString(destinationStream.ToArray());
      }
    }
                

    Here is how this helper class is used to read response.

    var responseData = WebApiHelper.ReadResponse<MyObject>(resp);
                

In subsequent posts I will discuss more about MVC Web Api optimization steps that you can take to improve performance of your client side as well as server side implementation.

comments powered by Disqus

Search

Social

Weather

30.8 °C / 87.4 °F

weather conditions Clouds

Monthly Posts

Blog Tags