我将一些代码从完整的.NET框架移植到WP7版本,我遇到了同步和异步调用的问题。
string response;
string requestString = GenerateReqString();
HttpWebRequest req = (HttpWebRequest) WebRequest.Create("endpoint");
req.Method = "POST";
req.ContentType = "text/xml";
req.ContentLength = requestString.Length;
StreamWriter sw = new StreamWriter (req.GetRequestStream(), System.Text.Encoding.ASCII);
sw.Write(requestString);
sw.Close();
StreamReader sr = new StreamReader(req.GetResponse().GetResponseStream());
response = sr.ReadToEnd();
sr.Close();
然后将响应字符串解析为方法返回的对象列表。
我遇到的问题是没有办法在Silverlight / WP7中同步进行调用。如果我使用回调,我将在不同的函数中获得响应,并且无法从原始函数返回它。有没有办法同步进行调用或从CallBack函数返回到启动异步调用的方法?
答案 0 :(得分:11)
您需要以不同的方式思考问题。要使异步事物“感觉”同步,最简单的方法是重构代码以使用“continuation passing style”。
本质上,您不是调用返回值的函数然后处理该值,而是调用函数,将匿名函数作为委托传递给它。然后被调用的函数将调用委托,传入字符串。
这是一个使用匿名函数和lambdas的例子:
void DoSomethingAsync( Action<string> callback ) {
HttpWebRequest req; // TODO: build your request
req.BeginGetResponse( result => {
// This anonymous function is a closure and has access
// to the containing (or enclosing) function.
var response = req.EndGetResponse( result );
// Get the result string and call the callback
string resultString = null; // TODO: read from the stream
callback(resultString);
}, null );
}
这是解决方案的一半。接下来的部分是实际调用它。想象一下,你有一个ICommand实例或更简单的按钮点击事件,需要调用此函数并“获取字符串”。你不是“获取字符串”而是调用这个函数并提供一个回调方法(这将是一个闭包)。
void btnGo_Click( object sender, EventArgs e ) {
DoSomethingAsync( resultString => {
// This anonymous function is called when the web request has
// finished and has your string.
// Now that we have the string, we can go and process it.
ProcessWebResponseResult( resultString );
});
}
这是一篇非常好的文章,进一步解释了这个概念: http://blogs.msdn.com/b/wesdyer/archive/2007/12/22/continuation-passing-style.aspx
答案 1 :(得分:2)
首先,我建议您尝试使用异步,但如果您确实需要/需要将异步调用转换为同步,则可以使用ManualResetEvent
来获得所需的结果。
以下是使用时的快速示例:
public ManualResetEvent _event = new ManualResetEvent(false);
...
{
...
var wc = new WebClient();
wc.OpenReadCompleted += new OpenReadCompletedEventHandler(ReadCompleted);
wc.OpenReadAsync(uri);
// block until async call is complete
_event.WaitOne();
}
private static void ReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
...
// set event to unblock caller
_event.Set();
}
现在,您的代码将在_event.WaitOne();
行阻止,直到调用_event.Set();
。
祝你好运!
答案 2 :(得分:1)
查看Wintellect的Power Threading库,它允许您使用同步编程模型执行异步操作。
http://csharperimage.jeremylikness.com/2010/03/sequential-asynchronous-workflows-in.html
答案 3 :(得分:-2)
最好以异步方式执行此操作,以便用户可以继续与设备进行交互。
我怀疑你想要这样做的原因是为了防止用户在完成请求之前与某些控件进行交互。
接受此方法的方法是隐藏或禁用在请求处理期间不应与之交互的UI元素。