简体   繁体   English

C#:使用 CancellationToken 取消 MySqlCommand 给出 NULLReferenceException

[英]C# : Cancelling MySqlCommand using CancellationToken giving NULLReferenceException

I was trying to cancel a MySqlCommand using a CancellationToken .我试图使用CancellationToken取消MySqlCommand The query executes successfully when cancellation is not requested.当未请求取消时,查询成功执行。

public async Task<int> ExecuteNonQueryAsync(string connectionString, string query, 
       CancellationToken cancellationToken)
{
    int affectedRowsCount = 0;
    await Task.Run(() =>
    {
        using (MySqlConnection connection = new MySqlConnection(connectionString))
        {
            using (MySqlCommand command = new MySqlCommand())
            {
                connection.Open();
                command.Connection = connection;
                cancellationToken.Register(() => command.Cancel());

                command.CommandText = query;
                command.CommandTimeout = 0;

                affectedRowsCount = command.ExecuteNonQuery();
                connection.Close();
             }
         }
     });

     return affectedRowsCount;
}

But when cancellation is requested it is producing NullReferenceException.但是当请求取消时,它会产生 NullReferenceException。 Can't figure out what is NULL.无法弄清楚什么是NULL。

在此处输入图片说明

I am calling the above method by我通过调用上述方法

deletedRowsInLastIteration = await 
    mySqlHelperService.ExecuteNonQueryAsync(
       connectionString,
       query, 
       cancellationToken);

if I try如果我尝试

cancellationToken.ThrowIfCancellationRequested();

before calling the ExecuteNonQueryAsync() method, it works.在调用ExecuteNonQueryAsync()方法之前,它可以工作。 But the cancel of MySqlCommand is not working.但是取消 MySqlCommand 不起作用。

This is the stack trace这是堆栈跟踪

System.NullReferenceException HResult=0x80004003 Message=Object reference not set to an instance of an object. System.NullReferenceException HResult=0x80004003 消息=未将对象引用设置为对象的实例。 Source=MySql.Data源=MySql.Data
StackTrace: at MySql.Data.MySqlClient.MySqlConnection.CancelQuery(Int32 timeout) StackTrace:在 MySql.Data.MySqlClient.MySqlConnection.CancelQuery(Int32 超时)
at MySql.Data.MySqlClient.MySqlCommand.Cancel() at ProjectName.Common.MySqlHelperService.<>c__DisplayClass1_1.b__1() in C:\\Users\\username\\source\\repos\\ProjectName\\Applications\\ProjectName.Common\\MySqlHelperService.cs:line 55 at System.Threading.CancellationToken.ActionToActionObjShunt(Object obj) at System.Threading.CancellationCallbackInfo.ExecutionContextCallback(Object obj) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.CancellationCallbackInfo.ExecuteCallback() at System.Threading.CancellationTokenSource.CancellationCallbackCoreWork(CancellationCallbackCoreWorkArguments args) at System.Threading.CancellationTo在 MySql.Data.MySqlClient.MySqlCommand.Cancel() 在 ProjectName.Common.MySqlHelperService.<>c__DisplayClass1_1.b__1() 在 C:\\Users\\username\\source\\repos\\ProjectName\\Applications\\ProjectName.Common\\MySqlHelperService.cs:第 55 行在 System.Threading.CancellationToken.ActionToActionObjShunt(Object obj) at System.Threading.CancellationCallbackInfo.ExecutionContextCallback(Object obj) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System。 Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.CancellationCallbackInfo.ExecuteCallback() at System.Threading .CancellationTokenSource.CancellationCallbackCoreWork(CancellationCallbackCoreWorkArguments args) 在 System.Threading.CancellationTo kenSource.ExecuteCallbackHandlers(Boolean throwOnFirstException) kenSource.ExecuteCallbackHandlers(Boolean throwOnFirstException)

You shouldn't use Task.Run to convert synchronous methods to asynchronous ones.您不应该使用Task.Run将同步方法转换为异步方法。 At best, this wastes a thread just waiting for some IO operation to complete.充其量,这浪费了一个线程只是在等待一些 IO 操作完成。

MySqlCommand has an ExecuteNonQueryAsync method that accepts a cancellation token. MySqlCommand有一个ExecuteNonQueryAsync方法,它接受取消标记。 MySqlConnection itself has an OpenAsync method. MySqlConnection本身有一个OpenAsync方法。 You should change your code to :您应该将代码更改为:

public async Task<int> ExecuteNonQueryAsync(string connectionString, string query, 
       CancellationToken cancellationToken)
{
    using (MySqlConnection connection = new MySqlConnection(connectionString))
    {
        using (MySqlCommand command = new MySqlCommand(query,connection))
        {
            await connection.OpenAsync();
            command.CommandTimeout = 0;

            var affectedRowsCount = await command.ExecuteNonQuery(cancellationToken);
         }
    }

    return affectedRowsCount;
}

How are you creating your cancellation Token and what is his value?你是如何创建你的取消令牌的,他的价值是什么?

Also here is a solution how to cancel a sql command with a cancellation token这里还有一个解决方案如何使用取消令牌取消 sql 命令

private CancellationTokenSource cts;
private async void TestSqlServerCancelSprocExecution()
{
cts = new CancellationTokenSource();
try
{
    await Task.Run(() =>
    {
        using (SqlConnection conn = new SqlConnection("connStr"))
        {
            conn.InfoMessage += conn_InfoMessage;
            conn.FireInfoMessageEventOnUserErrors = true;
            conn.Open();

            var cmd = conn.CreateCommand();
            cts.Token.Register(() => cmd.Cancel());
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.CommandText = "dbo.[CancelSprocTest]";
            cmd.ExecuteNonQuery();
        }
   });
}
catch (SqlException)
{
    // sproc was cancelled
}

} }

The code above is from this question, which had kinda the same problem, that the cancellation token won't cancel the sql command. 上面的代码来自这个问题,它有同样的问题,取消令牌不会取消 sql 命令。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM