I'm using Dapper 1.31 from Nuget. I have this very simple code snippet,
string connString = "";
string query = "";
int val = 0;
CancellationTokenSource tokenSource = new CancellationTokenSource();
using (IDbConnection conn = new SqlConnection(connString))
{
conn.Open();
val = (await conn.QueryAsync<int>(query, tokenSource.Token)).FirstOrDefault();
}
When I press F12 on QueryAsync
, it points me to
public static Task<IEnumerable<T>> QueryAsync<T>
(
this IDbConnection cnn,
string sql,
dynamic param = null,
IDbTransaction transaction = null,
int? commandTimeout = null,
CommandType? commandType = null
);
There is no CancellationToken
on its signature.
Questions:
- Why is the snippet completely buildable assuming that there is no compiler error on the whole solution?
- Forgive me that I cannot test if calling
tokenSource.Cancel()
would really cancel the method because I don't know how to generate a long running sql query. Will the.Cancel()
really cancel the method and throwOperationCancelledException
?
Thank you!
You can fix SqlMapper.cs in Dapper lib by adding these lines:
Rebuild your own Dapper lib and enjoy :)
You are passing the cancellation token as the parameter object; that won't work.
The first async methods in dapper did not expose a cancellation token; when I tried to add them as an optional parameter (as a separate overload, to avoid breaking existing assemblies), things got very confused with "ambiguous method" compilation problems. Consequently, I had to expose this via a separate API; enter
CommandDefinition
:This then passes the cancellation-token down the chain to all the expected places; it is the job of the ADO.NET provider to actually use it, but; it seems to work in most cases. Note that it can result in a
SqlException
rather than anOperationCancelledException
if the operation is in progress; this again is down to the ADO.NET provider, but makes a lot of sense: you could have interrupted something important; it surfaces as a critical connection issue.As for the questions:
Because... it is valid C#, even if it doesn't do what you expect.
ADO.NET provider-specific, but yes it usually works. As an example of "how to generate long running sql query"; the
waitfor delay
command on SQL server is somewhat useful here, and is what I use in the integration tests.I was using one
SqlConnection
for multiple threads. And then when I changed it so that eachThread
created it's ownSqlConnection
the error disappeared.try using a
SqlConnection
and catch the exception on canceland cancel the
SqlCommand