WebClient.DownloadDataTaskAsync vs. HttpClient.GetAsync
本文关键字:GetAsync HttpClient vs DownloadDataTaskAsync WebClient | 更新日期: 2023-09-27 17:52:57
我仍然在了解。net 4.5的各种异步特性,并且我遇到了一些有趣的事情。在我的MVC控制器中给定以下内容,我在执行(1)和(2)
时得到不同的结果public ActionResult Index() {
var stuff = SomeExpensiveFunction();
return View(stuff);
}
private byte[] SomeExpensiveFunction() {
string url = "http://some-url.../";
// (1)
var wc = new WebClient();
return wc.DownloadDataTaskAsync(url).Result;
// (2)
var hc = new HttpClient();
return hc.GetAsync(url).Result.Content.ReadAsByteArrayAsync().Result;
}
表面上看,它们似乎是相同的- WebClient.DownloadDataTaskAsync
和HttpClient.GetAsync
都是返回Task
的async
方法。WebClient
版本返回Task<byte[]>
,而HttpClient
版本返回Task<HttpResponseMessage>
,我必须从中挖掘字节,但我以任何方式调用.Result
,我希望在离开函数之前完成。
与(1),我得到一个黄屏与An asynchronous operation cannot be started at this time...
。有了(2),一切都很好。
我可以改变整个堆栈,并在控制器方法本身和SomeExpensiveFunction
上使用async
,一切都很好。但我试图弄清楚是否有根本性的错误与(1)或WebClient
一般与MVC工作时。任何想法吗?
EDIT:我知道在这个例子中,我可以使用这些调用的同步版本,因为我并没有真正异步地做任何事情——这只是一个基于更大代码库的例子。
你触犯了ASP。净的SynchronizationContext。要使WebClient示例工作,您应该使整个控制器异步。试试这个:
public async Task<ActionResult> IndexAsync() {
string url = "http://some-url.../";
using (var wc = new WebClient())
return View(await wc.DownloadDataTaskAsync(url));
}
请参阅http://www.asp.net/mvc/tutorials/mvc-4/using-asynchronous-methods-in-aspnet-mvc-4了解异步控制器的简介,并参阅http://www.tugberkugurlu.com/archive/asynchronousnet-client-libraries-for-your-http-api-and-awareness-of-async-await-s-bad-effects了解async/await模式的死锁效果。
我不是100%确定,但这可能是由于不当使用异步方法。也许您看到这种行为是因为您不希望通过调用Result.