C# SqlClient.SqlCommand.ExecuteScalarAsync的行为类似于同步调用

C# SqlClient.SqlCommand.ExecuteScalarAsync的行为类似于同步调用,c#,asynchronous,async-await,sqlcommand,C#,Asynchronous,Async Await,Sqlcommand,我已经将我的应用程序精简到最小的POC,我仍然得到相同的效果。看来ExecuteScalarAsync的行为就像一个同步调用。我认为当遇到wait时,异步方法中的其余代码将暂停,消息泵返回并从消息队列中获取另一条消息,从而允许UI继续。当标量调用完成时,异步方法的其余部分将放回消息队列中,以便完成 当这个小应用程序运行时,TestConnectionAsync方法将挂起UI,并且在ExecuteScalarAsync调用超时之前不会执行其他消息 我是做错了什么,还是这个异步方法的行为像一个同步方

我已经将我的应用程序精简到最小的POC,我仍然得到相同的效果。看来ExecuteScalarAsync的行为就像一个同步调用。我认为当遇到wait时,异步方法中的其余代码将暂停,消息泵返回并从消息队列中获取另一条消息,从而允许UI继续。当标量调用完成时,异步方法的其余部分将放回消息队列中,以便完成

当这个小应用程序运行时,TestConnectionAsync方法将挂起UI,并且在ExecuteScalarAsync调用超时之前不会执行其他消息

我是做错了什么,还是这个异步方法的行为像一个同步方法

表单有两个按钮。第一个运行异步方法,第二个尝试使用令牌取消异步方法。我从来没有机会点击第二个按钮

表格1.cs

public partial class Form1 : Form
{
    private DB _db = new DB();
    private string _nl = Environment.NewLine;

    public Form1()
    {
        InitializeComponent();
    }

    private async void button1_Click(object sender, EventArgs e)
    {
        textBox1.Text = "Starting" + _nl;
        string resultString
            = (string) await _db.TestConnectionAsync();
        textBox1.AppendText(resultString + _nl);
        textBox1.AppendText("Done" + _nl);
    }

    private void button2_Click(object sender, EventArgs e)
    {
        textBox1.AppendText("Cancelling..." + _nl);
        _db.CancelTest();
        textBox1.AppendText("Submitted Cancel Token" + _nl);
    }
}
DB.cs

致:

但是,当我取消CancellationTokenSource时,ExecuteScalarAsync仍然没有取消。有什么想法吗?

确实是一个异步方法,但是您的UI会停止,因为您没有异步调用这些方法。您可以看到如何更好地处理上的异步方法调用

您还需要异步打开连接,您也发现了这一点。该链接包含打开连接、获取数据和异步取消查询的良好示例

编辑**来自Doug

是的,哈桑是对的。让ExecuteScalarAsync正常工作的问题一直困扰着我,而问题始终是开放的。作为今后的经验法则,我将始终调用如下命令:

                await connection.OpenAsync(_token);
                _command = new SqlCommand(query, connection);
                await _command.ExecuteScalarAsync(_token);
这样,如果存在连接问题,异步和取消行为仍然可以工作


谢谢你,哈桑。

这可能会帮助你朝着正确的方向前进。谢谢你,哈桑。我看了这一页,但它似乎没有回答我的基本问题。ExecuteScalarAsync真的是异步的吗?确实是异步的。我上面提到的链接是为了帮助您处理如何调用异步方法,使它们保持异步。至于方法本身,Hassan,是的,我现在可以看到它确实是异步的。对我来说,还必须通过等待异步打开连接才能使命令工作,这是不直观的。现在我遇到了忽略取消的问题。Hassan,当我将令牌放入OpenAsync和ExecuteScalarAsync中时,它开始工作得很好。这是有道理的,因为超时的是Open,而不是ExecuteScalar。把这个写进一个答案,我会给你一个肯定。
                connection.Open();
                await connection.OpenAsync();
                await connection.OpenAsync(_token);
                _command = new SqlCommand(query, connection);
                await _command.ExecuteScalarAsync(_token);