CancellationToken с асинхронными методами Dapper?
Я использую Dapper 1.31 от Nuget. У меня есть этот очень простой фрагмент кода,
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();
}
Когда я нажимаю F12 на QueryAsync
, он указывает мне на
public static Task<IEnumerable<T>> QueryAsync<T>
(
this IDbConnection cnn,
string sql,
dynamic param = null,
IDbTransaction transaction = null,
int? commandTimeout = null,
CommandType? commandType = null
);
В его сигнатуре нет CancellationToken
.
Вопросы:
- Почему весь фрагмент полностью строится, предполагая, что ошибка компилятора на всем решении отсутствует?
- Простите меня, поскольку я не могу проверить, действительно ли вызов
tokenSource.Cancel()
действительно отменяет этот метод, потому что я не знаю, как создать длинный SQL-запрос. Будет ли .Cancel()
действительно отменять метод и выбрасывает OperationCancelledException
?
Спасибо!
Ответы
Ответ 1
Вы передаете токен отмены в качестве объекта параметра; это не сработает.
Первые асинхронные методы в dapper не отображали токен отмены; когда я пытался добавить их в качестве необязательного параметра (в качестве отдельной перегрузки, чтобы не нарушать существующие сборки), вещи очень запутались в проблемах компиляции "двусмысленного метода" . Следовательно, мне пришлось разоблачить это через отдельный API; введите CommandDefinition
:
val = (await conn.QueryAsync<int>(
new CommandDefinition(query, cancellationToken: tokenSource.Token)
).FirstOrDefault();
Затем он передает токен отмены по цепочке ко всем ожидаемым местам; это задача поставщика ADO.NET, чтобы использовать его, но; он работает в большинстве случаев. Обратите внимание, что это может привести к SqlException
, а не к OperationCancelledException
, если операция выполняется; это снова относится к провайдеру ADO.NET, но имеет большой смысл: вы могли бы прервать что-то важное; он возникает как критическая проблема подключения.
Что касается вопросов:
Почему весь фрагмент полностью строится, предполагая, что ошибка компилятора для всего решения отсутствует?
Потому что... это действительно С#, даже если он не делает то, что вы ожидаете.
Простите меня, поскольку я не могу проверить, вызывает ли вызов tokenSource.Cancel() действительно отмену метод, потому что я не знаю, как генерировать длинный SQL-запрос. Удалит ли .Cancel() этот метод и выбрасывает OperationCancelledException?
Спецификатор ADO.NET, но он обычно работает. В качестве примера "как создать длинный SQL-запрос"; команда waitfor delay
на сервере SQL здесь несколько полезна, и это то, что я использую в тестах интеграции.
Ответ 2
Вы можете исправить SqlMapper.cs в Dapper lib добавив следующие строки:
internal IDbCommand SetupCommand(IDbConnection cnn, Action<IDbCommand, object> paramReader)
{
var cmd = cnn.CreateCommand();
#if ASYNC
// We will cancel our IDbCommand
CancellationToken.Register(() => cmd.Cancel());
#endif
Восстановите свой собственный Dapper lib и наслаждайтесь:)
Ответ 3
попробуйте использовать SqlConnection
и поймать исключение при отмене
var sqlConn = db.Database.Connection as SqlConnection;
sqlConn.Open();
_cmd = new SqlCommand(textCommand, sqlConn);
_cmd.ExecuteNonQuery();
и отмените SqlCommand
_cmd.Cancel();
Ответ 4
Я использовал один SqlConnection
для нескольких потоков. И затем, когда я изменил его так, чтобы каждый Thread
создал свой собственный SqlConnection
ошибка исчезла.