programación metodos ejemplos ejemplo con asíncrona asincronos c# asynchronous windows-phone-8 async-await cancellationtokensource

metodos - programación asíncrona con c# pdf



Manejar la cancelación del método asíncrono (1)

Estoy usando Parse como una tienda de datos para una aplicación, y estoy implementando su funcionalidad de inicio de sesión de Facebook . AFAIK, este método de inicio de sesión no es diferente de otros métodos asíncronos, así que con suerte se aplica.

Por lo tanto, hay una página Login.xaml, que tiene un botón para "Iniciar sesión con Facebook", y al tocar este botón se accede a la página FacebookLogin.xaml que contiene solo el control WebBrowser según el documento de Parse vinculado. En ContentPanel.Loaded en FacebookLogin.xaml, puedo usar el siguiente código para iniciar sesión:

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) { } }

Si realmente inicio sesión, funciona, y puedo navegar al usuario a la siguiente página. El problema ocurre cuando dejo cargar el control del navegador (por lo que el método async está esperando ), y luego presiono el botón Atrás , y luego vuelvo a la página de inicio de sesión de Facebook .

Cuando hago esto, se lanza una OperationCancelledException , pero no estoy seguro de cómo manejarla. Lo que he intentado:

  1. En la catch de OperationCanceledException , configure reinicializar el control WebBrowser a uno nuevo. Esto no tuvo efecto.

  2. En la misma catch , vuelva a llamar a FacebookLogin() para volver a intentarlo. Esto tampoco funcionó.

  3. También intenté no utilizar await y devolver una Task<ParseUser> pero tampoco estaba seguro de cómo hacerlo.

¿Hay algo que pueda hacer con la excepción de cancelación, o use un CancellationToken para manejar esto mejor? Solo quiero manejar adecuadamente la cancelación para que pueda volver a cargar la página de inicio de sesión de Facebook si el usuario presiona "Atrás".

SOLUCIÓN:

Ok, después de mucha orientación de @JNYRanger, he encontrado una solución de trabajo. Puede haber una mejor manera, pero esto parece funcionar. Aquí está el código completo de mi 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); } }

Así que, básicamente, cuando se presiona "Atrás", utilizo el CancellationToken para solicitar una cancelación, que arroja una excepción. Cuando ocurre la excepción, configuro la task como nula. Ahora, al volver a navegar a la página de FacebookLogin (sin iniciar sesión previamente), la task puede volver a crear con éxito.


Nunca tener métodos de async void . No puede manejar las excepciones correctamente en ellos. Si su método async no devuelve nada, utilice la async Task (no genérica) como el tipo de devolución en su lugar.

A continuación, puede esperar en su Task devuelta para manejar las excepciones correctamente.

Si va a establecer el uso de CancellationTokens haga que pase el token de CancellationTokenSource al método async . Luego puede registrar este token en una devolución de llamada o continuar pasando el token al método de LoginAsync si esa sobrecarga está disponible. Utilicé este artículo de MSDN para familiarizarme con los métodos de cancelación.

También eche un vistazo a este artículo del blog de MSDN con respecto a evitar los problemas de falta de sincronización: las mejores prácticas de Async-Await

EDITAR
Por la edición en su pregunta, quería señalar algo. Si llamas

Task<ParseUser> t = FacebookLogin()

Ahora tiene un objeto Task que puede hacer cosas. Sin embargo, si solo quiere el objeto ParseUser y no tiene continuaciones o necesita hacer algo más con la Task , debería usar await una vez más.

ParseUser p = await FacebookLogin();

Como está en un controlador de eventos (cargado), es la única excepción en la que está bien tener un async void

En cuanto a lo que sucede cuando ocurre una cancelación, bueno eso depende de usted. Puede cerrar la ventana de inicio de sesión, cancelar otras tareas / métodos, etc.