2014-06-20 69 views
2

問題死鎖異步讀取響應內容

我使用的是DelegatingHandler中的WebAPI讀取響應內容並將其審計數據庫。

當代碼到達.ReadAsStringAsync()時,它似乎鎖定並阻止其他請求完成。我只知道這一點,因爲當我刪除違規線路時,它完美地工作。

public static void Register(HttpConfiguration config) 
{ 
    config.MessageHandlers.Add(new ResourceAuditHandler()); 
} 

public class ResourceAuditHandler : DelegatingHandler 
{ 
    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, 
                  CancellationToken cancellationToken) 
    { 
     var response = await base.SendAsync(request, cancellationToken); 

     string content = ""; 
     if (response.Content != null) 
     { 
      //THIS SEEMS TO CREATE DEADLOCK! 
      content = await response.Content.ReadAsStringAsync(); 
     } 

     AuditResponseToDatabase(content); 

     return response; 
    } 
} 

可能的原因

我讀過當應用程序的兩位正試圖讀取相同的請求/響應的內容會發生這種情況(一DelegatingHandler和控制器/ ModelBinder的)...或者更具體地說,當您嘗試讀取異步響應的。結果,但另一個實例已經讀取結果/響應流,然後該結果/響應流爲空。

我的第一個請求命中了一個簡單的控制器,但是第二個請求命中了一個控制器,該控制器具有一個檢查Action參數「id」的屬性來檢查它不爲null。我已經讀過,當DelegatingHandler和控制器ModelBinder都試圖從響應中讀取時,你會遇到死鎖。

替代方法(也無法)

我已經使用其他方法(如見於其他SO問題),也嘗試過它採用.ReadAsByteArrayAsync(),但這似乎仍然鎖定。我明白,這種方法不使用。結果的方法,並直接從響應流(以某種方式)讀取它。

var response = await base.SendAsync(request, cancellationToken); 

string content= ""; 
if (response.Content != null) 
{ 
    var bytes = await response.Content.ReadAsByteArrayAsync(); 
    responseContent = Encoding.UTF8.GetString(bytes); 
} 

AuditResponseToDatabase(content); 

請幫忙!

+1

通常情況下,如果你的代碼中的任何地方有'task.Wait()'或'task.Result',那麼就會發生這種情況(在外部調用堆棧上)。是這樣嗎? – Noseratio

+0

@ peter.swallow:你能否創建一個可靠地重現問題的小例子? –

回答

1

彼得,首先,你對這個僵局的原因是正確的。嘗試使用async/await一路下來。換句話說,不要阻止async的代碼。你應該做的另一件事是使用.ConfigureAwait(false)

var response = await base.SendAsync(request, cancellationToken).ConfigureAwait(false); 

    string content = ""; 
    if (response.Content != null) 
    { 
     content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); 
    } 

更多信息,你可以在這個link

發現如果沒有上述工作的,請提供一個完整的例子,好不好?

希望這會有所幫助!

+4

如果他沒有訪問'Result'或調用'Wait()'這不會幫助。此外,'ConfigureAwait(false)'在ASP.NET中的含義與在UI或控制檯應用程序中不同。 http://stackoverflow.com/questions/13489065/best-practice-to-call-configureawait-for-all-server-side-code –

+0

這確實確實解決了我的問題。不幸的是,它強調了第二個問題,即使用.ConfigureAwait(false),似乎失去了我的IOC(Autofac)所要求的上下文(在本例中爲HttpContext)。還有其他方式來保留上下文嗎? –

+0

我不知道,但我相信沒有... –