我正在使用Parse作为应用的数据存储,我正在实施他们的Facebook Login功能。 AFAIK,这个Login方法与其他异步方法没什么不同,所以希望它适用。
因此,有一个Login.xaml页面,其中有一个“使用Facebook登录”按钮,点击此按钮会将您带到FacebookLogin.xaml页面,该页面仅包含链接Parse的WebBrowser
控件documenation。在FacebookLogin.xaml的ContentPanel.Loaded
中,我可以使用以下代码登录:
async void FacebookLogin()
{
try
{
user = await ParseFacebookUtils.LogInAsync(fbBrowser, new[] { "user_likes", "email" });
}
catch (OperationCanceledException oce)
{
// task was cancelled, try again
//task = null;
//FacebookLogin();
}
catch (Exception ex)
{
}
}
如果我实际登录,它可以工作,我可以将用户导航到下一页。当我让浏览器控制加载时(async
方法等待),然后点击返回按钮,,然后来再次返回Facebook登录页面。
当我这样做时,会抛出OperationCancelledException
,但我不确定如何处理它。我尝试了什么:
在catch
的{{1}}中,设置将OperationCanceledException
控件重新初始化为新控件。这没有效果。
在相同的WebBrowser
中,再次致电catch
,重试。这也行不通。
我也尝试过不使用FacebookLogin()
并返回await
,但我也不知道如何去做。
我可以对取消例外做些什么,或使用Task<ParseUser>
来更好地处理这个问题?我只想妥善处理取消,以便在用户按下“返回”时重新加载Facebook登录页面。
SOLUTION:
好的,经过@JNYRanger的大力指导,我找到了一个有效的解决方案。可能有更好的方法,但这似乎有效。这是我的FacebookLogin.xaml的完整代码:
CancellationToken
所以基本上,当按下“Back”时,我使用public partial class LoginFacebook : PhoneApplicationPage
{
Task<ParseUser> task;
CancellationTokenSource source;
public LoginFacebook()
{
InitializeComponent();
ContentPanel.Loaded += ContentPanel_Loaded;
}
async void ContentPanel_Loaded(object sender, RoutedEventArgs e)
{
try {
source = new CancellationTokenSource();
task = ParseFacebookUtils.LogInAsync(fbBrowser, new[] { "user_likes" }, source.Token);
await task;
// Logged in! Move on...
}
catch (Exception ex) { task = null; }
}
protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{
if (task != null) source.Cancel(false);
base.OnBackKeyPress(e);
}
}
请求取消,这会引发异常。发生异常时,我将CancellationToken
设置为null。现在,当重新导航到FacebookLogin页面(之前没有登录)时,可以成功重新创建task
。
答案 0 :(得分:4)
从不使用async void
方法。您无法在其中正确处理异常。如果您的async
方法未返回任何内容,请使用async Task
(非通用)作为返回类型。
然后,您可以等待已退回的Task
正确处理例外情况。
如果您要设置使用CancellationTokens
,请让您将CancellationTokenSource
的令牌传递给async
方法。然后,您可以将此标记注册到回调,或者如果该重载可用,则继续将标记传递到LoginAsync
方法。我用MSDN article来熟悉取消方法。
另请参阅MSDN博客中有关避免async void
问题的文章:Async-Await Best Practices
修改强>
根据你的问题编辑,我想指出一些问题。如果你打电话
Task<ParseUser> t = FacebookLogin()
您现在拥有一个Task
对象,您可以使用它。但是,如果您只想要ParseUser
对象并且没有延续或需要对Task
执行任何其他操作,则应再次使用await
。
ParseUser p = await FacebookLogin();
由于这是在事件处理程序(已加载)中,因此可以使用async void
关于取消发生时会发生什么,这取决于你。您可以关闭登录窗口,取消其他任务/方法等。