CodeGym /Cours /C# SELF /Gestion des erreurs dans les opérations asynchrones ( asy...

Gestion des erreurs dans les opérations asynchrones ( async/ await)

C# SELF
Niveau 42, Leçon 3
Disponible

1. Introduction

Commençons par une question importante : pourquoi ne peut-on pas simplement faire confiance aux méthodes asynchrones et espérer que tout fonctionnera toujours parfaitement ? Les opérations sur fichiers lèvent souvent des exceptions — le fichier peut avoir été supprimé, la mémoire peut manquer, il peut manquer des permissions ou le fichier peut être verrouillé. Dans du code synchrone vous attraperiez les problèmes avec le traditionnel bloc try-catch. Dans le code asynchrone la philosophie est la même, mais il y a des nuances : l'erreur peut se produire pas tout de suite lors de l'appel de la méthode, mais plus tard, quand l'opération est réellement exécutée.

Moment d'apparition de l'erreur

Dans le code synchrone en lisant via StreamReader.Read() l'exception sautera directement à la ligne d'appel — vous la prenez dans le catch, et voilà.
Dans le code asynchrone (await stream.ReadAsync()) l'erreur tombera non pas au démarrage de l'opération, mais directement au moment du await — quand la Task se termine avec une erreur. Si vous oubliez de mettre await, l'erreur peut rester «invisible» jusqu'à un certain temps.

2. Comment attraper les exceptions dans les méthodes asynchrones

Regardons tout de suite le modèle typique :


try
{
    using FileStream fs = new FileStream("myfile.txt", FileMode.Open);
    byte[] buffer = new byte[1024];
    int bytesRead = await fs.ReadAsync(buffer, 0, buffer.Length);
    // Traitement ultérieur...
}
catch (IOException ex)
{
    Console.WriteLine("Erreur d'entrée-sortie : " + ex.Message);
}
catch (UnauthorizedAccessException ex)
{
    Console.WriteLine("Accès au fichier refusé : " + ex.Message);
}
catch (Exception ex)
{
    Console.WriteLine("Erreur inconnue : " + ex);
}

Oui-oui, c'est simple — on utilise le familier try-catch, mais dans une méthode asynchrone. Il est important que la méthode elle-même soit marquée par le mot-clé async, sinon le compilateur râlera.

Nuance importante : où placer le await


Task<int> readTask = fs.ReadAsync(buffer, 0, buffer.Length);
// ... ici on a accidentellement oublié await ou le traitement

Dans ce cas l'erreur, si elle survient, ira dans la Task elle-même (Task), et vous ne la connaîtrez pas tant que vous n'essayerez pas d'obtenir le résultat — par exemple via await readTask ou via la propriété Task.Exception. Si vous avez complètement oublié le await — la tâche peut se terminer avec une erreur et personne ne vous le dira.

3. Pourquoi le code asynchrone est sournois sans gestion des erreurs

Scénario 1 : «Fire and forget» — le piège du débutant


FileStream fs = new FileStream("file.txt", FileMode.Open);
byte[] buffer = new byte[8000];
fs.ReadAsync(buffer, 0, buffer.Length);
// Et ensuite le programme vit sa vie

L'opération de lecture part en «voyage parallèle», et si elle se termine par une erreur, aucun catch ne l'attrapera. L'exception sera cachée à l'intérieur de la Task. Ce pattern s'appelle «fire and forget» et dans les applications réelles il peut causer la perte d'erreurs critiques et des fuites de ressources.

Scénario 2 : Méthodes asynchrones sans await


Task t = MyAsyncMethod();
// ... ici on fait quelque chose, puis on oublie t

Les erreurs qui surviennent à l'intérieur de MyAsyncMethod ne remonteront pas tant que vous n'attendrez pas explicitement la tâche (await t ou t.Wait()).

4. Comment correctement attraper les erreurs provenant des tasks asynchrones

Stratégie 1 : Utilisez toujours await


try
{
    await SomeFileOperationAsync();
}
catch (Exception ex)
{
    Console.WriteLine("Quelque chose s'est mal passé : " + ex.Message);
}

Ainsi l'exception sera lancée directement à l'endroit de l'attente et ne se perdra pas.

Stratégie 2 : Gestion via .ContinueWith

Si pour une raison quelconque vous n'utilisez pas await, vous pouvez ajouter un gestionnaire d'erreurs via ContinueWith :


var task = fs.ReadAsync(buffer, 0, buffer.Length);
task.ContinueWith(t =>
{
    if (t.Exception != null)
        Console.WriteLine("Erreur lors de la lecture asynchrone : " + t.Exception.InnerException);
}, TaskContinuationOptions.OnlyOnFaulted);

Honnêtement ? Dans les applications C# modernes on fait rarement comme ça — async/await rend le code plus simple et plus propre.

Exceptions possibles lors du travail asynchrone avec des fichiers

5. Exemple : Lecture asynchrone avec gestion des erreurs

Ajoutons cette logique dans notre application :


using System;
using System.IO;
using System.Threading.Tasks;

namespace FileAsyncDemo
{
    class Program
    {
        static async Task Main()
        {
            string path = "bigfile.txt";
            byte[] buffer = new byte[4096];

            try
            {
                using FileStream fs = new FileStream(path, FileMode.Open);
                int bytesRead = await fs.ReadAsync(buffer, 0, buffer.Length);
                Console.WriteLine($"Lu {bytesRead} octets depuis {path}");
            }
            catch (FileNotFoundException ex)
            {
                Console.WriteLine("Fichier introuvable : " + ex.Message);
            }
            catch (UnauthorizedAccessException ex)
            {
                Console.WriteLine("Accès au fichier refusé : " + ex.Message);
            }
            catch (IOException ex)
            {
                Console.WriteLine("Erreur de lecture/écriture : " + ex.Message);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Autre erreur : " + ex.Message);
            }
        }
    }
}

Remarque importante

Si vous n'utilisez pas await dans Main, et que vous faites seulement Task result = SomeAsyncMethod(); — les erreurs resteront «silencieuses» et se manifesteront plus tard, quand vous essayerez finalement d'obtenir le résultat.

6. Erreurs les plus fréquentes et pièges lors de la gestion des erreurs

On oublie de mettre await sur une méthode asynchrone — les erreurs ne remontent pas à temps, le programme se comporte de manière imprévisible.

On n'entoure pas les appels asynchrones d'un try-catch — l'application plante au premier échec.

On ne traite que Exception, en ignorant des exceptions spécifiques comme UnauthorizedAccessException ou OperationCanceledException — au final le diagnostic est mauvais.

On utilise des tâches «fire and forget» sans journaliser explicitement les erreurs — les exceptions se perdent à l'intérieur de la Task.

On considère que si la tâche est terminée — tout s'est bien passé. Il faut explicitement attendre le résultat (await) et gérer les exceptions.

2
Mission
C# SELF, niveau 42, leçon 3
Bloqué
Gestion des erreurs lors de la lecture d'un fichier
Gestion des erreurs lors de la lecture d'un fichier
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION