[c#] await / async를 사용할 때 HttpClient.GetAsync (...)가 반환하지 않습니다.



Answers

편집 : 일반적으로 교착 상태를 피하기 위해 마지막 도랑 노력을 제외하고는 아래 작업을 피하십시오. Stephen Cleary의 첫 번째 의견을 읽으십시오.

here 에서 빠른 수정. 글쓰기 대신 :

Task tsk = AsyncOperation();
tsk.Wait();

시험:

Task.Run(() => AsyncOperation()).Wait();

또는 결과가 필요한 경우 :

var result = Task.Run(() => AsyncOperation()).Result;

소스에서 (위의 예와 일치하도록 편집 됨) :

AsyncOperation은 이제 SynchronizationContext가없는 ThreadPool에서 호출되며 AsyncOperation 내부에서 사용 된 연속은 호출하는 스레드로 다시 강제되지 않습니다.

내가 비동기 적으로 만드는 옵션이 없기 때문에이 옵션을 쓸모있는 옵션처럼 보인다.

출처 :

FooAsync 메서드에서 기다리는 것이 마샬링 할 컨텍스트를 찾지 못하게합니다. 이를 수행하는 가장 간단한 방법은 ThreadPool에서 비동기 작업을 호출하는 것입니다 (예 : Task.Run에서 호출을 래핑하는 방법).

int Sync () {return Task.Run (() => Library.FooAsync ()) 결과입니다. }

FooAsync는 이제 ThreadPool에서 호출됩니다. ThreadPool에서는 SynchronizationContext가없고 FooAsync 내부에서 사용되는 연속은 Sync ()를 호출하는 스레드로 다시 강제되지 않습니다.

Question

편집 : 이 문제 는 같은 문제가 될 수도 있지만 응답이 없습니다 ...

편집 : 테스트 케이스 5에서 작업이 WaitingForActivation 상태에서 멈춘 것처럼 보입니다.

.NET Framework 4.5에서 System.Net.Http.HttpClient를 사용하여 이상한 동작이 발생했습니다. 예를 들어 httpClient.GetAsync(...) 호출 결과가 "반환 대기"되지 않습니다.

이것은 새로운 비동기 / 대기 언어 기능 및 작업 API를 사용할 때 특정 상황에서만 발생합니다. 코드는 항상 연속 만 사용하는 경우 작동합니다.

다음은 문제를 재현하는 코드입니다. Visual Studio 11의 새로운 "MVC 4 WebApi 프로젝트"에이 GET 끝점을 표시하려면이 코드를 삽입하십시오.

/api/test1
/api/test2
/api/test3
/api/test4
/api/test5 <--- never completes
/api/test6

각 끝점은 여기서 완료되지 않는 /api/test5 를 제외하고 동일한 데이터 (.com의 응답 헤더)를 반환합니다.

HttpClient 클래스에서 버그가 발생 했습니까? 아니면 API를 잘못된 방법으로 사용하고 있습니까?

코드 재현 :

public class BaseApiController : ApiController
{
    /// <summary>
    /// Retrieves data using continuations
    /// </summary>
    protected Task<string> Continuations_GetSomeDataAsync()
    {
        var httpClient = new HttpClient();

        var t = httpClient.GetAsync("http://.com", HttpCompletionOption.ResponseHeadersRead);

        return t.ContinueWith(t1 => t1.Result.Content.Headers.ToString());
    }

    /// <summary>
    /// Retrieves data using async/await
    /// </summary>
    protected async Task<string> AsyncAwait_GetSomeDataAsync()
    {
        var httpClient = new HttpClient();

        var result = await httpClient.GetAsync("http://.com", HttpCompletionOption.ResponseHeadersRead);

        return result.Content.Headers.ToString();
    }
}

public class Test1Controller : BaseApiController
{
    /// <summary>
    /// Handles task using Async/Await
    /// </summary>
    public async Task<string> Get()
    {
        var data = await Continuations_GetSomeDataAsync();

        return data;
    }
}

public class Test2Controller : BaseApiController
{
    /// <summary>
    /// Handles task by blocking the thread until the task completes
    /// </summary>
    public string Get()
    {
        var task = Continuations_GetSomeDataAsync();

        var data = task.GetAwaiter().GetResult();

        return data;
    }
}

public class Test3Controller : BaseApiController
{
    /// <summary>
    /// Passes the task back to the controller host
    /// </summary>
    public Task<string> Get()
    {
        return Continuations_GetSomeDataAsync();
    }
}

public class Test4Controller : BaseApiController
{
    /// <summary>
    /// Handles task using Async/Await
    /// </summary>
    public async Task<string> Get()
    {
        var data = await AsyncAwait_GetSomeDataAsync();

        return data;
    }
}

public class Test5Controller : BaseApiController
{
    /// <summary>
    /// Handles task by blocking the thread until the task completes
    /// </summary>
    public string Get()
    {
        var task = AsyncAwait_GetSomeDataAsync();

        var data = task.GetAwaiter().GetResult();

        return data;
    }
}

public class Test6Controller : BaseApiController
{
    /// <summary>
    /// Passes the task back to the controller host
    /// </summary>
    public Task<string> Get()
    {
        return AsyncAwait_GetSomeDataAsync();
    }
}



이 두 학교는 실제로 배제되지 않습니다.

다음은 사용하기 쉬운 시나리오입니다.

   Task.Run(() => AsyncOperation()).Wait(); 

또는 뭔가

   AsyncContext.Run(AsyncOperation);

MVC 작업을 데이터베이스 트랜잭션 특성이 있습니다. 생각이 잘못되었을 때 액션에서 수행 한 모든 것을 되돌릴 수있는 아이디어였습니다. 이것은 컨텍스트 전환을 허용하지 않습니다. 그렇지 않으면 트랜잭션 롤백 또는 커밋 자체가 실패합니다.

필요한 라이브러리는 비동기이며 비동기로 실행될 것으로 예상됩니다.

유일한 옵션. 정상적인 동기화 호출로 실행하십시오.

나는 각자에게 말하고있다.




Links