代码之家  ›  专栏  ›  技术社区  ›  Omar Shahine

对于连续的WebClient请求,良好的异步模式

  •  5
  • Omar Shahine  · 技术社区  · 16 年前

    我在.NET中编写的用于进行REST调用的大多数代码都是同步的。因为Windows Phone上的Silverlight只支持异步WebClient和httpWebRequest调用,所以我想知道对于公开进行REST调用的方法的类来说,什么是好的异步模式。

    例如,我有一个应用程序需要执行以下操作。

    1. 登录并获取令牌
    2. 使用1中的令牌,获取相册列表
    3. 使用1中的令牌获取类别列表

    我的类公开了一些方法:

    1. 登录()
    2. GETPalm()
    3. GETCOMPIORIONS()

    因为每个方法都需要使用异步调用来调用WebClient,所以我需要做的基本上是阻止调用login,直到它返回,这样我就可以调用getAlbums()。

    在我的类中,公开这些方法的好方法是什么?

    4 回复  |  直到 15 年前
        1
  •  3
  •   Aurojit Panda    16 年前

    这真的取决于你想用这些信息做什么。例如,如果您正试图显示相册/类别列表等,则建模的一种方法是

    1. 拥有一个或多个实现inotifyPropertiesChanged接口的类,并用作视图的数据源(例如,请查看新PhoneListApplication中Models文件夹下的文件)。
    2. 启动异步操作以登录并获取令牌,让异步方法的回调为您存储令牌,并调用一个函数,该函数将启动异步操作以获取相册和类别列表。
    3. 异步操作获取相册/类别列表的回调可以更新可观察列表(通过向其添加项)。我想你有一个班级,每一个为专辑和类别,每个有一个可观察的列表。无论如何,添加完成后,只需使用所更改的属性的名称调用notifypropertychanged,您的数据就会显示出来。

    有一个明显的问题是,在您通过网络收到消息之前,您需要等待,而不是继续(例如,如果您希望保留登录页面,直到您知道您已经成功地进行了身份验证)。在这种情况下,您可以在异步回调中更改页面。

    显然,您也可以做一些更高级的事情,让线程等待异步回调设置的事件。我建议不要让UI线程这样做,因为它限制了您拥有超时等功能,并且通常非常混乱。

        2
  •  7
  •   JerKimball    16 年前

    您可以看一下反应式(RX)框架扩展:

    http://www.leading-edge-dev.de/?p=501

    http://themechanicalbride.blogspot.com/2009/07/introducing-rx-linq-to-events.html

    [编辑:哦-找到一个好链接:] http://rxwiki.wikidot.com/101samples

    它们提供了一种“排序”事件的方法,仅在满足某些条件时才进行操作-例如,假设您有一个方法“authenticationresult authenticate(string user,string pass)”。

    你可以这样做:

    var foo = Observable.FromAsyncPattern<string, string, AuthenticationResult>
        (client.BeginAuthenticate, client.EndAuthenticate);
    var bar = foo("username","password");
    var result = bar.First();
    

    有效地将异步方法转换为同步方法。您可以将此扩展为包括“链接”:

    var bar = foo("username", "password")
        .Then(authresult => DoSomethingWithResult(authresult));
    

    整洁的东西:)

        3
  •  1
  •   Jason Jackson    16 年前

    我们使用所有异步函数签名编写了客户端服务层,如下所示:

    public void MyFunction(
      ArtType arg, 
      Action<ReturnType> success, 
      Action<FailureType> failure);
    

    服务代码对Web服务进行异步调用,当返回时,如果调用成功,则调用Success回调;如果存在错误/异常,则调用Failure回调。然后呼叫代码看起来有点像这样:

    MyServiceInstance.MyFunction(
      blahVar,
      returnVal => UIInvoker.Invoke(() => 
        {
          //some success code here
        }),
      fault => UIInvoker.Invoke(() => 
        {
          //some fault handling code here
        }));
    

    (uiinvoker只是一个从后台线程发回ui的实用程序。)

        4
  •  1
  •   Amir    15 年前

    我把一些更流畅的东西放在一起。

    Restful-Silverlight 是我创建的一个库,用于帮助Silverlight和WP7。

    我已经包含了下面的代码来展示如何使用这个库从Twitter中检索tweets。

    Restful Silverlight从Twitter检索tweets的示例用法:

    
    //silverlight 4 usage
    List<string> tweets = new List<string>();
    var baseUri = "http://search.twitter.com/";
    
    //new up asyncdelegation
    var restFacilitator = new RestFacilitator();
    var restService = new RestService(restFacilitator, baseUri);
    var asyncDelegation = new AsyncDelegation(restFacilitator, restService, baseUri);
    
    //tell async delegation to perform an HTTP/GET against a URI and return a dynamic type
    asyncDelegation.Get<dynamic>(new { url = "search.json", q = "#haiku" })
        //when the HTTP/GET is performed, execute the following lambda against the result set.
        .WhenFinished(
        result => 
        {
            textBlockTweets.Text = "";
            //the json object returned by twitter contains a enumerable collection called results
            tweets = (result.results as IEnumerable).Select(s => s.text as string).ToList();
            foreach (string tweet in tweets)
            {
                 textBlockTweets.Text += 
                 HttpUtility.HtmlDecode(tweet) + 
                 Environment.NewLine + 
                 Environment.NewLine;
            }
        });
    
    asyncDelegation.Go();
    
    //wp7 usage
    var baseUri = "http://search.twitter.com/";
    var restFacilitator = new RestFacilitator();
    var restService = new RestService(restFacilitator, baseUri);
    var asyncDelegation = new AsyncDelegation(restFacilitator, restService, baseUri);
    
    asyncDelegation.Get<Dictionary<string, object>>(new { url = "search.json", q = "#haiku" })
                   .WhenFinished(
                   result =>
                   {
                       List<string> tweets = new List();
                       textBlockTweets.Text = "";
                       foreach (var tweetObject in result["results"].ToDictionaryArray())
                       {
                           textBlockTweets.Text +=
                               HttpUtility.HtmlDecode(tweetObject["text"].ToString()) + 
                               Environment.NewLine + 
                               Environment.NewLine;
                       }
                   });
    
    asyncDelegation.Go();
    
    
    推荐文章