The MSDN docs are correct, there's indeed a synchronous part which may block the UI if HttpWebRequest.BeginGetResponse
or HttpWebRequest.GetResponse
is called on the UI thread.
Thus, you'd need to call it on a separate thread. I'd suggest using Task Parallel Library for that. Task.Factory.FromAsync
could help wrapping BeginGetResponse
/EndGetResponse
, then you'd use Task.Factory.StartNew
, Task.Unwrap
and Task.ContinueWith
to start the request on pool thread and handle its completion. This can be further enhanced to support cancellation.
I'm not good enough with VB.NET to create a sample of this, but here it is in C# (.NET 4.0, VS2010), untested. Shouldn't be a problem to convert this to VB.NET, the API is the same.
public static class WebResponseExt
{
// convert BeginGetResponse/EndGetResponse into a Task
static public Task<WebResponse> GetResponseTapAsync(
this WebRequest request)
{
return Task.Factory.FromAsync(
(asyncCallback, state) =>
request.BeginGetResponse(asyncCallback, state),
(asyncResult) =>
request.EndGetResponse(asyncResult), null);
}
// call GetResponseTapAsync on a pool thread
// and unwrap the nested task
static public Task<WebResponse> OffloadGetResponseTapAsync(
this WebRequest request, CancellationToken token)
{
return Task.Factory.StartNew(
() => request.GetResponseTapAsync(),
token,
TaskCreationOptions.None,
TaskScheduler.Default).Unwrap();
}
}
class Program
{
void DoRequest(string url, CancellationToken token)
{
var request = HttpWebRequest.Create(url);
var cancellation = token.Register(() => request.Abort());
var task1 = request.OffloadGetResponseTapAsync(token);
var task2 = task1.ContinueWith(
(responseTask) =>
{
cancellation.Dispose();
try
{
WebResponse result = responseTask.Result;
// process result
}
catch (Exception ex)
{
Debug.Print(ex.ToString());
// process
// rethrow if needed
// the exception will be available as task2.Exception
throw;
}
},
token,
TaskContinuationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext());
}
// ...
}
If you decide to go on with Task
-based API, consider using task composition patterns like Stephen Toub's Then
.