C# 异步方法的句柄取消

C# 异步方法的句柄取消,c#,asynchronous,windows-phone-8,async-await,cancellationtokensource,C#,Asynchronous,Windows Phone 8,Async Await,Cancellationtokensource,我将其用作应用程序的数据存储,并实现其功能。好吧,这个登录方法和其他异步方法没有什么不同,所以希望它能应用 因此,有一个Login.xaml页面,其中有一个“使用Facebook登录”按钮,点击该按钮将进入FacebookLogin.xaml页面,该页面仅包含链接解析文档中的WebBrowser控件。在FacebookLogin.xaml上的ContentPanel.Loaded中,我可以使用以下代码登录: async void FacebookLogin() { try {

我将其用作应用程序的数据存储,并实现其功能。好吧,这个登录方法和其他异步方法没有什么不同,所以希望它能应用

因此,有一个Login.xaml页面,其中有一个“使用Facebook登录”按钮,点击该按钮将进入FacebookLogin.xaml页面,该页面仅包含链接解析文档中的
WebBrowser
控件。在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
方法正在等待),然后点击Back按钮,然后再次返回Facebook登录页面时,就会出现问题

当我执行此操作时,会抛出一个
操作取消异常
,但我不确定如何处理它。我所尝试的:

  • 操作取消例外
    捕获
    中,将
    WebBrowser
    控件重新初始化为新控件。这没有效果

  • 在相同的
    catch
    中,再次调用
    FacebookLogin()
    ,以重试。这也没用

  • 我也尝试过不使用
    await
    并返回
    任务
    ,但我也不知道该怎么做

  • 对于取消异常,我可以做些什么,或者使用
    CancellationToken
    更好地处理这个问题吗?我只是想妥善处理取消,以便在用户按“后退”时可以重新加载Facebook登录页面

    解决方案:

    好的,在@JNYRanger的大量指导下,我想出了一个有效的解决方案。也许有更好的办法,但这似乎有效。以下是my 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);
       }
    }
    
    公共部分类LoginFacebook:PhoneApplicationPage
    {
    任务;
    取消令牌源;
    公共登录facebook()
    {
    初始化组件();
    ContentPanel.Loaded+=ContentPanel\u Loaded;
    }
    已加载异步void ContentPanel_(对象发送方,路由目标)
    {
    试一试{
    source=新的CancellationTokenSource();
    task=ParseFacebookUtils.LogInAsync(fbBrowser,new[]{“user_likes”},source.Token);
    等待任务;
    //已登录!继续。。。
    }
    catch(异常ex){task=null;}
    }
    BackKeyPress上受保护的覆盖无效(System.ComponentModel.CancelEventArgs e)
    {
    if(task!=null)source.Cancel(false);
    基础。按Backkeypress(e);
    }
    }
    

    所以基本上,当按下“Back”时,我使用
    CancellationToken
    请求取消,这会引发异常。当异常发生时,我将
    task
    设置为null。现在,当重新导航到FacebookLogin页面(之前未登录)时,可以成功地重新创建
    任务

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

    然后,您可以等待返回的
    任务
    正确处理异常

    如果要设置use
    CancellationTokens
    使您可以将
    CancellationTokenSource
    的令牌传递给
    async
    方法。然后,您可以将该令牌注册到回调中,或者继续将该令牌传递到
    LoginAsync
    方法中(如果该重载可用)。我用这个来熟悉取消的方法

    另请参阅MSDN博客中有关避免
    async void
    问题的这篇文章:

    编辑
    根据你问题中的编辑,我想指出一些东西。如果您致电

    Task<ParseUser> t = FacebookLogin()
    
    由于这是在一个事件处理程序(已加载)中,因此可以使用
    异步void


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

    谢谢您提供的信息,请查看我的更新。我仍然很困惑,当发生取消异常时,我到底需要做什么?这取决于当方法被取消时您希望发生什么。当方法被取消时,您希望发生什么?还请记住,当您调用
    wait
    时,您得到的是包装的值,而不是任务本身。对,我不需要任务,只需要
    ParseUser
    ,这样我就可以在以后使用它。因此,当我转到FacebookLogin.xaml时,浏览器将加载,异步方法将等待用户登录。如果用户没有登录,而是点击“返回”,然后再次返回FacebookLogin.xaml页面,则会发生取消异常。我不需要任何特别的事情发生,我只需要正确地处理任务,这样我就可以再次尝试调用
    LoginAsync()
    。这就是我感到困惑的地方。我可以捕获异常,但是如果我尝试从那里再次调用
    FacebookLogin()
    ,我会立即收到另一个任务取消异常。好像页面或其他东西需要刷新。这可能是另一个问题。但是,最好在此时取消整个登录并更改窗口,而不是自动重试。请小心,您仍然有不是事件处理程序的
    async void
    方法。我不确定如何在没有
    async void
    的情况下使其工作,因为如果
    FacebookLogin()
    返回一个
    任务
    ,我必须在
    FacebookLogin()
    上使用
    wait
    ,这将要求我在
    ContentPanel\u加载的
    上使用
    async
    ,这会给我另一个
    async void
    ?实际上,根据您提供的文章,如果
    async
    m
    ParseUser p = await FacebookLogin();