[英]How to make HttpWebRequest async
I have such code: 我有这样的代码:
private async Task<string> Request(url)
{
Task<string> task = null;
try
{
task = MakeAsyncRequest(url, "text/html");
return await task;
}
catch
{
return null;
}
}
private async Task<string> MakeAsyncRequest(string url, string contentType)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.ContentType = contentType;
request.Method = WebRequestMethods.Http.Get;
request.Timeout = 20000;
request.Proxy = null;
Task<WebResponse> task = Task.Factory.FromAsync(
request.BeginGetResponse,
asyncResult => request.EndGetResponse(asyncResult),
(object)null);
//issue here:
return await task.ContinueWith(t => ReadStreamFromResponse(t.Result));
}
private string ReadStreamFromResponse(WebResponse response)
{
using (Stream responseStream = response.GetResponseStream())
using (StreamReader sr = new StreamReader(responseStream))
{
//Need to return this response
string strContent = sr.ReadToEnd();
return strContent;
}
}
I am calling Request(url)
in foreach
loop 我在
foreach
循环中调用Request(url)
foreach(var url in myUrlList)
{
string body = Request(method).Result;
}
But for some reason the code getting stacked at return await task.ContinueWith(t => ReadStreamFromResponse(t.Result));
但由于某种原因,代码在
return await task.ContinueWith(t => ReadStreamFromResponse(t.Result));
堆叠return await task.ContinueWith(t => ReadStreamFromResponse(t.Result));
and just freezing. 只是冷冻。
Is there a better way of doing this or may be some one can explain what is happening? 有没有更好的方法来做到这一点,或者有人可以解释发生了什么? I am not getting any errors just something wrong with the
await
.... 我没有得到任何错误只是
await
......
The call to Result
in your foreach
loop is causing a deadlock , as I explain on my blog. 正如我在博客中解释的那样,在
foreach
循环中调用Result
会导致死锁 。 In summary, await
will capture a "context" (eg, a UI context), and use that to resume the async
method. 总之,
await
将捕获“上下文”(例如,UI上下文),并使用它来恢复async
方法。 Some contexts (eg, the UI context) only allow one thread in the context. 某些上下文(例如,UI上下文)仅允许上下文中的一个线程。 So if you block that special thread (eg, the UI thread) by calling
Result
, then the async
method cannot resume execution within that context. 因此,如果通过调用
Result
阻止该特殊线程(例如,UI线程),则async
方法无法在该上下文中继续执行。
So, the solution is to change your foreach
loop: 所以,解决方案是改变你的
foreach
循环:
foreach(var url in myUrlList)
{
string body = await ProcessAsync(method);
}
Other notes: 其他说明:
Task-returning methods should end in "Async" to follow the TAP guidelines . 任务返回方法应以“异步”结束,以遵循TAP指南 。
Task.Factory.FromAsync
is unnecessary; Task.Factory.FromAsync
是不必要的; HttpWebRequest
already has awaitable methods. HttpWebRequest
已经有了等待的方法。 An even better option is to use HttpClient
instead. 更好的选择是使用
HttpClient
。
I recommend that you not use Task.ContinueWith
(or Task.Result
, or Task.Wait
); 我建议你不要使用
Task.ContinueWith
(或Task.Result
,或Task.Wait
); use await
instead. 用
await
来代替。
With these simplifications in place: 通过这些简化:
private async Task<string> MakeAsyncRequestAsync(string url, string contentType)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.ContentType = contentType;
request.Method = WebRequestMethods.Http.Get;
request.Timeout = 20000;
request.Proxy = null;
WebResponse response = await request.GetResponseAsync();
return ReadStreamFromResponse(response);
}
This code could be simplified further if you change HttpWebRequest
to HttpClient
. 如果将
HttpWebRequest
更改为HttpClient
则可以进一步简化此代码。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.