2016-03-07 86 views
0

要僅壓縮/縮小大於給定大小限制的WebAPI響應,我必須找出要返回的內容的大小。但是,以下行:在DelegatingHandler中調用LoadIntoBufferAsync時出現死鎖

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語法,我遇到了同樣的問題。

編輯:壓縮機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(); 
      } 
     }); 
    } 

=> Apperently當這之後稱爲管道破裂:

response.Content.LoadIntoBufferAsync() 

調用的任一兩個人單獨工作,所以他們必須是讀/寫內容流時遇到的問題。

+1

那麼,目前的變型,絕對是錯誤的* *。任何時候當你看到一個名稱以'Async'結尾的方法,其中的返回值被忽略時,它應該觸發警報響鈴。 –

+0

我認爲問題在於我在CompressedContent類中使用壓縮流重新覆蓋了內容,因此內容變得混亂。 – Philipp

回答

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/

+0

我發現當你使用: response.Content.Headers.ContentLength時會發生死鎖,並隨後嘗試訪問Header,例如: –