Vladyslav Yefremov
Vladyslav Yefremov

Reputation: 368

How to handle task cancellation using ContinueWith?

I've got the following example:

public void Run()
{
    var ctc = new CancellationTokenSource();

    try
    {
        DoAsync(ctc).Wait();

        Console.WriteLine("Done");
    }
    catch (AggregateException exception)
    {
        Console.WriteLine("Inside try-catch block");
        Console.WriteLine();
        Console.WriteLine(exception);

        exception.Handle(ex =>
        {
            Console.WriteLine(ex.Message);
            return true;
        });
    }
}

private async Task DoAsync(CancellationTokenSource ctc)
{
    Console.WriteLine("DoAsync started");

    await Task.Run(() =>
                Console.WriteLine("DoAsync Run"),
                ctc.Token
            )
            .ContinueWith(antecedent =>
                Console.WriteLine("DoAsync Run cancelled"),
                TaskContinuationOptions.OnlyOnCanceled
            );

    Console.WriteLine("DoAsync finished");
}

I've created a method (DoAsync) that does some asynchronous work and can be cancelled at any time.

As you can see Task.Run gets a cancellation token. For this reason I created continuation task with continuationOptions = TaskContinuationOptions.OnlyOnCanceled.

As a result I expected continuation task to be called only when cancellation is requested and in other cases - ignored.

But in my implementation task returned by ContinueWith throws an exception when its antecedent task is not being cancelled:

DoAsync started
DoAsync Run

Inside try-catch block
System.AggregateException...

A task was canceled.

I can fix this by adding another ContinueWith as in the example below:

await Task.Run(() =>
        Console.WriteLine("DoAsync Run"),
        ctc.Token
    )
    .ContinueWith(antecedent =>
        Console.WriteLine("DoAsync Run cancelled"),
        TaskContinuationOptions.OnlyOnCanceled
    )
    .ContinueWith(antecedent => { });

And this code doesn't throw any exceptions.

But can I handle the cancellation using single ContinueWith properly?

Upvotes: 4

Views: 3741

Answers (1)

Servy
Servy

Reputation: 203811

The remarks for ContinueWith specifically state:

If the continuation criteria specified through the continuationOptions parameter are not met, the continuation task will be canceled instead of scheduled.

Since the criteria you specified for the antecedent weren't met, (namely, it wasn't cancelled) the continuation was set to be cancelled. You awaited the cancelled task, which therefore result in DoAsync faulting with an operation cancelled exception.

Upvotes: 4

Related Questions