要仅压缩/缩小大于给定大小限制的WebAPI响应,我必须找出要返回的内容的大小。但是以下一行:
response.Content.LoadIntoBufferAsync()
似乎会在API响应周期中导致死锁。正确确定大小并且处理程序执行正常,但之后请求将永久挂起。
这是我的DelegatingHandler的SendAsync方法。
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);
}
我尝试了与Wait(..),ConfigureAwait(..)和ContinueWith(..)的不同组合。使用async / await语法我遇到了同样的问题。
编辑:Compressor的SerializeToStreamAsync(负责压缩内容流):
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();
}
});
}
=&GT;在以下调用之后,管道显然会被破坏:
response.Content.LoadIntoBufferAsync()
调用两个中的任何一个单独工作,因此它们必须是读取/写入内容流的问题。
答案 0 :(得分:0)
我试图做同样的事情。您似乎在以下语句中缺少等待:
await response.Content.LoadIntoBufferAsync();
我发现上面的内容与死锁无关。当您尝试使用以下内容获取内容长度时会出现问题:
response.Content.Headers.ContentLength
然后尝试访问标题,例如:
private void AddHeaders()
{
foreach (var header in content.Headers)
{
Headers.TryAddWithoutValidation(header.Key, header.Value);
}
Headers.ContentEncoding.Add(compressor.EncodingType);
}
要解决此问题,您需要选择性地添加标题而不是使用foreach循环。例如:
private void AddHeaders()
{
//foreach (var header in content.Headers)
//{
// Headers.TryAddWithoutValidation(header.Key, header.Value);
//}
Headers.ContentType = new MediaTypeHeaderValue("application/json");
Headers.ContentEncoding.Add(compressor.EncodingType);
}
有选择地使用压缩的其他选项是使用动作过滤器。您可以在以下帖子中找到有关它的更多信息:
http://blog.developers.ba/asp-net-web-api-gzip-compression-actionfilter/