Web Api + HttpClient:비동기 작업이 보류 중인 동안 비동기 모듈 또는 핸들러가 완료되었습니다.
저는 ASP를 이용하여 HTTP 요청을 대행하는 어플리케이션을 작성하고 있습니다.NET Web API와 저는 간헐적인 오류의 원인을 파악하는 데 어려움을 겪고 있습니다.인종적인 상황인 것 같네요...하지만 확실하지는 않아요
자세한 설명을 드리기 전에 애플리케이션의 일반적인 통신 흐름을 소개합니다.
- 클라이언트가 프록시 1에 HTTP 요청을 합니다.
- Proxy 1은 HTTP 요청의 내용을 Proxy 2에 전달합니다.
- 프록시 2는 HTTP 요청의 내용을 Target Web Application에 전달합니다.
- 대상 웹 앱이 HTTP 요청에 응답하고 응답이 Proxy 2로 스트리밍(청크 전송)됩니다.
- 프록시 2는 프록시 1에 응답을 반환하고 프록시 1은 원래 클라이언트 호출에 응답합니다.
Proxy 응용프로그램은 ASP로 작성됩니다.사용하는 NET Web API RTM.NET 4.5.릴레이를 수행하는 코드는 다음과 같습니다.
//Controller entry point.
public HttpResponseMessage Post()
{
using (var client = new HttpClient())
{
var request = BuildRelayHttpRequest(this.Request);
//HttpCompletionOption.ResponseHeadersRead - so that I can start streaming the response as soon
//As it begins to filter in.
var relayResult = client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead).Result;
var returnMessage = BuildResponse(relayResult);
return returnMessage;
}
}
private static HttpRequestMessage BuildRelayHttpRequest(HttpRequestMessage incomingRequest)
{
var requestUri = BuildRequestUri();
var relayRequest = new HttpRequestMessage(incomingRequest.Method, requestUri);
if (incomingRequest.Method != HttpMethod.Get && incomingRequest.Content != null)
{
relayRequest.Content = incomingRequest.Content;
}
//Copies all safe HTTP headers (mainly content) to the relay request
CopyHeaders(relayRequest, incomingRequest);
return relayRequest;
}
private static HttpRequestMessage BuildResponse(HttpResponseMessage responseMessage)
{
var returnMessage = Request.CreateResponse(responseMessage.StatusCode);
returnMessage.ReasonPhrase = responseMessage.ReasonPhrase;
returnMessage.Content = CopyContentStream(responseMessage);
//Copies all safe HTTP headers (mainly content) to the response
CopyHeaders(returnMessage, responseMessage);
}
private static PushStreamContent CopyContentStream(HttpResponseMessage sourceContent)
{
var content = new PushStreamContent(async (stream, context, transport) =>
await sourceContent.Content.ReadAsStreamAsync()
.ContinueWith(t1 => t1.Result.CopyToAsync(stream)
.ContinueWith(t2 => stream.Dispose())));
return content;
}
간헐적으로 발생하는 오류는 다음과 같습니다.
비동기 작업이 보류 중인 동안 비동기 모듈 또는 핸들러가 완료되었습니다.
이 오류는 일반적으로 프록시 응용 프로그램에 대한 처음 몇 번의 요청에서 발생하며, 그 후에는 오류가 다시 나타나지 않습니다.
Visual Studio는 던졌을 때 Exception을 포착하지 못합니다.그러나 Global.asax Application_Error 이벤트에서 오류가 발생할 수 있습니다.안타깝게도 예외에는 스택 추적이 없습니다.
프록시 응용프로그램은 Azure Web Roles에서 호스팅됩니다.
범인을 특정하는 데 도움을 주시면 감사하겠습니다.
당신의 문제는 미묘한 문제입니다.async
당신이 지나가는 람다PushStreamContent
는 것으로 해석되고 있습니다.async void
(시공자가 다음만 수행하기 때문에)Action
s 파라미터)를 입력합니다.모듈/핸들러 완료와 완료 사이에는 경합 조건이 존재합니다.async void
람다
PostStreamContent
스트림이 닫히는 것을 감지하고 스트림의 끝으로 처리합니다.Task
(모듈/handler comple), 그래서 당신은 단지 아무 것도 없는지 확인하기만 하면 됩니다.async void
스트림이 닫힌 후에도 여전히 실행될 수 있는 메서드입니다.async Task
메소드는 정상이므로 이를 해결해야 합니다.
private static PushStreamContent CopyContentStream(HttpResponseMessage sourceContent)
{
Func<Stream, Task> copyStreamAsync = async stream =>
{
using (stream)
using (var sourceStream = await sourceContent.Content.ReadAsStreamAsync())
{
await sourceStream.CopyToAsync(stream);
}
};
var content = new PushStreamContent(stream => { var _ = copyStreamAsync(stream); });
return content;
}
프록시의 확장성을 조금 더 향상시키려면 모든 기능을 제거하는 것이 좋습니다.Result
호출:
//Controller entry point.
public async Task<HttpResponseMessage> PostAsync()
{
using (var client = new HttpClient())
{
var request = BuildRelayHttpRequest(this.Request);
//HttpCompletionOption.ResponseHeadersRead - so that I can start streaming the response as soon
//As it begins to filter in.
var relayResult = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
var returnMessage = BuildResponse(relayResult);
return returnMessage;
}
}
이전 코드는 (헤더가 수신될 때까지) 각 요청에 대해 하나의 스레드를 차단합니다.async
컨트롤러 레벨까지 올라오면 그 시간 동안 스레드를 차단하지 않습니다.
같은 실수로 착륙한 다른 사람들을 위해 지혜를 보태고 싶지만, 당신의 모든 코드는 괜찮은 것 같습니다.호출 트리에 걸쳐 함수에 전달된 람다 식을 찾습니다.
MVC 5.x 컨트롤러 작업에 대한 자바스크립트 JSON 호출에서 이 오류가 발생했습니다.내가 했던 모든 일들이 정의를 내렸어요async Task
전화를 걸었습니다.await
.
그러나 Visual Studio의 "Set next statement(다음 문장 설정)" 기능을 사용하여 줄을 체계적으로 건너뛰어 원인을 파악했습니다.저는 외부 NuGet 패키지에 대한 호출을 받기 전까지 로컬 방법을 계속 연구했습니다.호출된 메소드는Action
매개 변수로서 그리고 이에 대해 전달된 람다 표현식은 다음에 선행되었습니다.async
키워드.Stephen Cleary가 그의 답변에서 위에서 지적했듯이, 이것은 하나의 것으로 취급됩니다.async void
, MVC가 좋아하지 않는.다행히도 패키지에는 *비동기 버전의 동일한 방법이 있습니다.동일한 패키지로 다운스트림 호출과 함께 이를 사용하는 것으로 전환하면 문제가 해결되었습니다.
이것이 문제에 대한 새로운 해결책이 아니라는 것을 알고 있지만 문제를 해결하기 위해 검색할 때 이 스레드를 몇 번 넘겼습니다.async void
아니면async <Action>
다른 사람이 그걸 피할 수 있도록 돕고 싶었거든요
좀 더 간단한 모델은 실제로 HttpContents를 직접 사용하여 릴레이 내부에서 전달할 수 있다는 것입니다.비교적 간단한 방식으로 내용을 버퍼링하지 않고 비동기적으로 요청과 응답을 모두 의존할 수 있는 방법을 보여주는 샘플만 업로드했습니다.
적절한 경우 연결을 재사용할 수 있으므로 동일한 HttpClient 인스턴스를 재사용하는 것도 유용합니다.
언급URL : https://stackoverflow.com/questions/15060214/web-api-httpclient-an-asynchronous-module-or-handler-completed-while-an-async
'programing' 카테고리의 다른 글
Piwik 사용자 정의 변수별 필터 그래프 (0) | 2023.09.28 |
---|---|
SQL "LIKE" 문과 동등한 SQL Lchemy (0) | 2023.09.28 |
MySQL Workbench는 결과를 BLOB로 표시합니다. (0) | 2023.09.28 |
새 가져오기 표준에 의해 시작된 요청을 탐지하려면 어떻게 해야 합니까?일반적으로 어떻게 AJAX 요청을 감지해야 합니까? (0) | 2023.09.28 |
PHP에서 특정 유형의 객체를 확인하는 방법 (0) | 2023.09.28 |