OperationCanceledException VS TaskCanceledException when task is canceled

The difference here comes from using token.ThrowIfCancellationRequested(). This method checks for cancellation and if requested throws OperationCanceledException specifically and not TaskCanceledException (understandable as CancellationToken isn't exclusive to the TPL). You can look at the reference source and see that it calls this method:

private void ThrowOperationCanceledException()
{
    throw new OperationCanceledException(Environment.GetResourceString("OperationCanceled"), this);
}

"Regular" cancellation though will indeed generate a TaskCanceledException. You can see that by cancelling the token before the task had a chance to start running:

cancellationTokenSource.Cancel();
var task = Task.Run(() => { }, cancellationTokenSource.Token);
try
{
    await task; 
}
catch (Exception ex)
{
    Console.WriteLine(ex.ToString());
    Console.WriteLine($"Task.IsCanceled: {task.IsCanceled}");
    Console.WriteLine($"Task.IsFaulted: {task.IsFaulted}");
    Console.WriteLine($"Task.Exception: {((task.Exception == null) ? "null" : task.Exception.ToString())}");
}

Output:

System.Threading.Tasks.TaskCanceledException: A task was canceled.
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Sandbox.Program.<MainAsync>d__1.MoveNext()
Task.IsCanceled: True
Task.IsFaulted: False
Task.Exception: null

Traditional .Net methods usually don't use CancellationToken.ThrowIfCancellationRequested for async API as this is only appropriate when offloading work to another thread. These methods are for inherently asynchronous operations so cancellation is monitored using CancellationToken.Register (or the internal InternalRegisterWithoutEC).


TaskCanceledException inherits from OperationCanceledException. So it least there is a little consitency.

if( ex is OperationCanceledException)
{
...
}