3

我正在使用Parse作为应用程序的数据存储,并且我正在实现他们的Facebook 登录功能。AFAIK,此登录方法与其他异步方法没有任何不同,因此希望它适用。

因此,有一个 Login.xaml 页面,其中有一个“使用 Facebook 登录”按钮,点击此按钮会将您带到 FacebookLogin.xaml 页面,该页面仅包含WebBrowser链接的 Parse 文档中的控件。在ContentPanel.LoadedFacebookLogin.xaml 中,我可以使用以下代码登录:

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. catchfor 中OperationCanceledException,将控件重新初始化WebBrowser为一个新的。这没有效果。

  2. 同样catch,再次调用FacebookLogin(),重试。这也没有奏效。

  3. 我也尝试过不使用await和返回 aTask<ParseUser>但我也不知道该怎么做。

我可以对取消异常做些什么,或者使用 aCancellationToken来更好地处理这个问题?我只想正确处理取消,以便在用户按“返回”时重新加载 Facebook 登录页面。

解决方案:

好的,经过@JNYRanger 的大量指导,我想出了一个可行的解决方案。可能有更好的方法,但这似乎有效。以下是我的 FacebookLogin.xaml 中的完整代码:

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来请求取消,这会引发异常。当异常发生时,我设置task为null。现在,当重新导航到 FacebookLogin 页面(之前没有登录)时,task可以成功重新创建。

4

1 回答 1

4

从来没有async void方法。您无法正确处理其中的异常。如果您的async方法不返回任何内容async Task,请改为使用(非通用)作为返回类型。

然后,您可以等待返回Task以正确处理异常。

如果您要设置 use CancellationTokensmake your 您将CancellationTokenSource' 的令牌传递给该async方法。然后,您可以将此令牌注册到回调或继续将令牌传递给LoginAsync方法(如果该重载可用)。我使用这篇MSDN 文章来熟悉取消方法。

另请参阅 MSDN 博客中关于避免这些async void问题的这篇文章:Async-Await Best Practices

编辑
根据您问题中的编辑,我想指出一些事情。如果你打电话

Task<ParseUser> t = FacebookLogin()

你现在有了一个Task可以用来做事的对象。但是,如果您只想要该ParseUser对象并且没有延续或需要对您做任何其他事情,Task您应该await再次使用。

ParseUser p = await FacebookLogin();

由于这是在事件处理程序(已加载)中,因此它是一个例外,可以有一个async void

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

于 2014-01-21T02:41:50.783 回答