Reputation: 1241
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
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
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
Reputation: 2760
So imho you should to do next:
I hope this help you
Upvotes: -3