如何在异步数据库连接期间避免 "Access Violation"?

How do I avoid "Access Violation" during asynchronous database connections?

目标:正确使用 ExecuteAsync。

我知道我的应用程序本身至少非常接近更正,因为它正确执行一次,所以我知道我可以消除防火墙的常见嫌疑,错误的数据库密码,程序名称等

private async Task<T> executeAsyncHelper<T>(Func<IDataReader, T> then)
{
    using (SqlConnection conn = new SqlConnection(connectionString))
    {
        conn.Open();
        using (SqlCommand cmd = new SqlCommand(name, conn))
        {
            parameters.Select(p => cmd.Parameters.Add(p))
                .ToImmutableList(); 
            cmd.CommandType = CommandType.StoredProcedure;
            using (IDataReader rdr = await cmd.ExecuteReaderAsync())
            {
                return then(rdr);
            }
        }
    }
}

问题:第二个 SqlConnection.Open()

上的访问冲突

该方法在同一过程中被调用两次。第一次,它成功地更新了数据库。第二次,整个事情在 conn.Open() 上转储 "Access violation." 重要的是,它没有抛出异常。相反,整个调试器以否定状态代码退出。

这些是调试器输出的最后两行(调试器输出的其余部分看起来很正常):

The program '[6904] dotnet.exe' has exited with code -1073741819 (0xc0000005) 'Access violation'.  
The program '[6904] dotnet.exe: Program Trace' has exited with code 0 (0x0).

此行为是 100% 可重复的。

假设:连接池和异步性

据我所知,最可能的原因是异步打开两个连接存在一些问题,但我不立即知道如何 .我已经尽可能安全地编写了该方法。

其次,我检查了我的 Azure SQL 服务器实例是否有任何异常限制。这是一个基本实例,但我怀疑这是问题所在,因为如果那是问题所在,我希望出现 SQL 异常(调试器将中断并显示正常的堆栈跟踪)。

环境信息

结论

有没有人发现我实施此方法的方式有任何问题,或者有任何建议来了解有关该错误的更多信息?

试试这个:

private async Task<T> executeAsyncHelper<T>(Func<IDataReader, Task<T>> then)
{
    using (SqlConnection conn = new SqlConnection(connectionString))
    {
        conn.Open();
        using (SqlCommand cmd = new SqlCommand(name, conn))
        {
            parameters.Select(p => cmd.Parameters.Add(p))
                .ToImmutableList(); 
            cmd.CommandType = CommandType.StoredProcedure;
            using (IDataReader rdr = await cmd.ExecuteReaderAsync())
            {
                return await then(rdr);
            }
        }
    }
}

注意签名的更改,并等待 return

为了检查您是否没有达到连接限制,您可以执行 exec sp_who2 并查看 sql 服务器上有多少连接。如果 sql 服务器上显示很多连接,则可能是资源问题。你有没有在常规同步中尝试 运行 这段代码,它是否导致了同样的问题?您的连接字符串中是否有任何限制连接数的内容?由于我看不到这段代码的上下文,所以只是抛出了一些理论。

非常有信心我想通了。它实际上与程序死亡的精确行没有任何关系。

相反,该程序在其他线程的其他地方溢出了堆栈。 conn.Open() 是一个转移注意力的问题,尽管那是调试器在失败之前总是指向的地方。我的猜测是 conn.Open() 只是资源密集型,足以将其置于边缘,使其看起来像是造成它的原因。

为了将来的参考,如果您 "Access violation," 重构为同步代码,那么调试器将能够直接通过并实际抛出 WhosebugException 而不是崩溃。