ps:此人博客非常不错,可以收藏下http://blogs.msdn.com/b/kiranchalla/
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.