async await code

Les bénéfices de la programmation asynchrone sont nombreux. Notre application est plus réactive, plus performante, surtout lorsqu’elle a une IHM. Elle utilise mieux les ressources de la machine sur laquelle elle tourne.

Les exceptions sont des comportements anormaux, des erreurs qui peuvent se produire lors de l’exécution de notre programme. La gestion des exceptions est différentes entre la programmation synchrone et asynchrone.

Voyons dans ce petit article comment gérer les exceptions efficacement dans les méthodes asynchrones.

Une méthode asynchrone peut retourner trois types de valeurs Void, Task et Task<T>. La prise en charge des exceptions sera différente en fonction du type de retour.

Les exceptions dans les méthodes asynchrones retournant void

try
{
    ThrowExceptionAsync();
}
catch (Exception ex)
{
    Console.WriteLine(ex.Message);
}

static async void ThrowExceptionAsync()
{
    await Task.Delay(1000);
    throw new Exception("An error occurred...");
}

L’exécution du code ci-dessus nous montre que les exceptions des méthodes asynchrones retournant void ne sont pas catchés par le try…catch.
Notre code n’affiche jamais le message An error occurred… de notre exception. Ces méthodes gèrent les exceptions de manière différentes. Il est recommandé de préférer les méthodes retournant Task ou Task<T> à celles retournant void.

Les exceptions dans une méthode retournant Task ou Task<T>

Regardons le code suivant:

try
{
    await MyMethod();
}
catch (InvalidOperationException ex)
{
    Console.WriteLine(ex.Message);
}
catch (IndexOutOfRangeException ex)
{
    Console.WriteLine(ex.Message);
}
catch(ArithmeticException ex)
{
    Console.WriteLine(ex.Message);
}

async Task MyMethod()
{
    var firstTask = Task.Run(() => throw new IndexOutOfRangeException("An IndexOutOfRangeException is thrown explicitly."));

    var secondTask = Task.Run(() => throw new InvalidOperationException("An InvalidOperationException is thrown explicitly."));

    var thirdTask = Task.Run(() => throw new ArithmeticException("An ArithmeticException is thrown explicitly."));

    await Task.WhenAll(secondTask, thirdTask, firstTask);
}

A l’exécution, notre code « catche » uniquement la première exception. Il ignore les autres. C’est donc le message « An InvalidOperationException is thrown explicitly » qui s’affichera. Car c’est cette Task qui est la première dans Task.WhenAll(…).

Pour « catcher » toutes les exceptions, notre code doit ressembler à ceci:

async Task MyMethod()
{
    Task tasks = null;

    try
    {
        var firstTask = Task.Run(() => throw new IndexOutOfRangeException("An IndexOutOfRangeException is thrown explicitly."));

        var secondTask = Task.Run(() => throw new InvalidOperationException("An InvalidOperationException is thrown explicitly."));

        var thirdTask = Task.Run(() => throw new ArithmeticException("An ArithmeticException is thrown explicitly."));

        tasks = Task.WhenAll(secondTask, thirdTask, firstTask);

        await tasks;
    }
    catch
    {
        Console.WriteLine("The following exceptions have occurred: ");
        AggregateException allExceptions = tasks.Exception;

        foreach (var ex in allExceptions.InnerExceptions)
        {
            Console.WriteLine(ex.Message);
        }
    }
}

Notre Task tasks contient une propriété Exception de type AggregateException. Ce type possède une propriété InnerExceptions qui est une liste de toutes les exceptions levées durant l’exécution de notre méthode asynchrone. Il suffit donc de la parcourir pour récupérer nos exceptions.

Rien de bien difficile comme vous avez pu le constater. La gestion des exceptions dans les méthodes asynchrones est à la portée de tous.

Photo de Ferenc Almasi sur Unsplash

Auteur : Daniel MINKO FASSINOU

Laisser un commentaire




Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.