我有这样的代码:
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;
}
但由于某种原因,代码堆积在return await task.ContinueWith(t => ReadStreamFromResponse(t.Result));
并且只是冻结。
有没有更好的方法可以做到这一点,或者有人可以解释发生了什么?
我对await
....
答案 0 :(得分:7)
call to Result
in your foreach
loop is causing a deadlock,正如我在博客中解释的那样。总之,await
将捕获“上下文”(例如,UI上下文),并使用它来恢复async
方法。一些上下文(例如,UI上下文)仅允许上下文中的一个线程。因此,如果通过调用Result
来阻止该特殊线程(例如,UI线程),则async
方法无法在该上下文中继续执行。
因此,解决方案是更改foreach
循环:
foreach(var url in myUrlList)
{
string body = await ProcessAsync(method);
}
其他说明:
任务返回方法应以“异步”结尾,以跟随TAP guidelines。
Task.Factory.FromAsync
是不必要的; HttpWebRequest
已经有了等待的方法。更好的选择是使用HttpClient
代替。
我建议您不要使用Task.ContinueWith
(或Task.Result
或Task.Wait
);请改用await
。
通过这些简化:
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
,则可以进一步简化此代码。