如何让返回调用等待async完成c#

本文关键字:async 完成 等待 调用 返回 | 更新日期: 2023-09-27 18:25:41

我用用户名和密码调用这个静态登录方法。我希望它等待返回,直到下载字符串同步完成。对于我的怪异生活,我不能等待。

我试过老式

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);            
    }

如何让返回调用等待async完成c#

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

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

现在,由于您使用的是WindowsPhone8,您可以在这里安全地使用异步:

    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);
        }
    }

异步必须编译,因为它只是起作用。如果您遇到问题,请在此处再次询问您的代码片段。

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

如果需要阻塞线程直到异步操作完成,可以使用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););
                            };
}

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

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

您最好使用Windows Phone的HttpClient,并使用async/await模式。您可以将其作为Microsoft.Net.Http包从NuGet下载。

您可以在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;

}

因此,这样一来,您就可以等待您的电话,直到回拨回来。这是实现功能的最有效和最新的方法