Inside a Portable Class Library, I've the following method which post data to a specific Url. The method works great. However I'd like to specify a more aggressive timeout (the default is 100 seconds).
Considering that there's no Timeout property on the HttpWebRequest class from the Portable Class Library, how can I make sure that the call is abandoned if it takes longer than a few seconds?
public async Task<HttpResponse> PostAsync(Uri uri, string data)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
using (Stream requestStream = await request.GetRequestStreamAsync())
{
byte[] postBytes = Encoding.UTF8.GetBytes(data);
requestStream.Write(postBytes, 0, postBytes.Length);
}
HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync();
return new HttpResponse(response.StatusCode, await new StreamReader(response.GetResponseStream()).ReadToEndAsync());
}
Below code either will return a HttpWebResponse or null if timed out.
HttpWebResponse response = await TaskWithTimeout(request.GetResponseAsync(), 100);
if(response != null)
{
....
}
Task<HttpWebResponse> TaskWithTimeout(Task<WebResponse> task, int duration)
{
return Task.Factory.StartNew(() =>
{
bool b = task.Wait(duration);
if (b) return (HttpWebResponse)task.Result;
return null;
});
}
--EDIT--
Creating an extension method would be even better
public static class SOExtensions
{
public static Task<T> WithTimeout<T>(this Task<T> task, int duration)
{
return Task.Factory.StartNew(() =>
{
bool b = task.Wait(duration);
if (b) return task.Result;
return default(T);
});
}
}
Usage would be:
var response = (HttpWebResponse)await request.GetResponseAsync().WithTimeout(1000);
--EDIT 2--
Another way of doing it
public async static Task<T> WithTimeout<T>(this Task<T> task, int duration)
{
var retTask = await Task.WhenAny(task, Task.Delay(duration))
.ConfigureAwait(false);
if (retTask is Task<T>) return task.Result;
return default(T);
}