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?
The remarks for
ContinueWith
specifically state: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.