Estoy tratando de conectarme a una base de datos que se ejecuta en MariaDB usando MySqlConnector . Sin embargo, si ejecuto el fragmento de código básico desde el sitio web especificado, mi programa finaliza tan pronto como se trata de la apertura asincrónica de la conexión de la base de datos (resuelto por depuración). En general, la ventana de la consola solo aparece en la pantalla y luego se cierra inmediatamente.

Instalé MySqlConnector como se describe aquí a través del administrador de paquetes NuGet.

Las versiones síncronas de los métodos asíncronos funcionan sin ningún problema, recibo los datos como se esperaba. Una conexión a otra base de datos tampoco funcionó.

Este es mi programa:

    static void Main(string[] args)
    {                    
        doSomeStuff();            
    }

    public static async void doSomeStuff()
    {
        var connString = "Server=localhost;User ID=root;Password=password;Database=mysql";

        using (var conn = new MySqlConnection(connString))
        {
            await conn.OpenAsync();                

            using (var cmd = new MySqlCommand("SELECT host FROM mysql.user", conn))
            using (var reader = await cmd.ExecuteReaderAsync())
                while (await reader.ReadAsync())
                    Console.WriteLine(reader.GetString(0));
        }


        Console.WriteLine("Finished!");
        Console.ReadKey();
    }      

¿Por qué pasó esto? ¿Hay algo que me falta? ¿Quizás algo relacionado con la configuración en el lado del servidor?

Marco dirigido: .NET Framework 4.7.1 Versión MySqlConnector: 0.53.0 Versión MariaDB: 10.3.14

1
Pete Hilde 10 may. 2019 a las 15:04

3 respuestas

La mejor respuesta

Su problema es que no está esperando la ejecución del método doSomeStuff, por lo que cuando llega a la primera espera, devuelve el control a main y, dado que no queda nada por hacer en main, vuelve a terminar el programa.

Tienes 2 opciones aquí,

  1. Es ejecutar un asíncrono principal en espera de un Task.delay (-1), ejecutar primero el método que tiene, y dado que está esperando una tarea que nunca terminará, hará el trabajo.

  2. Llame a su método de esta manera doSomeStuff (). GetAwaiter (). GetResult (). Esto esperará a que el método ejecute lo que necesita y luego regrese al hilo principal. Para lograr esto, debe cambiar la firma de su método para una tarea asíncrona en lugar de un vacío asíncrono. (La mejor opción si usa versiones anteriores de C #)

  3. Opción 3 (mejor opción si c # 7.1 o más reciente) por MickyD

https://stackoverflow.com/a/56078498/10513564

4
nalnpir 10 may. 2019 a las 17:39

Su mayor problema podría ser el uso del método async void , lo que sucede con los async void es que cuando ocurren errores, su método muere silenciosamente (se bloquea la aplicación según la ubicación) y nunca le dice cuál es el problema,

Unos pocos artículos en la red explican este principio, sobre esto en https : //haacked.com/archive/2014/11/11/async-void-methods/

En C #, los métodos de vacío asíncrono son un flagelo para su código. Para entender por qué, recomiendo este artículo detallado de Stephen Cleary, Mejores prácticas en programación asincrónica. En resumen, las excepciones lanzadas cuando se llama a un método vacío asíncrono no se manejan de la misma manera que en espera de una Tarea y bloquean el proceso. No es una gran experiencia.

Recientemente, encontré otra razón para evitar los métodos de vacío asíncrono. Mientras investigaba un error, noté que la prueba de la unidad que debería haber fallado aparentemente debido al error aprobado con gran éxito. Eso es extraño. No había razón lógica para que la prueba pasara dado el error.

Luego noté que el tipo de retorno del método era nulo asíncrono. En una corazonada lo cambié a Tarea asíncrona y comenzó a fallar. Ohhhhh snap!

Hay algunos otros que puede verificar en la red, los vacíos asíncronos se usan principalmente para eventos, intente cambiar el vacío en una Tarea y aparecerá el error que espera (al menos tendrá un punto de partida para descubrir por qué su la conexión está fallando)

Además, si está ejecutando un asíncrono en uno sincrónico, simplemente haga un Task.Run(() => doSomeStuff()).Result;

Eso obligará a su método a ejecutarse hasta su finalización en un método sincrónico si no tiene acceso a la palabra clave de espera

2
mahlatse 10 may. 2019 a las 12:12

Teniendo en cuenta que está utilizando .NET Framework 4.7.1 , puede considerar forzar C # 7.1 en su proyecto y utilizar async Main(). Conduce a un código mucho más limpio sin ningún GetResult() / Result / Sleep / Task.Delay feo.

E.g.

class Program
{
    // Specify C# 7.1 in the project's Properties.Build.Advanced.Language Version field
    // in order to use 'static async Task Main'
    static async Task Main(string[] args) // <--- Note the async Task
    {
        Console.WriteLine("Sleeping for 3 seconds");

        // the await prevents the app from exiting prematurely
        await Task.Delay(TimeSpan.FromSeconds(3));  
    }
}

Si obtiene un error de compilación, es posible que deba forzar C # 7.1:

enter image description here

Entonces, en su caso, cambie su código a:

static async Task Main(string[] args)
{
    await doSomeStuff();
}

public static async Task doSomeStuff() // <--- make it Task so it can be await'ed
{
    var connString = "Server=localhost;User ID=root;Password=password;Database=mysql";

    using (var conn = new MySqlConnection(connString))
    {
        await conn.OpenAsync();

        using (var cmd = new MySqlCommand("SELECT host FROM mysql.user", conn))
        using (var reader = await cmd.ExecuteReaderAsync())
            while (await reader.ReadAsync())
                Console.WriteLine(reader.GetString(0));
    }


    Console.WriteLine("Finished!");
    Console.ReadKey();
}

Vacío asíncrono

Aunque la advertencia de mahlatse sobre async void tiene merrit, no se aplica a su problema específico por el cual la aplicación se cierra prematuramente debido a que no espera tareas completar en lugar de que una aplicación se cierre prematuramente debido a que se ha lanzado una excepción desde un método async void . Asumiendo que la única diferencia entre su código síncrono y el código asíncrono es el async y no decir las conexiones de la base de datos, su código debería no estar fallando.

2
MickyD 10 may. 2019 a las 13:28