在可移植类库中,我有以下方法将数据发布到特定的Url。该方法效果很好。但是我想指定一个更积极的超时(默认为100秒)。
考虑到可移植类库中的HttpWebRequest类没有Timeout属性,如果调用时间超过几秒,我如何确保调用被放弃?
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());
}
答案 0 :(得分:23)
下面的代码会返回一个HttpWebResponse,如果超时则返回null。
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;
});
}
<强> - 编辑 - 强>
创建扩展方法会更好
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);
});
}
}
用法是:
var response = (HttpWebResponse)await request.GetResponseAsync().WithTimeout(1000);
- 编辑2 -
另一种方法
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);
}
答案 1 :(得分:0)
// Abort the request if the timer fires.
private static void TimeoutCallback(object state, bool timedOut) {
if (timedOut) {
HttpWebRequest request = state as HttpWebRequest;
if (request != null) {
request.Abort();
}
}
}
是的,客户端应用程序有责任实施自己的超时机制。您可以从上面设置超时的代码执行此操作,并使用ThreadPool.RegisterWaitForSingleObject方法。有关详细信息,请参阅http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.abort.aspx。从本质上讲,它会从GetResponse,BeginGetResponse,EndGetResponse,GetRequestStream,BeginGetRequestStream或EndGetRequestStream中止。