and85
and85

Reputation: 1241

What is the best way to catch "Operation cancelled by user" exception

I have the following piece of code:

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;
}

How can I identify that the exception caught was caused by operation cancelation?

In this case ExecuteNonQuery throws an exception with error code 0x80131904, but it's a very general exception which can be caused by many reasons. The error message looks like this: "A severe error occurred on the current command. The results, if any, should be discarded.\r\nOperation cancelled by user."

I don't see any options except parsing the error message... Any ideas?

Thanks

PS. Yeah, I know that using the Cancel command for async operation probably is not the best idea, because in the .NET 2.0 documentation on MSDN there was a warning. But in the .NET 4.0 documentation, this warning is removed.
I also don't like other implementations where the cancel method is called from another thread, as for me it makes code more difficult.

Upvotes: 16

Views: 10179

Answers (3)

Mitch
Mitch

Reputation: 22251

There doesn't seem to be a locale insensitive mechanism to catch just this error. The HResult 0x80131904 is just COR_E_SqlException. The error is initiated at TdsParser.cs:2332 without any unique properties. It is almost the exact same code as :2759 - Unknown Error and :3850 - Unexpected Collation.

Here are the bad solutions I have come up with:

Option 1: Break the good advice of "don't make logic locale sensitive"

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

Option 2: Assume that no other severe locally generated error matters after a cancel has been issued

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

Upvotes: 9

cuong pham
cuong pham

Reputation: 1

You can exam exception message in catch block to find which operation was cancelled by user:

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

Upvotes: -4

Likurg
Likurg

Reputation: 2760

So imho you should to do next:

  1. Make a thread where you will use ado (read this Thread example)
  2. Delete Thread.Sleep(100); //Imho never use it
  3. Add to your class static bool muststop=false;
  4. Add to your class public static function to change "muststop"
  5. Change you thread's function to stop it if muststop==true

I hope this help you

Upvotes: -3

Related Questions