To only zip / deflate WebAPI responses bigger than a given size limit, I have to find out the size of the content to be returned. However the following line:
response.Content.LoadIntoBufferAsync()
seems to cause a deadlock later in the API response-cycle. The size is determined correctly and the handler executes fine, but afterwards the request is pending forever.
This is the SendAsync-method of my DelegatingHandler.
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
return base.SendAsync(request, cancellationToken).ContinueWith(
task =>
{
HttpResponseMessage response = task.Result;
if (response.RequestMessage != null && response.RequestMessage.Headers.AcceptEncoding != null && response.RequestMessage.Headers.AcceptEncoding.Count > 0)
{
if (response.Content != null)
{
response.Content.LoadIntoBufferAsync(); // when I remove this line the request finishes, but then ContentLength = 0
if (response.Content.Headers.ContentLength > 4000)
{
string encodingType = GetEncodingType(response.RequestMessage.Headers.AcceptEncoding); // use deflate if possible
if (encodingType == "deflate" || encodingType == "gzip")
{
response.Content = new CompressedContent(response.Content, encodingType);
}
}
}
}
return response;
}, cancellationToken);
}
I tried different combinations with Wait(..), ConfigureAwait(..) and ContinueWith(..). With the async / await syntax I had the same problem.
EDIT: SerializeToStreamAsync of Compressor (responsible for compression the content stream):
protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
{
Stream compressedStream = null;
if (m_EncodingType == "gzip")
{
compressedStream = new GZipStream(stream, CompressionMode.Compress, true);
}
else if (m_EncodingType == "deflate")
{
compressedStream = new DeflateStream(stream, CompressionMode.Compress, true);
}
return m_OriginalContent.CopyToAsync(compressedStream).ContinueWith(task =>
{
if (compressedStream != null)
{
compressedStream.Dispose();
}
});
}
=> Apperently the pipeline is broken when this is called after:
response.Content.LoadIntoBufferAsync()
Calling either one of the two alone works, so their must be a problem in reading / writing the content stream.
I was trying to do exactly the same thing. It appears that you are missing await in the following statement:
await response.Content.LoadIntoBufferAsync();
I found that the above has nothing to do with the deadlock. The problem comes when you try to get the content length using:
response.Content.Headers.ContentLength
and subsequently try to access the Header, for example:
To fix this you need to add the header selectivly rather than using foreach loop. For example:
Other option to use the compression selectively is to use action filters. You could find more info about it in the following post:
http://blog.developers.ba/asp-net-web-api-gzip-compression-actionfilter/