[C#] Asynchronous methods should take a CancellationToken

Asynchronous methods should take a CancellationToken.
Sometimes, async methods are not written with cooperative cancellation in mind. Either because a developer is not aware of the pattern or because they consider it unnecessary in a specific case.
Not accepting a CancellationToken can however cause an awful lot of refactoring if the async call chain is deep and contains many methods not taking a cancellation token. Accepting a token on each asynchronous method ensures that the scope of refactoring to use cancellation later is limited, as it essentially comes down to passing on tokens that were previously ignored.
Additionally, it helps considering where to act on a hot CT when implementing a method, which is easier than reasoning about the right place to cancel when refactoring code to make use of CTs.
CancellationToken is a readonly struct that only holds a reference to the underlying CancellationTokenSource, thus the overhead is minimal (i.e. it can be used in performance critical paths as well).
Enabling this rule on non-compliant code may cause many positives, but that’s probably true for all new rules.

Noncompliant Code:

public Task DoAsync(){}
public Task<T> DoAsync<T>(){}
public ValueTask DoValueAsync(){}
public ValueTask<T> DoValueAsync<T>(){}

Compliant Code:

public Task DoAsync(CancellationToken cancellationToken){}
public Task<T> DoAsync<T>(CancellationToken cancellationToken){}
public ValueTask DoValueAsync(CancellationToken cancellationToken){}
public ValueTask<T> DoValueAsync<T>(CancellationToken cancellationToken){}
// as well as this (
public Task DoAsync(CancellationToken cancellationToken = default){}
public Task<T> DoAsync<T>(CancellationToken cancellationToken = default){}
public ValueTask DoValueAsync(CancellationToken cancellationToken = default){}
public ValueTask<T> DoValueAsync<T>(CancellationToken cancellationToken = default){}

Exceptions to the Noncompliant Code:
If side effects can already be observed, subsequent tasks should not be cancelled. I doubt that that could be anaylzed automatically though. However, accepting a CancellationToken does not require the callee to act on cancellation, so callees can simply opt out of cancellation by not evaluating the token/not passing it on.
External references:

Type: Code Smell
Tags: csharp, async-await

Hi @jasper-d, thanks a lot for your suggestion. This looks to be very useful when implementing asynchronous applications. I’ve added an issue on our side to implement it but unfortunately I cannot provide an ETA.