HttpWebRequest.BeginGetResponse blocks; What is the correct way to get HttpWebResponse asynchronously?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
HttpWebRequest.BeginGetResponse belongs to the old APM pattern built around Begin... and End... methods. It can still be used asynchronously, but many implementations accidentally block because they mix it with synchronous waiting, synchronous request-stream writes, or UI-thread marshaling. In modern .NET code, the correct answer is usually to use await with HttpClient, or at least with GetResponseAsync, instead of writing new code around BeginGetResponse.
Why BeginGetResponse Seems to Block
Calling BeginGetResponse does not guarantee your overall code path is non-blocking. Common reasons it still appears to block include:
- waiting on the returned
IAsyncResultwithAsyncWaitHandle.WaitOne() - calling
EndGetResponseon the initiating thread too early - writing the request body synchronously before reading the response
- blocking the UI thread while the callback tries to marshal back
The API is asynchronous only if the whole workflow is asynchronous.
Preferred Modern Solution: HttpClient
For new code, HttpClient is the cleaner API:
This is easier to read, integrates naturally with async and await, and avoids the callback-heavy structure of the APM pattern.
If You Must Stay on HttpWebRequest
If legacy code forces you to keep HttpWebRequest, use the task-based wrapper when available:
This preserves the older request type while still using the task-based pattern that composes well with the rest of modern .NET.
Correct APM Usage Pattern
If you are maintaining an older codebase that still uses BeginGetResponse, the important rule is to finish the operation in the callback and avoid synchronous waiting:
This is asynchronous in the APM sense because you are not blocking the caller waiting for completion. But it is still more awkward and error-prone than await.
Do Not Forget the Request Stream
For POST or PUT requests, the request body matters too. If you write the request stream synchronously and then call BeginGetResponse, the operation can still tie up the calling thread. The request stream should be obtained asynchronously as well, or you should move to HttpClient where the request content handling is simpler.
With HttpWebRequest, a full legacy async flow often needs both:
- '
BeginGetRequestStreamorGetRequestStreamAsync' - '
BeginGetResponseorGetResponseAsync'
Doing only half the process asynchronously still leaves synchronous bottlenecks.
Common Pitfalls
The most common pitfall is calling BeginGetResponse and then immediately waiting for it with a manual wait handle. That defeats the purpose of asynchronous I/O.
Another pitfall is assuming the response side is the only part that matters. If the request body is written synchronously, the code may still feel blocked.
Developers also keep using HttpWebRequest in new code because it looks familiar. In most cases, HttpClient is the better abstraction and reduces the chance of subtle blocking bugs.
Finally, if this code runs on a UI thread, avoid .Result, .Wait(), or manual callbacks that depend on the UI message pump. Those patterns are a common source of deadlocks and unresponsive applications.
Summary
- '
BeginGetResponseis only non-blocking if the surrounding workflow is also fully asynchronous.' - For new code, prefer
HttpClientwithasyncandawait. - For legacy
HttpWebRequest, preferGetResponseAsyncover new APM code. - If you keep
BeginGetResponse, complete the work in the callback and do not wait synchronously. - For request bodies, make the request-stream step asynchronous too.

