14

我有以下代码和平:

IAsyncResult beginExecuteReader = command.BeginExecuteNonQuery();

while (!beginExecuteReader.IsCompleted)
{
    if (controllerTask.CancellationTokenSource.IsCancellationRequested)
    {
        command.Cancel();
    }

    Thread.Sleep(100);
}

try
{
    result = command.EndExecuteNonQuery(beginExecuteReader);
}
catch (SqlException exception)
{
    if (exception.ErrorCode == OperationCanceled)
    {
        throw new OperationCanceledException();
    }

    throw;
}

我如何识别捕获的异常是由操作取消引起的。在这种情况下,ExecuteNonQuery 会抛出错误代码为 0x80131904 的异常,但这是非常普遍的异常,可能由多种原因引起。错误消息如下所示:{“当前命令发生严重错误。结果(如果有)应被丢弃。\r\n操作已被用户取消。”}

除了解析错误消息外,我没有看到任何选项......有什么想法吗?

谢谢

PS。是的,我知道取消异步操作的命令可能不是最好的主意,因为对于 .NET 2.0,MSDN 上有警告,但对于 .NET 4.0,此警告已被删除。当从另一个线程调用取消方法时,我也不喜欢其他实现,因为对我来说它使代码更加困难

4

3 回答 3

7

似乎没有一种语言环境不敏感的机制来捕获这个错误。HResult 0x80131904 只是COR_E_SqlException. 该错误在TdsParser.cs:2332处启动,没有任何唯一属性。它与:2759 - Unknown Error:3850 - Unexpected Collat ​​ion的代码几乎完全相同。

以下是我提出的不好的解决方案:

选项 1:打破“不要使逻辑语言环境敏感”的好建议

using (var con = new SqlConnection("Server=(local);Integrated Security=True;"))
{
    con.Open();

    try
    {
        var sqc = new SqlCommand("WAITFOR DELAY '1:00:00'", con);
        var readThread = Task.Run(() => sqc.ExecuteNonQuery());

        // cancel after 5 seconds
        Thread.Sleep(5000);
        sqc.Cancel();

        // this should throw
        await readThread;

        // unreachable
        Console.WriteLine("Succeeded");
    }
    catch (SqlException ex) when (ex.Number == 0 && ex.State == 0 && ex.Class == 11 
        && ex.Message.Contains("Operation cancelled by user."))
    {
        Console.WriteLine("Cancelled");
    }
    catch (Exception ex)
    {
        Console.WriteLine("Error");
    }
}

选项 2:假设在发出取消后没有其他严重的本地生成错误重要

using (var con = new SqlConnection("Server=(local);Integrated Security=True;"))
{
    con.Open();

    bool isCancelled = false;
    try
    {
        var sqc = new SqlCommand("WAITFOR DELAY '1:00:00'", con);
        var readThread = Task.Run(() => sqc.ExecuteNonQuery());

        // cancel after 5 seconds
        Thread.Sleep(5000);
        isCancelled = true;
        sqc.Cancel();

        // this should throw
        await readThread;

        // unreachable
        Console.WriteLine("Succeeded");
    }
    catch (SqlException ex) when (isCancelled && ex.Number == 0 && ex.State == 0 && ex.Class == 11)
    {
        Console.WriteLine("Cancelled");
    }
    catch (Exception ex)
    {
        Console.WriteLine("Error");
    }
}
于 2018-08-09T22:44:48.823 回答
-2

所以恕我直言,您接下来应该做的是:

  1. 创建一个您将使用 ado 的线程(阅读此线程示例
  2. 删除 Thread.Sleep(100); //恕我直言,从不使用它
  3. 添加到你的类 static bool muststop=false;
  4. 添加到您的类公共静态函数以更改“必须停止”
  5. 如果 muststop==true 则更改线程的功能以停止它

我希望这对你有帮助

于 2012-04-19T11:22:15.017 回答
-3

您可以检查 catch 块中的异常消息以查找用户取消了哪个操作:

try
{
   //your code
}
catch (SqlException ex)
{
  if (ex.Message.Contain("Operation cancelled by user"))
   {
       //Do something here
   }
}
于 2013-07-10T07:34:07.130 回答