2014-06-20 4 views
2

문제교착 상태 읽기 비동기 응답 콘텐츠

내가 응답 내용을 읽고 데이터베이스에 감사 WebAPI에서 DelegatingHandler을 사용하고 있습니다.

코드가 .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; 
    } 
} 

내가 응용 프로그램의 두 비트가 동일한 요청/응답의 내용을 읽을하려고 할 때이 발생할 수 읽었습니다

원인 (A DelegatingHandler 및 컨트롤러/ModelBinder를) ... 또는 좀 더 구체적으로 을 읽으려고하면 비동기 응답의이 반환되지만 다른 인스턴스는 이미 Result/Response Stream을 읽었습니다. 그 결과는 null입니다.

첫 번째 요청은 간단한 컨트롤러를 공격하지만 두 번째 요청은 Action 매개 변수 "id"를 검사하여 null이 아닌지 확인하는 특성을 가진 컨트롤러에 도달합니다. 나는 DelegatingHandler와 Controller ModelBinder가 응답에서 읽으려고 시도 할 때 교착 상태에 빠지게된다고 읽었습니다. .ReadAsByteArrayAsync를 (사용 (또는 실패)

대체 방법

나는 또한 (다른 SO 질문에서와 같이) 다른 방법을 사용하려고했습니다)는하지만 여전히 잠 것으로 보인다. 나는이 방법이 .Result 접근 방식을 사용하지 않고 응답 스트림 (어쨌든)에서 직접 읽음을 이해했다.

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) : 위의 작업 중 어느 것도, 좋아, 완벽한 예제를 제공하지하십시오이 link

에서 찾을 수 있습니다

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

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

더 많은 정보?

희망이 도움이됩니다.

+4

그가'Result'에 접근 중이 아니거나'Wait()'을 호출하면 도움이되지 않습니다. 게다가'ConfigureAwait (false)'는 UI 나 콘솔 앱과는 다른 의미를 ASP.NET에서 가지고 있습니다. http://stackoverflow.com/questions/13489065/best-practice-to-call-configureawait-for-all-server-side-code –

+0

이것은 실제로 내 문제를 해결했습니다. 아쉽게도 .ConfigureAwait (false)를 사용하면 IOC (Autofac)에 필요한 컨텍스트 (이 경우 HttpContext)가 손실되는 것으로 보이는 두 번째 문제점이 강조되었습니다. 문맥을 유지하는 다른 방법이 있습니까? –

+0

잘 모르겠지만 믿을 수는 없습니다 ... –