为什么我的程序在调用 "OpenAsync()" 时终止?

Why is my program terminated when calling "OpenAsync()"?

我正在尝试使用 MySqlConnector 连接到 MariaDB 上 运行 的数据库。但是,如果我从指定网站执行基本代码片段,我的程序会在异步打开数据库连接时立即终止(通过调试发现)。通常,控制台 window 只是在屏幕上弹出然后立即再次关闭。

我通过 NuGet 包管理器 here 安装了 MySqlConnector。

异步方法的同步版本没有任何问题,我收到了预期的数据。与另一个数据库的连接也不起作用。

这是我的程序:

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

为什么会这样?有什么我想念的吗?也许与服务器端的配置有关?

目标框架:.NET Framework 4.7.1 MySqlConnector 版本:0.53.0 MariaDB 版本:10.3.14

你的问题是你没有等待方法doSomeStuff的执行,所以当它到达第一个await时,它returns控制到main,并且由于有main 中无事可做 return 程序结束。

这里有 2 个选项,

  1. 是给运行一个主异步等待一个Task.delay(-1),先执行你有的方法,因为你在等待一个永远不会结束的任务你会完成任务的。

  2. 像这样调用您的方法 doSomeStuff().GetAwaiter().GetResult() 。这将等待该方法执行它需要执行的操作,然后 return 到主线程。为了实现这一点,您应该为异步任务而不是异步无效更改方法的签名。 (如果使用旧的 c# 版本,最好的选择)

  3. MickyD

  4. 的选项 3(如果是 c# 7.1 或更新版本则为最佳选项)

你最大的问题可能是使用 async void 方法,async voids 发生的事情是当错误发生时,你的方法静静地死去(根据位置崩溃应用程序)并且永远不会告诉你问题是什么,

网上有几篇文章解释了这个原理,在https://haacked.com/archive/2014/11/11/async-void-methods/

In C#, async void methods are a scourge upon your code. To understand why, I recommend this detailed Stephen Cleary article, Best Practices in Asynchronous Programming. In short, exceptions thrown when calling an async void method isn’t handled the same way as awaiting a Task and will crash the process. Not a great experience.

Recently, I found another reason to avoid async void methods. While investigating a bug, I noticed that the unit test that should have ostensibly failed because of the bug passed with flying colors. That’s odd. There was no logical reason for the test to pass given the bug.

Then I noticed that the return type of the method was async void. On a hunch I changed it to async Task and it started to fail. Ohhhhh snap!

还有一些其他的你可以在网上查看,async voids 主要用于事件,尝试将 void 更改为 Task 并且你期望的错误会弹出(至少你会有一个起点找出连接失败的原因)

此外,如果您 运行 是同步中的异步,那么只需执行 Task.Run(() => doSomeStuff()).Result;

如果您无权访问 await 关键字,这将强制您的方法 运行 在同步方法中完成

考虑到您正在使用 .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:

因此,在您的情况下,将您的代码更改为:

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

异步无效

虽然 mahlatse 的 关于 async void 的警告有好处,但它不适用于 应用程序过早退出的特定问题 由于 没有等待任务完成 而不是由于 async void 方法 抛出异常而导致应用程序过早退出].假设您的同步代码和异步代码之间的唯一区别是 async 而不是说数据库连接,您的代码应该 而不是 出错。