如何使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
则可以进一步简化此代码。
- 在.NET 4.5中找不到HttpClient
- 如何在Windows 8.1应用程序和Windows Phone 8应用程序中使用SOAP?
- Thread.CurrentPrincipal已经过身份validation,但ClaimsPrincipal.Current不是
- 如何在不中断async / await的情况下创建HttpWebRequest?
- Task.WaitAll不等待任务完成
- LogicalOperationStack与.Net 4.5中的异步不兼容
- MVC 4 Connectionstring到SQL Server 2012
- 如何防止回到上一页
- 什么时候.NET Monitor完全进入内核模式?