Jay Kannan
Jay Kannan

Reputation: 1274

appending timeouts to asynchronous requests in WinRT

I'm using this piece of code to append a TimeOut to a request call that I'm making to ensure that we don't encounter a slow internet connection - and that its handled appropriately.
When I DO meet the timeout condition I get an error message that I've been unable to fix within the extended function.

How to go about this task in general?

Code:

public static class SOExtensions
{
    public static Task<T> WithTimeout<T>(this Task<T> task, TimeSpan duration)
    {
        return Task.Factory.StartNew(() =>
        {
            bool b = task.Wait(duration);
            if (b) return task.Result;
            return default(T);
        });
    }
}

Usage:

var response = await HttpWebRequest
                     .Create(request)
                     .GetResponseAsync()
                     .WithTimeout(TimeSpan.FromSeconds(1));

I handle AggregateException with this (and through a WebException), but it still generates AggregateException when the timeout fails.

Upvotes: 0

Views: 850

Answers (1)

Stephen Cleary
Stephen Cleary

Reputation: 457187

I recommend using CancellationToken for timeouts (new CancellationTokenSource(myTimeSpan).Token), which you can then use within your async methods (e.g., for HttpClient, you pass the token to the GetAsync method). This takes up fewer resources because the HTTP request itself is canceled.

But if you want an "external" timeout, a more natural approach would be this:

public static async Task<T> WithTimeout<T>(this Task<T> task, TimeSpan duration)
{
  var timeout = Task.Delay(duration);
  var completeTask = await Task.WhenAny(task, timeout);
  if (completeTask == timeout)
    return default(T);
  else
    return await task;
}

This will prevent the exceptions from being wrapped into an AggregateException. It's not as efficient as the CancellationToken approach, though, which would look like this:

var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(1));
var response = await new HttpClient().GetAsync(uri, timeout.Token);

Note that the CancellationToken approach will throw OperationCanceledException instead of returning a default(T) if there is a timeout.

Upvotes: 2

Related Questions