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:
En la
catch
deOperationCanceledException
, configure reinicializar el controlWebBrowser
a uno nuevo. Esto no tuvo efecto.En la misma
catch
, vuelva a llamar aFacebookLogin()
para volver a intentarlo. Esto tampoco funcionó.También intenté no utilizar
await
y devolver unaTask<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.