捕捉"用户取消操作的最佳方法是什么?例外

时间:2012-04-19 10:37:19

标签: 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;
}

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

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

由于

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

3 个答案:

答案 0 :(得分:2)

似乎没有语言环境不敏感的机制可以捕获此错误。 HResult 0x80131904 is just COR_E_SqlException。错误始于TdsParser.cs:2332,没有任何唯一属性。它几乎与:2759 - Unknown Error:3850 - Unexpected Collation完全相同。

以下是我想出的错误解决方案:

选项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");
    }
}

答案 1 :(得分:-1)

所以你应该做下一步:

  1. 制作一个您将使用ado的帖子(阅读此Thread example
  2. 删除Thread.Sleep(100); // Imho从不使用它
  3. 添加到您的班级静态bool muststop = false;
  4. 添加到您的班级公共静态函数以更改“muststop”
  5. 如果muststop == true
  6. ,请更改线程的功能以停止它

    我希望这可以帮到你

答案 2 :(得分:-2)

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

try
{
   //your code
}
catch (SqlException ex)
{
  if (ex.Message.Contain("Operation cancelled by user"))
   {
       //Do something here
   }
}