如何使HttpWebRequest异步

我有这样的代码:

private async Task Request(url) { Task task = null; try { task = MakeAsyncRequest(url, "text/html"); return await task; } catch { return null; } } private async Task 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 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; } } 

我在foreach循环中调用Request(url)

 foreach(var url in myUrlList) { string body = Request(method).Result; } 

但由于某种原因,代码在return await task.ContinueWith(t => ReadStreamFromResponse(t.Result));堆叠return await task.ContinueWith(t => ReadStreamFromResponse(t.Result)); 只是冷冻。

有没有更好的方法来做到这一点,或者可能有人可以解释发生了什么? 我没有得到任何错误await错误….

正如我在博客中解释的那样,在foreach循环中调用Result会导致死锁 。 总之, await将捕获“上下文”(例如,UI上下文),并使用它来恢复async方法。 某些上下文(例如,UI上下文)仅允许上下文中的一个线程。 因此,如果通过调用Result阻止该特殊线程(例如,UI线程),则async方法无法在该上下文中恢复执行。

所以,解决方案是改变你的foreach循环:

 foreach(var url in myUrlList) { string body = await ProcessAsync(method); } 

其他说明:

任务返回方法应以“异步”结束,以遵循TAP指南 。

Task.Factory.FromAsync是不必要的; HttpWebRequest已经有了等待的方法。 更好的选择是使用HttpClient

我建议你不要使用Task.ContinueWith (或Task.Result ,或Task.Wait ); 请改用。

通过这些简化:

 private async Task 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则可以进一步简化此代码。