我用.NET编写的用于进行REST调用的大多数代码都是同步的。由于Windows Phone上的Silverlight仅支持Async WebClient和HttpWebRequest调用,因此我想知道暴露出进行REST调用的方法的类有什么好的异步模式。
例如,我有一个需要执行以下操作的应用程序。
我的课程公开了一些方法:
因为每个方法都需要使用异步调用来调用WebClient,所以我需要做的就是阻止调用Login直到它返回,这样我就可以调用GetAlbums()。
在我的班级中有什么好的方法来揭示这些方法?
答案 0 :(得分: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));
整洁的东西。 :)
答案 1 :(得分:3)
这实际上取决于您对此信息的处理方式。例如,如果您试图显示专辑/类别列表等,那么建模的一种方法是
如果您想通过网络收到某些内容(例如,如果您想要保留登录页面,直到您知道自己已成功通过身份验证),则会出现明显的问题。在这种情况下,您只需更改异步回调中的页面即可。
你显然也可以做一些比较漂亮的事情并让线程等待异步回调设置的事件。我建议不要让UI线程执行此操作,因为它限制了您执行超时等操作的能力,并且通常非常混乱。
答案 2 :(得分: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的实用程序。)
答案 3 :(得分:1)
我把一些更流畅的东西放在一起。
Restful-Silverlight是我创建的一个库,用于帮助Silverlight和WP7。
我在下面列出了代码,以展示如何使用该库从Twitter检索推文。
来自Twitter的Restful-Silverlight检索推文的示例用法:
//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();