WebClient.DownloadDataTaskAsync vs. HttpClient.GetAsync



我仍然在了解。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.DownloadDataTaskAsyncHttpClient.GetAsync都是返回Taskasync方法。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.

以同步方式使用Async方法。

最新更新