In ASP.NET HttpClient.GetAsync(...)
occasional deadlock occurs when using await
/async
When using the new async
/await
language features and the Tasks API in .NET 4.5, the "awaiting" results of httpClient.GetAsync(...)
may sometimes get stuck. This is due to misuse of the API.
Explanation
In ASP.NET, only one thread can handle a request at a time. Parallel processing can be performed if desired, but additional threads will need to be borrowed from the thread pool, and these threads will have no request context. This is managed by the ASP.NET SynchronizationContext.
By default, when waiting for a Task, methods resume on the captured SynchronizationContext or captured TaskScheduler (if there is no SynchronizationContext). Normally, this is ideal: the async controller action will wait for something, and when it resumes, it resumes using the request context.
Test5Controller.Get
This particular controller method performs AsyncAwait_GetSomeDataAsync (in the context of an ASP.NET request). AsyncAwait_GetSomeDataAsync performs HttpClient.GetAsync (in the context of an ASP.NET request). The HTTP request is sent and HttpClient.GetAsync returns an unfinished Task. Then, AsyncAwait_GetSomeDataAsync waits for the unfinished Task, so it returns an unfinished Task. Now, Test5Controller.Get blocks the current thread until the Task completes.
The HTTP response arrives and the Task returned by HttpClient.GetAsync is completed. AsyncAwait_GetSomeDataAsync then attempts to resume in the ASP.NET request context. However, there is already a thread in this context: the thread blocked in Test5Controller.Get. This can lead to deadlock.
Best Practices
To correct this problem, it is recommended:
ConfigureAwait(false)
in your "library" async methods whenever possible. In this case AsyncAwait_GetSomeDataAsync will be changed to result = await httpClient.GetAsync("http://stackoverflow.com", HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false);
await
instead of "GetResult" (Task.Result
, Task.Wait
should also be replaced with await
). By following these best practices, the continuation (the rest of the AsyncAwait_GetSomeDataAsync method) will run on a normal thread pool thread without the need to enter the ASP.NET request context, and the controller itself is asynchronous (will not block the request thread) .
The above is the detailed content of Why does `HttpClient.GetAsync(...)` sometimes deadlock when using `await`/`async` in ASP.NET?. For more information, please follow other related articles on the PHP Chinese website!