CodeGym /Cursos /C# SELF /Gestión de errores en operaciones asíncronas ( async/ awa...

Gestión de errores en operaciones asíncronas ( async/ await)

C# SELF
Nivel 42, Lección 3
Disponible

1. Introducción

Empezamos con una pregunta importante: ¿por qué no puedes simplemente confiar en los métodos asíncronos y esperar que todo siempre funcione bien? Las operaciones con archivos a menudo lanzan excepciones: el archivo pudo haber sido eliminado, se acabó la memoria, faltan permisos o el archivo está bloqueado. En código síncrono atraparías los problemas con el habitual bloque try-catch. En código asíncrono la filosofía es la misma, pero hay matices: el error puede ocurrir no inmediatamente al llamar al método, sino más tarde, cuando la operación realmente se ejecuta.

Momento de aparición del error

En código síncrono al leer con StreamReader.Read() la excepción saltará directamente en la línea de la llamada — la atrapas en el catch, y todo bien.
En código asíncrono (await stream.ReadAsync()) el error caerá no al iniciar la operación, sino precisamente en el await — cuando la tarea finalice con error. Si olvidas poner await, el error puede quedarse "invisible" por un tiempo.

2. Cómo atrapar excepciones en métodos asíncronos

Veamos de inmediato un patrón típico:


try
{
    using FileStream fs = new FileStream("myfile.txt", FileMode.Open);
    byte[] buffer = new byte[1024];
    int bytesRead = await fs.ReadAsync(buffer, 0, buffer.Length);
    // Procesamiento posterior...
}
catch (IOException ex)
{
    Console.WriteLine("Error de entrada/salida: " + ex.Message);
}
catch (UnauthorizedAccessException ex)
{
    Console.WriteLine("Sin acceso al archivo: " + ex.Message);
}
catch (Exception ex)
{
    Console.WriteLine("Error desconocido: " + ex);
}

Sí, sí, todo simple — usamos el conocido try-catch, pero en un método asíncrono. Es importante que el propio método tenga la palabra clave async, si no el compilador se quejará.

Matiz importante: dónde poner el await


Task<int> readTask = fs.ReadAsync(buffer, 0, buffer.Length);
// ... aquí accidentalmente olvidamos await o el manejo

En ese caso, el error, si ocurre, irá a la propia tarea (Task), y no te enterarás hasta que intentes obtener el resultado — por ejemplo, con await readTask o con la propiedad Task.Exception. Si directamente olvidaste el await, la tarea puede terminar con error y nadie te lo dirá.

3. Por qué el código asíncrono es traicionero sin manejo de errores

Escenario 1: «Fire and forget» — trampa para novatos


FileStream fs = new FileStream("file.txt", FileMode.Open);
byte[] buffer = new byte[8000];
fs.ReadAsync(buffer, 0, buffer.Length);
// Y luego el programa sigue su vida

La operación de lectura se lanza a "nadar por separado", y si termina con error, ningún catch lo atrapará. La excepción se ocultará dentro de la tarea. Este patrón se llama "fire and forget" y en aplicaciones reales trae pérdida de errores críticos y fugas de recursos.

Escenario 2: Métodos asíncronos sin await


Task t = MyAsyncMethod();
// ... aquí hacemos algo, y luego nos olvidamos de t

Los errores que ocurran dentro de MyAsyncMethod no se propagarán hasta que esperes explícitamente la tarea (await t o t.Wait()).

4. Cómo manejar correctamente errores de tareas asíncronas

Estrategia 1: Siempre usa await


try
{
    await SomeFileOperationAsync();
}
catch (Exception ex)
{
    Console.WriteLine("Algo salió mal: " + ex.Message);
}

Así la excepción será lanzada justo en el punto de espera y no se perderá.

Estrategia 2: Manejo con .ContinueWith

Si por alguna razón no usas await, puedes añadir un manejador de errores con ContinueWith:


var task = fs.ReadAsync(buffer, 0, buffer.Length);
task.ContinueWith(t =>
{
    if (t.Exception != null)
        Console.WriteLine("Error al leer asíncronamente: " + t.Exception.InnerException);
}, TaskContinuationOptions.OnlyOnFaulted);

¿La verdad? En aplicaciones C# modernas esto se usa raramente — async/await hace el código más simple y limpio.

Posibles excepciones al trabajar con archivos asíncronamente

5. Ejemplo: Lectura asíncrona con manejo de errores

Añadamos esta lógica a nuestra aplicación:


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($"Leídos {bytesRead} bytes de {path}");
            }
            catch (FileNotFoundException ex)
            {
                Console.WriteLine("Archivo no encontrado: " + ex.Message);
            }
            catch (UnauthorizedAccessException ex)
            {
                Console.WriteLine("Sin acceso al archivo: " + ex.Message);
            }
            catch (IOException ex)
            {
                Console.WriteLine("Error de lectura/escritura: " + ex.Message);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Otro error: " + ex.Message);
            }
        }
    }
}

Nota importante

Si no usas await en Main, y solo haces Task result = SomeAsyncMethod(); — los errores "callarán" y se manifestarán más tarde, cuando finalmente intentes obtener el resultado.

6. Errores más frecuentes y "rastrillos" al manejar errores

Olvidar poner await en un método asíncrono — las excepciones no emergen a tiempo, el programa se comporta de forma impredecible.

No envolver las llamadas asíncronas en try-catch — la aplicación cae en el primer fallo.

Capturar solo Exception, ignorando excepciones específicas como UnauthorizedAccessException o OperationCanceledException — resulta en mala diagnóstica.

Usar tareas "fire and forget" sin logging explícito de errores — las excepciones se pierden dentro de la Task.

Creer que si la tarea terminó entonces todo fue bien. Hay que esperar explícitamente el resultado (await) y manejar las excepciones.

2
Tarea
C# SELF, nivel 42, lección 3
Bloqueada
Manejo de errores al leer un archivo
Manejo de errores al leer un archivo
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION