Handling Compression (Accept-Encoding) Sample
Long time back there was a question on forums regarding how we could achieve compression scenario via Accept-Encoding headers in Web API. Thought of bringing that sample here so that it could be useful for anyone looking for this kind of functionality.
NOTE: ASP.NET Web API doesn’t have inherent support for Accept-Encoding header.
Let’s assume we have the following controller which is returning 3 different HttpContents: StringContent, StreamContent & ObjectContent.
public class AcceptEncodingTestsController : ApiController
{
[HttpGet]
public HttpResponseMessage GetStringContent()
{
HttpResponseMessage response = new HttpResponseMessage();
response.Content = new StringContent("Hello World!");
return response;
}
[HttpGet]
public HttpResponseMessage GetStreamContent()
{
HttpResponseMessage response = new HttpResponseMessage();
response.Content = new StreamContent(new FileStream(@"D\Sample.txt", FileMode.Open));
response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/plain");
return response;
}
[HttpGet]
public Customer GetCustomer() // the return value is actually converted to ObjectContent
{
return new Customer() { Id = 100, DateOfBirth = new DateTime(1975, 4, 3) };
}
}
Encoding handler:
public class EncodingDelegateHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
return base.SendAsync(request, cancellationToken).ContinueWith<HttpResponseMessage>((responseToCompleteTask) =>
{
HttpResponseMessage response = responseToCompleteTask.Result;
if (response.RequestMessage.Headers.AcceptEncoding != null &&
response.RequestMessage.Headers.AcceptEncoding.Count > 0)
{
string encodingType = response.RequestMessage.Headers.AcceptEncoding.First().Value;
response.Content = new CompressedContent(response.Content, encodingType);
}
return response;
},
TaskContinuationOptions.OnlyOnRanToCompletion);
}
}
public class CompressedContent : HttpContent
{
private HttpContent originalContent;
private string encodingType;
public CompressedContent(HttpContent content, string encodingType)
{
if (content == null)
{
throw new ArgumentNullException("content");
}
if (encodingType == null)
{
throw new ArgumentNullException("encodingType");
}
originalContent = content;
this.encodingType = encodingType.ToLowerInvariant();
if (this.encodingType != "gzip" && this.encodingType != "deflate")
{
throw new InvalidOperationException(string.Format("Encoding '{0}' is not supported. Only supports gzip or deflate encoding.", this.encodingType));
}
// copy the headers from the original content
foreach (KeyValuePair<string, IEnumerable<string>> header in originalContent.Headers)
{
this.Headers.TryAddWithoutValidation(header.Key, header.Value);
}
this.Headers.ContentEncoding.Add(encodingType);
}
protected override bool TryComputeLength(out long length)
{
length = -1;
return false;
}
protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
{
Stream compressedStream = null;
if (encodingType == "gzip")
{
compressedStream = new GZipStream(stream, CompressionMode.Compress, leaveOpen: true);
}
else if (encodingType == "deflate")
{
compressedStream = new DeflateStream(stream, CompressionMode.Compress, leaveOpen: true);
}
return originalContent.CopyToAsync(compressedStream).ContinueWith(tsk =>
{
if (compressedStream != null)
{
compressedStream.Dispose();
}
});
}
}
Register the handler:
config.MessageHandlers.Add(new EncodingDelegateHandler());
With the above example you should see that all the 3 types of contents are compressed via the encoding handler.
Comments
Anonymous
September 12, 2012
is it possible to write an application using the python languageAnonymous
September 19, 2012
You have given really good article. I will following your other posts in the future. Thank you really much. <a href="food-machine.org/.../index.html">Coffee making machine</a>Anonymous
February 26, 2013
Nice article!Anonymous
June 24, 2013
I tried this approach, but somehow in Fiddler or IE developer tools (Visual Studio 2010, IISExpress), i cannot see that the response was gzipped. I don't see the Transport header named "Content-Encoding" with a value of gzip. Is there something wrong with my setup?Anonymous
July 29, 2015
Need to send Json string as output ... which is nearly 450mb.. I stuck to send it as HTTP Response message content .. Please give me suggestion and mail me ... vasanthitser@live.comAnonymous
August 10, 2015
The comment has been removedAnonymous
August 10, 2015
Updated version crediting this source can be found here: benfoster.io/.../aspnet-web-api-compression Blaine Manock