5

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

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

  1. 登录并获取令牌
  2. 使用 #1 中的令牌,获取专辑列表
  3. 使用 #1 中的令牌获取类别列表
  4. ETC

我的课程公开了一些方法:

  1. 登录()
  2. 获取相册()
  3. 获取类别()

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

在我的课堂上公开这些方法的好方法是什么?

4

4 回答 4

7

你可以看看 Reactive (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));

整洁的东西。:)

于 2010-03-19T20:21:52.307 回答
3

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

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

有一个明显的问题是,您想要等待而不继续,直到您通过网络收到返回的东西(例如,如果您想保留登录页面,直到您知道您已成功通过身份验证)。在这种情况下,您可以只更改异步回调中的页面。

你显然也可以做一些更花哨的事情,让一个线程等待异步回调设置的事件。我建议不要让 UI 线程执行此操作,因为它会限制您进行超时等操作的能力,并且通常会非常混乱。

于 2010-03-19T18:29:46.873 回答
1

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

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

服务代码对 Web 服务进行异步调用,当它返回时,如果调用成功则调用成功回调,如果出现故障/异常则调用失败回调。然后调用代码有点像这样:

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

(UIInvoker 只是一个从后台线程分派回 UI 的实用程序。)

于 2010-03-20T03:18:40.657 回答
1

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

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

我在下面包含了代码来展示如何使用该库从 Twitter 中检索推文。

Restful-Silverlight 从 Twitter 检索推文的示例用法:


//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();

于 2010-12-21T20:04:15.543 回答