3

Я использую Parse как хранилище данных для приложения, и я реализую их функциональность Facebook Login. AFAIK, этот метод входа не отличается от других методов async, поэтому, надеюсь, он применим.Отказ от асинхронного метода

Таким образом, есть страница Login.xaml, в которой есть кнопка «Войти в Facebook», и нажатие этой кнопки приведет вас к странице FacebookLogin.xaml, которая содержит только элемент управления WebBrowser в соответствии с связанной документацией. В ContentPanel.Loaded на FacebookLogin.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. В catch для OperationCanceledException, установить повторно инициализировать WebBrowser управление новым. Это не имело никакого эффекта.

  2. В том же catch, позвоните по телефону FacebookLogin(), чтобы повторить попытку. Это тоже не сработало.

  3. Я также пытался не использовать await и возвращать Task<ParseUser>, но я не был уверен, как это сделать.

Есть ли что-то я могу сделать, за исключением отмены, или использовать CancellationToken, чтобы справиться с этим лучше? Я просто хочу правильно обработать отмену, чтобы я мог повторно загрузить страницу входа в систему 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); 
    } 
} 

Так в основном, когда «Back» нажата, я использую CancellationToken, чтобы запросить отмены, который вызывает исключение. Когда возникает исключение, я установил task в значение null. Теперь, когда вы переходите на страницу FacebookLogin (без предварительной регистрации), task может быть успешно воссоздан.

+0

Осторожно, у вас все еще есть методы async void, которые не являются обработчиками событий. – JNYRanger

+0

Я не уверен, как заставить его работать без 'async void', потому что если' FacebookLogin() 'возвращает' Task ', мне придется использовать 'await' на' FacebookLogin() ', что потребовало бы мне использовать 'async' в' ContentPanel_Loaded', что дает мне еще одну «асинхронную пустоту»? – lhan

+0

На самом деле, в соответствии с предоставленной вами статьей, если метод 'async' является обработчиком событий (поскольку' ContentPanel_Loaded' будет), это нормально. Так это было бы лучшим решением, чтобы просто сделать 'ContentPanel_Loaded'' async'? – lhan

ответ

4

Никогда не принимайте async void методов. Вы не можете правильно обрабатывать исключения. Если ваш метод async ничего не возвращает, используйте вместо этого вместо этого тип async Task (не общий).

Затем вы можете ждать по возвращенному Task, чтобы правильно обрабатывать исключения.

Если вы собираетесь использовать CancellationTokens, то сделайте свой тоновый маркер CancellationTokenSource методу async. Затем вы можете зарегистрировать этот токен либо в обратном вызове, либо продолжать передавать токен в метод LoginAsync, если эта перегрузка доступна. Я использовал это MSDN article, чтобы ознакомиться с методами отмены.

Также обратите внимание на эту статью из блога MSDN относительно избежать async void вопросов: Async-Await Best Practices

EDIT
Per редактирования в вашем вопросе я хотел бы указать что-то. Если вы звоните

Task<ParseUser> t = FacebookLogin() 

Теперь у вас есть Task объект, который вы можете сделать вещи с. Однако, если вы просто хотите объект ParseUser и не имеете никаких дальнейших действий или вам нужно что-либо делать с Task, вы должны снова использовать await.

ParseUser p = await FacebookLogin(); 

Так как это в обработчике событий (нагруженной) это одно исключение, когда это нормально, чтобы иметь async void

Что касается того, что происходит, когда вы происходит отмена, так что до вас. Вы можете закрыть окно входа в систему, отменить другие задачи/методы и т. Д.

+0

Благодарим вас за информацию, пожалуйста, ознакомьтесь с моим обновлением. Я все еще смущен тем, что мне нужно на самом деле делать *, когда возникает исключение отмены? – lhan

+0

Это зависит от того, что вы хотите, когда метод отменен. Что вы хотите, когда метод отменен? Также имейте в виду, что когда вы вызываете 'await', вы получаете завернутое значение, а не сама задача. – JNYRanger

+0

Правильно, мне не нужна задача, только «ParseUser», поэтому я могу использовать ее после. Итак, когда я перехожу на FacebookLogin.xaml, браузер загружается, и асинхронный метод ожидает входа пользователя. Если пользователь не входит в систему и вместо этого отбирает обратно, а затем снова возвращается на страницу FacebookLogin.xaml, возникает исключение отмены. Мне не нужно ничего особенного, я просто нуждаюсь в задаче, чтобы ее можно было утилизировать, чтобы я снова попытался вызвать 'LoginAsync()'. – lhan

 Смежные вопросы

  • Нет связанных вопросов^_^