如何使HttpWebRequest异步 [英] How to make HttpWebRequest async
问题描述
我有这样的代码:
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;
}
}
我正在呼叫 Request( url)
在 foreach
循环中
foreach(var url in myUrlList)
{
string body = Request(method).Result;
}
但是由于某些原因,代码在返回时会堆积等待任务。ContinueWith(t => ReadStreamFromResponse(t.Result));
并冻结。
But for some reason the code getting stacked at return await task.ContinueWith(t => ReadStreamFromResponse(t.Result));
and just freezing.
有没有更好的方法这或也许有人可以解释发生了什么?
我没有遇到任何错误,只是 await
....
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
....
推荐答案
调用<$正如我在博客中所解释的, foreach
循环中的c $ c>结果导致死锁。总之, await
将捕获一个上下文(例如UI上下文),并使用它来恢复 async
方法。某些上下文(例如,UI上下文)仅在该上下文中允许一个线程。因此,如果通过调用 Result
阻止该特殊线程(例如,UI线程),则 async
方法将无法恢复
The call to Result
in your foreach
loop is causing a deadlock, as I explain on my blog. In summary, await
will capture a "context" (e.g., a UI context), and use that to resume the async
method. Some contexts (e.g., the UI context) only allow one thread in the context. So if you block that special thread (e.g., the UI thread) by calling Result
, then the async
method cannot resume execution within that context.
因此,解决方案是更改 foreach
循环:
So, the solution is to change your foreach
loop:
foreach(var url in myUrlList)
{
string body = await ProcessAsync(method);
}
其他说明:
返回任务的方法应以异步结尾,以遵循 TAP准则。
Task-returning methods should end in "Async" to follow the TAP guidelines.
Task.Factory.FromAsync
是不必要的; HttpWebRequest
已经具有可等待的方法。更好的选择是使用 HttpClient
。
Task.Factory.FromAsync
is unnecessary; HttpWebRequest
already has awaitable methods. An even better option is to use HttpClient
instead.
我建议您不要使用 Task.ContinueWith
(或 Task.Result
或 Task.Wait
);使用 await
代替。
I recommend that you not use Task.ContinueWith
(or Task.Result
, or Task.Wait
); use await
instead.
使用以下简化方法:
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);
}
如果更改 HttpWebRequest,则可以进一步简化此代码
到 HttpClient
。
这篇关于如何使HttpWebRequest异步的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!