处理异步方法的取消

时间:2014-01-21 02:26:08

标签: c# asynchronous windows-phone-8 async-await cancellationtokensource

我正在使用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,但我不确定如何处理它。我尝试了什么:

  1. catch的{​​{1}}中,设置将OperationCanceledException控件重新初始化为新控件。这没有效果。

  2. 在相同的WebBrowser中,再次致电catch,重试。这也行不通。

  3. 我也尝试过不使用FacebookLogin()并返回await,但我也不知道如何去做。

  4. 我可以对取消例外做些什么,或使用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

1 个答案:

答案 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

关于取消发生时会发生什么,这取决于你。您可以关闭登录窗口,取消其他任务/方法等。