How to catch OperationCanceledException when using ContinueWith

I have code that I downgrade from .NET 4.5 fine async and await keywords to .NET 4.0. I use ContinueWith to create a continuation similar to how await works.

Basically, my old code is:

 var tokenSource = newCancellationTokenSource(); var myTask = Task.Run(() => { return MyStaticClass.DoStuff(tokenSource.Token); }, tokenSource.Token); try { var result = await myTask; DoStuffWith(result); } catch (OperationCanceledException) { // Cancel gracefully. } 

(As expected, MyStaticClass.DoStuff(token) regularly calls token.ThrowIfCancellationRequested() .)

My new code is as follows:

 var tokenSource = new CancellationTokenSource(); try { Task.Factory.StartNew(() => { return MyStaticClass.DoStuff(tokenSource.Token); }, tokenSource.Token) .ContinueWith(task => { var param = new object[1]; param[0] = task.Result; // I need to use Invoke here because "DoStuffWith()" does UI stuff. Invoke(new MyDelegate(DoStuffWith, param)); }); } catch (OperationCanceledException) { // Cancel gracefully. } 

However, OperationCanceledException never throws. What's happening? Where can I place a try / catch block?

+5
source share
1 answer

Cancel is handled differently than other exceptions. Basically, you can use this template:

 Task.Factory.StartNew(() => { // The task }, tokenSource.Token) .ContinueWith(task => { // The normal stuff }, TaskContinuationOptions.OnlyOnRanToCompletion) .ContinueWith(task => { // Handle cancellation }, TaskContinuationOptions.OnlyOnCanceled) .ContinueWith(task => { // Handle other exceptions }, TaskContinuationOptions.OnlyOnFaulted); 

Or an alternative option:

 Task.Factory.StartNew(() => { // The task }, tokenSource.Token) .ContinueWith(task => { switch (task.Status) { case TaskStatus.RanToCompletion: // The normal stuff break; case TaskStatus.Canceled: // Handle cancellation break; case TaskStatus.Faulted: // Handle other exceptions break; } }); 

In your case, you will not catch anything, because:

  • Task.Factory.StartNew returns immediately and always succeeds.
  • Your continuation is always in progress.
  • Access to task.Result throws an AggregateException because the task is canceled
  • The exception is not handled by anything because it is selected from the thread pool thread. Unfortunately. What will happen next depends on the version of the frame :

    • In .NET <4.5, the process will be completed as soon as the unsuccessful task completes, since you have a subtle exception.
    • In .NET> = 4.5, the exception will be disabled.
+6
source

All Articles