Associate a CancellationToken with an async method's Task
async-await, c#, cancellation-token, task-parallel-library
Solution
I think the design works well for the common case: if any child operations are cancelled, then the cancellation propagates to the parent (the most common case is that the parent and child share cancellation tokens).
If you want different semantics, you can `catch` the `OperationCanceledException` in your `async` method and throw an exception that fits the semantics you need. If you want to use these semantics repeatedly, an extension method for `Task` should fit the bill.
Problem
Question: Is there a way to associate a `CancellationToken` with the `Task` returned from an `async` method? Generally, a `Task` will end up in the `Canceled` state if an `OperationCancelledException` is thrown with a `CancellationToken` matching the `Task`'s `CancellationToken`. If they don't match, then the task goes into the `Faulted` state: ``` void WrongCancellationTokenCausesFault() { var cts1 = new CancellationTokenSource(); var cts2 = new CancellationTokenSource(); cts2.Cancel(); // This task will end up in the Faulted state due to the task's CancellationToken // not matching the thrown OperationCanceledException's token. var task = Task.Run(() => cts2.Token.ThrowIfCancellationRequested(), cts1.Token); } ``` With `async`/`await`, I haven't found a way to set the method's `Task`'s `CancellationToken` (and thus achieve the same sort of functionality). From my testing, it seems that any `OperationCancelledException` will cause the `async` method to enter the Cancelled state: ``` async Task AsyncMethodWithCancellation(CancellationToken ct) { // If ct is cancelled, this will cause the returned Task to be in the Cancelled state ct.ThrowIfCancellationRequested(); await Task.Delay(1); // This will cause the returned Task to be in the Cancelled state var newCts = new CancellationTokenSource(); newCts.Cancel(); newCts.Token.ThrowIfCancellationRequested(); } ``` It would be nice to have a little more control, since if a method I call from my `async` method is cancelled (and I don't expect cancellation--i.e. its not this `Task`'s `CancellationToken`), I would expect the task to enter the `Faulted` state--not the `Canceled` state.