-2

我正在使用用户名和密码调用此静态登录方法。我希望它等到下载字符串异步完成后再返回。对于我这该死的生活,我不能让它等待。

我试过老派

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

4 回答 4

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 包,你就可以毫无问题地编译它。

于 2013-08-01T10:48:29.353 回答
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););
                            };
}
于 2013-08-01T03:29:13.687 回答
1

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

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

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

于 2013-08-01T09:05:49.873 回答
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;

}

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

于 2013-08-01T10:37:59.657 回答