WebRequest.GetResponseAsync (with timeout) for PCL
I've been working on porting Budgie over to the Portable Class Library framework so it'll be usable from WinRT apps as well as "desktop" .NET apps.
Budgie's TwitterClient
class has a Timeout
property which applies to all requests, but the PCL version of WebRequest
has such property, since it has no synchronous GetResponse
method that would honour it.
So here's a simple extension method which uses the BeginGetResponse
and EndGetResponse
methods, and wraps them up in a task with a timeout.
internal static class WebRequestExtensions
{
internal static Task<WebResponse> GetResponseAsync(this WebRequest request, TimeSpan timeout)
{
return Task.Factory.StartNew<WebResponse>(() =>
{
var t = Task.Factory.FromAsync<WebResponse>(
request.BeginGetResponse,
request.EndGetResponse,
null);
if (!t.Wait(timeout)) throw new TimeoutException();
return t.Result;
});
}
}
This method uses the FromAsync<T>
factory method to spin up a new task from the old "begin/end" asynchronous method pairs, but does so inside a task so it can wait for the result with a timeout without blocking. If the timeout expires, it simply throws a TimeoutException
.
Trackbacks
- Dew Drop–November 12, 2012 (#1,441) | Alvin Ashcraft's Morning Dew | http://www.alvinashcraft.com/2012/11/12/dew-dropnovember-12-2012-1441/
- rimonabantexcellence site title | http://www.rimonabantexcellence.com/t.php?ahr0cdovl21hdhroyw1pbhrvbi5vcmcvcgnslxdlynjlcxvlc3qtz2v0cmvzcg9uc2vhc3luyw==
No new comments are allowed on this post.
Comments
OmariO
Matt, your solution is asynchronous i.e. not blocking the thread calling GetResponseAsync, but it synchronous in relation to the thread pool thread on which task.Wait is called. So the extension would be useful in UI (to unload waiting to another thread) but not for server side, where fully nonblocking wating is a requirement for scalability (in terms of thread usage).
Matt Hamilton
Good point, Omar.
The ideal way to do this is to spin up two tasks, one which does the HTTP call and the other which simply uses Task.Delay to sleep, then use Task.WhenAny to wait for one of them to finish.
The problem with that approach is that the Portable Class Library framework subset doesn't include Task.Delay or Task.WhenAny.
@JakeGinnivan has suggested taking a dependency on Microsoft.Bcl.Async, which will make these methods available via a TaskEx class, but I'm torn as I want to limit Budgie's dependencies. It's a conundrum!