我该如何处理这个windowsphone网络客户端异步问题
本文关键字:windowsphone 网络 客户端 问题 异步 何处理 处理 | 更新日期: 2024-10-19 00:15:39
我有一个方法如下:
public decimal GetExchangeRate(string fromCurrency, string toCurrency)
{
GoogleCurrencyService googleCurrencyService = new GoogleCurrencyService();
return googleCurrencyService.GetRateForCurrency(fromCurrency, toCurrency);
}
另一类如下
public class GoogleCurrencyService
{
public decimal GetRateForCurrency(string fromCurrency, string toCurrency)
{
try
{
WebClient client = new WebClient();
client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(StringDownloadCompleted);
client.DownloadStringAsync(new Uri(_requestUri + fromCurrency + "=?" + toCurrency));
}
catch (Exception)
{
ExchangeRate = 0;
}
return ExchangeRate;
}
private void StringDownloadCompleted(object sender, DownloadStringCompletedEventArgs e)
{
_response = e.Result;
ExchangeRate = ParseResponseAndGetExchangeRate();
}
}//class GoogleCurrencyService
变量ExchangeRate总是为零,所以我相信函数调用"GetRateForCurrency"会在调用异步回调之前返回。我如何确保这种情况不会发生,因为我需要在返回变量ExchangeRate之前进行设置。谢谢此外,我注意到回调永远不会被调用,因为我在其中有一个断点,还有一个没有被调用的异常。所以我不知道问题出在哪里。任何帮助都很感激。
您可以使用事件等待句柄来阻止当前线程并等待异步调用。。。
public class GoogleCurrencyService
{
private const string RequestUri = "http://www.google.com/ig/calculator?hl=en&q=1{0}%3D%3F{1}";
public decimal ExchangeRate { get; private set; }
public decimal GetRateForCurrency(string fromCurrency, string toCurrency)
{
ExchangeRate = 0;
// use a signaler to block this thread and wait for the async call.
var signaler = new ManualResetEvent(false);
try
{
var client = new WebClient();
client.DownloadStringCompleted += StringDownloadCompleted;
// pass the signaler as user token
client.DownloadStringAsync(new Uri(String.Format(RequestUri, fromCurrency, toCurrency)), signaler);
// wait for signal, it will be set by StringDownloadCompleted
signaler.WaitOne();
}
finally
{
signaler.Dispose();
}
return ExchangeRate;
}
private void StringDownloadCompleted(object sender, DownloadStringCompletedEventArgs e)
{
try
{
ExchangeRate = ParseResponseAndGetExchangeRate(e.Result);
}
finally
{
// set signal
((ManualResetEvent)e.UserState).Set();
}
}
private decimal ParseResponseAndGetExchangeRate(string result)
{
return 123;
}
}
EDIT:使用异步模式的同一类
public class GoogleCurrencyService
{
private const string RequestUri = "http://www.google.com/ig/calculator?hl=en&q=1{0}%3D%3F{1}";
public void GetRateForCurrency(string fromCurrency, string toCurrency, Action<decimal> callback)
{
var client = new WebClient();
client.DownloadStringCompleted += StringDownloadCompleted;
// pass the callback as user token
client.DownloadStringAsync(new Uri(String.Format(RequestUri, fromCurrency, toCurrency)), callback);
}
private void StringDownloadCompleted(object sender, DownloadStringCompletedEventArgs e)
{
// parse response to get the rate value
var rate = ParseResponseAndGetExchangeRate(e.Result);
// if a callback was specified, call it passing the rate.
var callback = (Action<decimal>)e.UserState;
if (callback != null)
callback(rate);
}
private decimal ParseResponseAndGetExchangeRate(string result)
{
return 123;
}
}
消耗异步类:
// this is your UI form/control/whatever
public class MyUI
{
public void OnButtonToGetRateClick()
{
var from = "USD"; // or read from textbox...
var to = "EUR";
// call the rate service
var service = new GoogleCurrencyService();
service.GetRateForCurrency(from, to, (rate) =>
{
// do stuff here to update UI.
// like update ui.
});
}
}
也许您将不得不将UI更改发送到UI线程。我这里没有WP框架来证实这一点,但我认为确实如此。
当您运行异步方法时,您将在完成的方法中得到结果,即
StringDownloadCompleted
因此,在您的代码中,您调用async方法并立即返回ExchangeRate,它将始终为0。
您必须在已完成的方法StringDownloadCompleted 中获取ExchangeRate
如果你想在GetRateForCurrency中获得汇率,请同步调用
client.DownloadString(new Uri(_requestUri + fromCurrency + "=?" + toCurrency));
以下是您需要做的操作。
您在类中创建了一个事件。在您的代码中,您启动异步web客户端调用。一旦调用完成,就可以包装数据并设置事件。我倾向于定义可以保存数据的事件参数。
一旦设置了事件,调用者就会收到通知。
如果你想要一个例子,可以在我的帖子中查看来源http://invokeit.wordpress.com/2012/06/30/bing-mapcontrol-offline-tiles-solution-wpdev-wp7dev/
它是bing-maps示例的扩展,并且包含地址查找器类。看看它是如何被激发的,以及客户端是如何得到通知的
调用uri 后可以等待
公共十进制GetRateForCurrency(字符串fromCurrency,字符串toCurrency){
try
{
WebClient client = new WebClient();
client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(StringDownloadCompleted);
client.DownloadStringAsync(new Uri(_requestUri + fromCurrency + "=?" + toCurrency));
Thread.sleep(500000); //waiting
}
catch (Exception)
{
ExchangeRate = 0;
}
return ExchangeRate;
}
所以设置一个类似webcontrol的标签并进行
private void StringDownloadCompleted(object sender, DownloadStringCompletedEventArgs e)
{
_response = e.Result;
yourlabel.Text = _response ;
ExchangeRate = ParseResponseAndGetExchangeRate();
}
您唯一的选择是使GetRateForCurrency
也异步(这意味着引发自己的Completed
事件)。
如果支持TPL,您可以使用Task<T>
作为一种很好的方式来将异步封装到链中,但不幸的是,WP7不支持它。
作为一种替代方案,以及我所做的,是使用反应扩展(Microsoft.Phone.Reactive
)并将IObservable
传递到链的下游——然而,如果你只想在这一种情况下使用Rx,那么它还有很多需要学习的地方。