Почему моя программа прерывается при вызове "OpenAsync ()"? - PullRequest
1 голос
/ 10 мая 2019

Я пытаюсь подключиться к базе данных, которая работает на MariaDB, используя MySqlConnector .Однако, если я выполняю фрагмент кода с указанного веб-сайта, моя программа завершает работу, как только происходит асинхронное открытие соединения с базой данных (выясняется при отладке).В общем, окно консоли просто появляется на экране, а затем сразу же снова закрывается.

Я установил MySqlConnector, как описано здесь через менеджер пакетов NuGet.

СинхронныйВерсии асинхронных методов работают без проблем, я получаю данные, как и ожидалось.Соединение с другой базой данных также не работает.

Это моя программа:

    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();
    }      

Почему это происходит?Я что-то пропустил?Возможно, что-то касается конфигурации на стороне сервера?

Targeted Framework: .NET Framework 4.7.1 Версия MySqlConnector: 0.53.0 Версия MariaDB: 10.3.14

Ответы [ 3 ]

4 голосов
/ 10 мая 2019

Ваша проблема в том, что вы не ожидаете выполнения метода doSomeStuff, поэтому, когда он прибывает в первое ожидание, он возвращает элемент управления в main, и, так как в main ничего не остается, он возвращает окончание программы.

У вас есть 2 варианта здесь,

  1. Запускает основной асинхронный режим в ожидании Task.delay (-1), сначала выполняет метод, который у вас есть, и, поскольку вы ожидаете задачу, которая никогда не закончится, вы получите работу.

  2. Вызовите ваш метод следующим образом doSomeStuff (). GetAwaiter (). GetResult (). Это будет ждать, пока метод выполнит то, что ему нужно, а затем вернется в основной поток. Чтобы добиться этого, вы должны изменить сигнатуру вашего метода для асинхронной задачи вместо асинхронной пустоты. (Лучший вариант при использовании более старых версий c #)

  3. Вариант 3 (лучший вариант, если c # 7.1 или новее) от MickyD

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

2 голосов
/ 10 мая 2019

Учитывая, что вы используете .NET Framework 4.7.1 , вы, возможно, захотите использовать C # 7.1 в своем проекте и использовать async Main().Это приводит к значительному чистому коду без каких-либо уродливых GetResult() / Result / Sleep / Task.Delay.

например

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));  
    }
}

Если вы получитеошибка компиляции, вам может потребоваться принудительное использование C # 7.1:

enter image description here

Итак, в вашем случае измените код на:

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();
}

async void

Хотя предупреждение Махлатсе о async void имеет преимущество, оно не относится к вашей конкретной проблеме, из-за которой приложение преждевременно закрывается из-за не ожидает выполнения задач , в отличие от приложения, преждевременно завершающего работу из-за , исключение выдается из async void метода .Предполагая, что единственное различие между вашим синхронным кодом и асинхронным кодом заключается в async, а не в соединениях с базой данных, ваш код должен не быть ошибочным.

2 голосов
/ 10 мая 2019

Самой большой проблемой может быть использование метода async void . Что происходит с асинхронными пустотами, так это то, что при возникновении ошибок ваш метод молча умирает (происходит сбой приложения в зависимости от местоположения) и никогда не сообщает вам, в чем проблема

Несколько статей в сети объясняют этот принцип, например, в https://haacked.com/archive/2014/11/11/async-void-methods/

В C # асинхронные пустые методы являются бичом для вашего кода. Чтобы понять почему, я рекомендую эту подробную статью Стивена Клири, Best Practices в асинхронном программировании. Короче, исключения, возникающие при вызове асинхронный метод void не обрабатывается так же, как ожидание задачи и остановит процесс. Не большой опыт.

Недавно я нашел другую причину избегать асинхронных пустых методов. В то время как исследуя ошибку, я заметил, что модульный тест, который должен иметь якобы потерпел неудачу из-за ошибки, переданной с летающими цветами. Это странный. Не было логической причины для прохождения теста с учетом ошибки.

Затем я заметил, что тип возвращаемого значения метода был асинхронным void. На догадка Я изменил его на асинхронную задачу, и он начал терпеть неудачу. Оххххххххххххххх!

Есть несколько других, которые вы можете проверить в сети, асинхронные пустоты в основном используются для событий, попробуйте изменить пустоту в Задачу, и вы увидите ожидаемую ошибку (по крайней мере, у вас будет начальная точка для расчета почему ваше соединение не работает)

Также, если вы запускаете асинхронный в синхронном режиме, просто выполните Task.Run(() => doSomeStuff()).Result;

Это заставит ваш метод работать до завершения синхронным методом, если у вас нет доступа к ключевому слову await

...