SqlConnection.OpenAsync() 在不抛出异常的情况下退出

6

我有以下代码。调用connection.OpenAsync()时程序会退出而没有任何异常。甚至调用者方法上的finally也不会被调用。该程序针对的是.NET45,有什么想法吗?

更新:这里是父代码,使用.Wait()可以正常工作。当在下面的子方法中调用connection.OpenAsync()时,没有使用.Wait()时程序会退出。

        static void Main(string[] args)
        {
            UpdateSqlDatabase updateSqlDatabase = new UpdateSqlDatabase(args);
            updateSqlDatabase.UpdateDatabaseSchemaAsync().Wait();
        }

经过一系列异步方法调用后:

    public async Task<T> ExecuteQueryAsync<T>(string connectionString, string commandText, IDictionary<string, object> parameters, Func<SqlDataReader, T> rowMapFunc)
    {
        using (var connection = new SqlConnection(connectionString))
        {
            try
            {
                await connection.OpenAsync();
            }
            catch (Exception ex)
            {
            }

            SqlCommand command = connection.CreateCommand();
            command.CommandType = CommandType.Text;
            command.CommandText = commandText;
            if (parameters != null)
            {
                foreach (var item in parameters)
                {
                    command.Parameters.AddWithValue(item.Key, item.Value);
                }
            }

            SqlDataReader reader = await command.ExecuteReaderAsync();
            T retObj = default(T);

            while (await reader.ReadAsync())
            {
                retObj = rowMapFunc(reader);
            }

            return retObj;
        }
    }

不要这样做:catch (Exception) {},你会自食其果的。毕竟异常详情是什么? - noseratio - open to work
当我调试代码时,它从来没有到达过。我添加了那个 catch 语句来查看哪里出了问题(不会成为我的代码的一部分)。基本上,当我调试时,在执行 connection.OpenAsync() 时程序就直接退出了。也就是说,控制台应用程序在没有任何错误/异常的情况下就退出了。在这段代码中,catch 块从未被触发。 - ksj
将您的代码更改为以下内容:http://pastebin.com/ZmsA3k4g。在“A”、“B”、“C”、“D”行上设置断点并在调试器下运行。哪些断点被触发? - noseratio - open to work
A和B被击中了。C和D没有。 - ksj
然后按照@JAnderson的建议检查Windows事件日志。 - noseratio - open to work
3个回答

4

问题在于我的代码中有一系列异步调用,但父方法(主方法)不是异步的,也没有使用await,导致程序在其中一个子方法调用异步时退出。我在主方法(同步方法)中对异步方法的调用添加了.Wait(),然后它就正常工作了。

谢谢!


1
在异步链的根部使用.Wait()几乎从来不是正确的做法,而且经常会导致程序陷入死锁!要么你应该编写没有任何异步的代码,要么调用Wait()的函数应该是异步的,并且应该使用await等待任务完成,而不是使用.Wait()。如果可以的话,请更新您的问题并显示您添加了.Wait()的初始函数,我们可以帮助您找出哪个选项是正确的。 - Scott Chamberlain
好的,从您添加的代码来看,您是站在“不使用异步”这一边的。您正在使用控制台应用程序,没有理由使用异步代码。它只会增加开销并减慢您的代码速度。请查看是否有updateSqlDatabase.UpdateDatabaseSchema()函数的版本,您应该在您的情况下使用它。 - Scott Chamberlain
我已经在原始帖子中添加了代码。感谢您的帮助。 - ksj
1
异步代码只有在等待期间有其他工作要做时才有用。在 UI 应用程序中,它可以让 UI 回到处理新的鼠标点击和重新绘制屏幕,对于 ASP.NET 程序,它会将线程返回到线程池,以便更多请求可以进来。在像您这样的控制台应用程序中,没有其他工作“等待完成”,因此只需同步运行代码,不要为执行异步操作而付出额外的开销。 - Scott Chamberlain
我刚刚打了一些快速测试,忘记使用await调用我的异步业务层,结果出现了相同的行为。这是一个快速提醒,谢谢。 - Evan Morrison

3
msdn文档表示:

如果连接超时而未能成功连接,则异常将通过返回的Task传播。实现会返回一个Task,而不会阻塞调用线程,无论是池化还是非池化连接。

因此,正确使用connection.OpenAsync()应该如下所示:

using(var connection = new SqlConnection(connectionString))
{
    var connectionTask = connection.OpenAsync();
    // other code goes here
    Task.WaitAll(connectionTask); //make sure the task is completed
    if(connectionTask.IsFaulted) // in case of failure
    {
       throw new Exception("Connection failure", connectionTask.Exception);
    }
    // rest of the code
 }

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接