DelegatingHandler for GZip in ASP.NET Web API
public class GzipHandler : DelegatingHandler | |
{ | |
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) | |
{ | |
if (request.Content != null && | |
request.Content.Headers.ContentType != null && | |
(request.Content.Headers.ContentType.MediaType == "application/gzip" || | |
request.Content.Headers.ContentType.MediaType == "application/deflate")) | |
{ | |
string encodingType = request.Content.Headers.ContentType.MediaType.Split('/').Last(); | |
Stream stream; | |
if (encodingType == "gzip") | |
{ | |
stream = new GZipStream(await request.Content.ReadAsStreamAsync(), CompressionMode.Decompress); | |
} | |
else if (encodingType == "deflate") | |
{ | |
stream = new DeflateStream(await request.Content.ReadAsStreamAsync(), CompressionMode.Decompress); | |
} | |
else | |
{ | |
throw new HttpException(HttpStatusCode.UnsupportedMediaType, string.Format("Encoding '{0}' is not supported. Only supports gzip or deflate encoding.", encodingType)); | |
} | |
request.Content = new DecompressedContent(request.Content, stream); | |
} | |
var response = await base.SendAsync(request, cancellationToken); | |
if (response.Content != null && | |
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; | |
} | |
} | |
public class CompressedContent : HttpContent | |
{ | |
private HttpContent _content; | |
private string _encodingType; | |
public CompressedContent(HttpContent content, string encodingType) | |
{ | |
_content = content; | |
_encodingType = encodingType.ToLowerInvariant(); | |
if (_encodingType != "gzip" && _encodingType != "deflate") | |
{ | |
throw new HttpException(HttpStatusCode.UnsupportedMediaType, string.Format("Encoding '{0}' is not supported. Only supports gzip or deflate encoding.", _encodingType)); | |
} | |
// copy the headers from the original content | |
foreach (KeyValuePair<string, IEnumerable<string>> header in _content.Headers) | |
{ | |
Headers.TryAddWithoutValidation(header.Key, header.Value); | |
} | |
Headers.ContentEncoding.Add(encodingType); | |
} | |
protected override bool TryComputeLength(out long length) | |
{ | |
length = -1; | |
return false; | |
} | |
protected override async 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); | |
} | |
try | |
{ | |
await _content.CopyToAsync(compressedStream); | |
} | |
finally | |
{ | |
compressedStream.Dispose(); | |
} | |
} | |
} | |
public class DecompressedContent : StreamContent | |
{ | |
public DecompressedContent(HttpContent content, Stream stream) : base(stream) | |
{ | |
// copy the headers from the original content | |
foreach (KeyValuePair<string, IEnumerable<string>> header in content.Headers) | |
{ | |
Headers.TryAddWithoutValidation(header.Key, header.Value); | |
} | |
Headers.Remove("Content-Type"); | |
Headers.Add("Content-Type", "application/json"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment