У меня есть долго работающая хранимая процедура в SQL Server, которую мои пользователи должны иметь возможность отменить. Я написал небольшое тестовое приложение, как показано ниже, которое демонстрирует, что метод SqlCommand.Cancel()
работает довольно хорошо:
private SqlCommand cmd;
private void TestSqlServerCancelSprocExecution()
{
TaskFactory f = new TaskFactory();
f.StartNew(() =>
{
using (SqlConnection conn = new SqlConnection("connStr"))
{
conn.InfoMessage += conn_InfoMessage;
conn.FireInfoMessageEventOnUserErrors = true;
conn.Open();
cmd = conn.CreateCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "dbo.[CancelSprocTest]";
cmd.ExecuteNonQuery();
}
});
}
private void cancelButton_Click(object sender, EventArgs e)
{
if (cmd != null)
{
cmd.Cancel();
}
}
После вызова cmd.Cancel()
я могу убедиться, что базовая хранимая процедура прекращает выполнение практически сразу. Учитывая, что я довольно часто использую шаблон async / await в своем приложении, я надеялся, что методы async на SqlCommand
, которые принимают параметры CancellationToken
, будут работать одинаково хорошо. К сожалению, я обнаружил, что вызов Cancel()
на CancellationToken
приводит к тому, что обработчик событий InfoMessage
больше не вызывается, но базовая хранимая процедура продолжает выполняться. Мой тестовый код для асинхронной версии выглядит следующим образом:
private SqlCommand cmd;
private CancellationTokenSource cts;
private async void TestSqlServerCancelSprocExecution()
{
cts = new CancellationTokenSource();
using (SqlConnection conn = new SqlConnection("connStr"))
{
conn.InfoMessage += conn_InfoMessage;
conn.FireInfoMessageEventOnUserErrors = true;
conn.Open();
cmd = conn.CreateCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "dbo.[CancelSprocTest]";
await cmd.ExecuteNonQueryAsync(cts.Token);
}
}
private void cancelButton_Click(object sender, EventArgs e)
{
cts.Cancel();
}
Я что-то упустил в том, как CancellationToken
должен работать? Я использую .NET 4.5.1 и SQL Server 2012, если это имеет значение.
РЕДАКТИРОВАТЬ: я переписал тестовое приложение как консольное приложение на случай, если контекст синхронизации был фактором, и я вижу такое же поведение - вызов CancellationTokenSource.Cancel()
не останавливает выполнение базовой хранимой процедуры.
РЕДАКТИРОВАТЬ: вот тело хранимой процедуры, которую я вызываю, если это имеет значение. Он вставляет записи и распечатывает результаты с интервалом в одну секунду, чтобы можно было легко увидеть, были ли попытки отмены вступили в силу незамедлительно.
WHILE (@loop <= 40)
BEGIN
DECLARE @msg AS VARCHAR(80) = 'Iteration ' + CONVERT(VARCHAR(15), @loop);
RAISERROR (@msg,0,1) WITH NOWAIT;
INSERT INTO foo VALUES (@loop);
WAITFOR DELAY '00:00:01.01';
SET @loop = @loop+1;
END;
cmd.Cancel
. Можете указать мне, где вы это читаете? Вы видели msdn.microsoft.com/en-us/library/hh211418.aspx? - person John Saunders   schedule 19.07.2014