如何使返回调用等待异步完成c#

时间:2013-08-01 03:24:03

标签: c# asynchronous windows-phone-8

我使用用户名和密码调用此静态登录方法。我希望它等待,直到downloadstringasync完成。对于我的生活,我不能让它等待。

我尝试过oldschool

while(wc.IsBusy){} //Which froze

还尝试了各种甚至没有编译的异步废话

    public static dbObj Login(String username, String password)
    {
        dbObj ret = new dbObj();
        String rawWebReturn = "";
        ret.propBag.Add(_BAGTYPE,returnTypes.Login.ToString());
        DateTime date = DateTime.Now;
        WebClient wc = new WebClient();
        wc.DownloadStringAsync(new Uri(baseLoginURI + "uname=" + username + "&pword=" + password + "&date=" + date.ToString()));   


        wc.DownloadStringCompleted  += (s,e) => {                                         
                                   if(e.Error!=null)
                                      rawWebReturn = e.Error.Message;
                                   else
                                      rawWebReturn = e.Result;
                                };
        return parseWebReturn(rawWebReturn,ret);            
    }

4 个答案:

答案 0 :(得分:3)

首先,您永远不应该等待来完成异步操作。而是在函数完成后继续执行。

编辑:您必须在此处添加NuGet包Microsoft.Bcl.Async

现在,由于您使用的是Windows Phone 8,因此可以安全地在此处使用async:

    public static async dbObj Login(String username, String password)
    {
        dbObj ret = new dbObj();
        String rawWebReturn = "";
        ret.propBag.Add(_BAGTYPE, returnTypes.Login.ToString());
        DateTime date = DateTime.Now;
        WebClient wc = new WebClient();
        try
        {
            var result = await wc.DownloadStringTaskAsync(new Uri(baseLoginURI + "uname=" + username + "&pword=" + password + "&date=" + date.ToString()));
            return parseWebReturn(result, ret);
        }
        catch (Exception e)
        {
            return parseWebReturn(e.Message, ret);
        }
    }

Async 必须编译,因为它才有效。如果您遇到问题,请在此处再次使用您的代码段。

如果你想要定位Windows Phone 7,添加上面提到的NuGet包,你就可以毫无问题地编译它。

答案 1 :(得分:1)

如果您需要阻止线程直到异步操作完成,您可以使用ManualResetEvent,如下所示:

ManualResetEvent wait = new ManualResetEvent(false);

wc.DownloadStringCompleted  += (s,e) => {                                         
    // ...

    // allow to proceed
    wait.Set();
};

// wait until Set
wait.WaitOne();

return parseWebReturn(rawWebReturn,ret); 

通常,您不希望阻止线程,而是使用回调。您可以通过提供Action代理而不是返回值来执行此操作:

public static void Login(String username, String password, Action<dbObj> callback)
{
    // ...

    wc.DownloadStringCompleted  += (s,e) => {                                         
                               if(e.Error!=null)
                                  rawWebReturn = e.Error.Message;
                               else
                                  rawWebReturn = e.Result;

                               Callback(parseWebReturn(rawWebReturn, ret););
                            };
}

答案 2 :(得分:1)

如果您通过旋转while循环或使用ManualResetEvent.WaitOne强制在UI线程中等待,那么您实际上是在使应用程序陷入僵局。在某些时候网络调用似乎需要触摸UI线程,但你已经冻结它=死锁。

像这样冻结UI线程在许多其他方面也很糟糕(不会处理任何触摸事件,没有屏幕更新等)。

最好使用HttpClient for Windows Phone并使用async / await模式。您可以从NuGet下载此软件作为Microsoft.Net.Http软件包。

答案 3 :(得分:1)

您可以借助Async和Await方法重写现有的WebClient方法

public Task<string> GetRssFeed(string feedUrl)
{
       var tcs = new TaskCompletionSource<string>();
       var client = new WebClient();
       client.DownloadStringCompleted += (s, e) =>
       {
             if (e.Error == null)
             {
                  tcs.SetResult(e.Result);
             }
             else
             {
                  tcs.SetException(e.Error);
             }
        };

        client.DownloadStringAsync(new Uri(feedUrl));
        return tcs.Task;

}

通过这样做,你可以等待你的电话,直到回调回来。这是实现功能的最有效和最新的方法