捕获"用户取消操作"异常的最佳方法是什么

and*_*d85 10 c# ado.net

我有以下代码和平:

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;
}
Run Code Online (Sandbox Code Playgroud)

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

除了解析错误信息之外,我没有看到任何选项...任何想法?

谢谢

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

Mit*_*tch 6

似乎没有一种区域设置不敏感的机制来捕获这个错误。该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");
    }
}
Run Code Online (Sandbox Code Playgroud)

选项 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");
    }
}
Run Code Online (Sandbox Code Playgroud)


Lik*_*urg -3

所以恕我直言,你下一步应该做:

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

我希望这对你有帮助