如何将 .net 4.5 Async/Await 示例转换回 4.0?

14

ASP.NET MVC 4.0的等效代码是什么?

using System.Net;
using System.Net.Http;
using System.Web.Mvc;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace Web.Controllers
{
    public class HomeController : Controller
    {
        private HttpClient httpClient = new HttpClient();
        private static dynamic shots;

        public async Task<ActionResult> Index()
        {
            if (shots == null)
            {
                try
                {
                    var responseMessage = 
                       await httpClient.GetAsync
                            ("http://api.dribbble.com/shots/everyone?per_page=30");
                    responseMessage.EnsureSuccessStatusCode();

                    var value = await responseMessage.Content.ReadAsStringAsync();
                    shots = await JsonConvert.DeserializeObjectAsync<dynamic>(value);
                }
                catch (WebException)
                {
                }
            }
            return View(shots);
        }
    }
}

这真的有效吗?疯狂!我得去看看这个疯狂的4.5东西。如果我想要异步UI交互,我会使用ajax/json,如果我想要异步服务器工作而不需要将数据返回给客户端,我可能会考虑生成一个线程或使用后台工作者 - musefan
1
任务并行库是 .NET 4 的一个非常好用的功能。完全没有必要使用更重、更繁琐的后台工作器。 - Panagiotis Kanavos
4个回答

9

注意: 这仅适用于Async/Await部分。

最简单的方法是使用Async CTP。它有一个Go Live许可证,这意味着您可以在生产代码中使用它。在Async CTP不提供异步等效项的情况下,您将需要进行一些修改。

您可以在Azure上使用Async CTP,唯一需要的是额外的DLL。这里有一个类似的SO问题:Async CTP和Windows Azure支持

我已经在生产中使用Async CTP超过一年了,没有任何问题。我绝对推荐这个。升级到.NET 4.5相当容易,基本上只需要一些类名更改(从TaskEx到Task)和一些签名更改。

如果您可以使用Visual Studio 2012 RC,则还可以使用Async Targeting pack,这将允许您在.NET 4中使用异步代码,而无需进行太多更改,与使用Async CTP相比。

最后,强制解决方案是使用ParallelExtensionsExtras示例中的TaskIterator来模拟async/await的功能。您将需要将所有异步调用转换为任务或返回任务的方法,然后遍历这些任务列表。这是更多的代码,但如果您不想使用CTP代码,即使它具有Go Live许可证,这是唯一的解决方案。

ParallelExtensionsExtras包括WebClient的异步任务,如果您决定从HttpClient切换到WebClient,则可能会有用。


PS...我已经浪费了无数个小时来处理WebClient及其不必要的异常。真希望我6个月前就知道Nuget上的HttpClient... - Panagiotis Kanavos
好的,哈哈,我得测试一下。是啊,微软通过 NuGet 发布 RC 版本,这很酷,有很多带外版本发布。 - superlogical
但是即使安装了Async CTP或从中获取AsyncCtpLibrary.dll,.NET 4.0中仍然无法使用HttpClient - Gennady Vanin Геннадий Ванин
1
HttpClient不在Async CTP中,它在自己的包中。 - Panagiotis Kanavos
@PanagiotisKanavos,在“.NET4.0/VS2010 + Async CTP”情况下,它是否仅在其自己的包中?没有文档可供参考。因此,我查看了十几个有关VS2012(.NET 4.5)异步/等待编程的How-to和Walkthroghs。大多数使用HttpClient,但从未提到安装获取System.Net.Http.dll包的步骤。 - Gennady Vanin Геннадий Ванин
显示剩余3条评论

5

作为一个探索如何在.NET 4.0中使所有这些工作的人,我发现本主题和其他主题中给出的答案都不够完整,无法立即启动。因此,以下是更全面的答案,告诉您应该简单地做什么:

======= 步骤#1)安装Microsoft ASP.NET Web API客户端库(RC)4.0.20505.0 =======

http://nuget.org/packages/Microsoft.AspNet.WebApi.Client

PM> Install-Package Microsoft.AspNet.WebApi.Client

安装:System.Net.Http.dll,System.Net.Http.Formatting.dll,System.Net.Http.WebRequest.dll,Newtonsoft.Json.dll

======= 步骤 #2) Microsoft .NET Framework 4 HTTP 客户端库 2.0.20505.0 =======

http://nuget.org/packages/Microsoft.Net.Http

PM> Install-Package Microsoft.Net.Http.

如果您已经按照步骤#1操作,NuGet应该已经获取了此依赖项:System.Net.Http.dll。 System.Net.Http. 提供了 HttpClient、HttpRequestMessage 和 HttpResponseMessage。
此时,使用async/await时会出现错误(尽管这些关键字仍然显示为关键字),指出如下内容:
“无法找到“async”修饰符所需的所有类型。您是否针对错误的框架版本或缺少对程序集的引用?”
因此:
======= 步骤#3)Visual Studio 的异步定位包 =======

http://www.microsoft.com/en-us/download/details.aspx?id=29576

PM> Install-Package Microsoft.CompilerServices.AsyncTargetingPack

('...Visual Studio 11'的名称需要在NuGet上更新,两者版本均为1.0.0)

安装了1个dll:Microsoft.CompilerServices.AsyncTargetingPack.Net4.dll

"“Visual Studio 2012异步目标包”使得针对.NET Framework 4.0或Silverlight 5的项目能够使用C# 5中的异步语言特性..." http://www.microsoft.com/en-us/download/details.aspx?id=29576

此外,添加了TaskEx(一个.NET 4.0版本,填充了许多新的Task特性。 TaskEx仅适用于4.0版本...因此.NET 4.5:“Task.Run”在4.0版本中为“TaskEx.Run”,这个库中的其他许多内容也是如此)

突然间,await、async等一系列功能开始完美运作!如果你仔细思考,其中最重要的事情之一就是这个类(没有命名空间声明):AsyncCompatLibExtensions。它是一个静态类,包含了特别的扩展方法,主要针对以下内容: 1)Stream。例如ReadAsync。现在,stream.ReadAsync突然出现了!(实际上,它干净地包装了stream的BeginRead/BeginWrite,如果你想知道的话) 2)WebClient。例如webClient.DownloadStringTaskAsync,等等。


我简直不敢相信有人会因为我耐心地为社区做出贡献而给我一个踩。如果你是真正的男人或女人,何不发表一条评论呢?你可能是同一个人,之前也曾踩过er-v,这毫无意义。顺便提一下,注意日期,4.5版本还没有发布,所以这个答案现在可能已经被取代了。 - Nicholas Petersen

3

警告:没有错误检查!

我觉得今天我学到了一些东西,阅读这篇文章http://blogs.msdn.com/b/pfxteam/archive/2010/11/21/10094564.aspx,以学习更好的处理方式 :)

using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Mvc;
using Newtonsoft.Json;
namespace DribbbleR.Web.Controllers
{
    public class HomeController : Controller
    {
        private static dynamic shots;
        private HttpClient client = new HttpClient();
        private string url = "http://api.dribbble.com/shots/everyone?per_page=30";

        public Task<dynamic> Index()
        {    if (shots == null)
             shots = Task.Factory.StartNew
                   (() => return DownloadContent();).Unwrap();    
             return shots;
        }
        public Task<dynamic> DownloadContent()
        {    var responseTask = client.GetAsync(url);
             var readTask = responseTask.ContinueWith
                 (t =>
                     {   t.Result.EnsureSuccessStatusCode();
                         return t.Result.Content.ReadAsStringAsync();
                      }
                  ).Unwrap();
            var deserializeTask = readTask.ContinueWith
                  (t => return JsonConvert.DeserializeObjectAsync<dynamic>(t.Result);)
            .Unwrap();
            var viewTask = deserializeTask.ContinueWith
                  (t =>  return this.View(t.Result););
            return viewTask;
        }
    }
}

2

真荒谬,有人投票反对这个回答以及我下面的回答。我投了赞成票来平衡一下。 - Nicholas Petersen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接