如何让返回调用等待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);
}
首先,您永远不应该等待异步操作完成。相反,在函数完成后继续执行。
编辑:必须在此处添加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;
}
因此,这样一来,您就可以等待您的电话,直到回拨回来。这是实现功能的最有效和最新的方法