I've stripped my application down to a minimal POC and I'm still getting the same effect. It appears that ExecuteScalarAsync is behaving like a synchronous call. I thought that when the await is encountered the remainder of the code in the async method is paused and the message pump goes back and gets another message from the message queue allowing the UI to continue. When the Scalar call completes, the remainder of the async method is then put back in the message queue so that it will complete.
When this little application runs, the TestConnectionAsync method hangs the UI and no other messages execute until the ExecuteScalarAsync call times out.
Am I doing something wrong, or is this async method behaving like a synchronous method?
The form has two buttons. The first runs the async method and the second tries to cancel the async method with a token. I never get a chance to click the second button.
Form1.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
public class DB
{
private SqlCommand _command = null;
private CancellationTokenSource _tokenSource
= new CancellationTokenSource();
private CancellationToken _token;
public async Task<string> TestConnectionAsync()
{
_token = _tokenSource.Token;
string query = "SELECT COUNT(*) FROM tblDintData";
try
{
using (SqlConnection connection
= new SqlConnection(BuildConnectionString()))
{
connection.Open();
_command = new SqlCommand(query, connection);
await _command.ExecuteScalarAsync(_token);
return "Successful Database Connection";
}
}
catch (Exception ex)
{
return "Connection Failed:"
+ Environment.NewLine + ex.Message;
}
}
public void CancelTest()
{
_tokenSource.Cancel();
}
private string BuildConnectionString()
{
string ret = "";
ret = "Server=NotARealServer;"
+ "Database=NoSuchDatabase;"
+ "Trusted_Connection=True;";
return ret;
}
}
EDIT ***
Ok, I discovered something just by trial-and-error. If I also make the Connection.Open asynchronous by instead calling Connection.OpenAsync then the UI suddenly becomes responsive. This is not intuitive, but this is the line I changed:
from:
connection.Open();
to:
await connection.OpenAsync();
HOWEVER, the ExecuteScalarAsync is still not cancelling when I cancel the CancellationTokenSource. Any ideas???