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
3 respuestas
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í,
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.
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 #)
Opción 3 (mejor opción si c # 7.1 o más reciente) por MickyD
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
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:
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.
Preguntas relacionadas
Nuevas preguntas
c#
C # (pronunciado "see sharp") es un lenguaje de programación multi-paradigma de alto nivel, estáticamente tipado desarrollado por Microsoft. El código C # generalmente se dirige a la familia de herramientas y tiempos de ejecución .NET de Microsoft, que incluyen .NET Framework, .NET Core y Xamarin, entre otros. Use esta etiqueta para preguntas sobre el código escrito en las especificaciones formales de C # o C #.