CancellationTokenSource creates a CancellationToken that asynchronous work can use as a stop signal. Think of the source as a restaurant host and the token as a pager: the host triggers the signal, and the holder can respond. section 4.4
Passing a token is explicit, not automatic. An async method can check IsCancellationRequested before starting an HTTP call, then pass the same token to both the HTTP request and stream deserialization. Depending on the operation, cancellation can mean returning null or throwing an exception. section 4.4
Listing 4.35 Asynchronous version of GetComicWithTitle
static async Task<Comic?> GetComicWithTitleAsync( #1
string title)
{
var cancellationToken = new CancellationTokenSource(); #2
var lastComic = await Comic.GetComicAsync(0, #3
cancellationToken.Token);
var tasks = new List<Task>(); #4
Comic? foundComic = null; #5
for (int number = lastComic!.Number;
number > 0;
number--)
{
var localNumber = number; #6
var getComicTask = Comic.GetComicAsync(localNumber, #7
cancellationToken.Token);
var continuationTask = getComicTask.ContinueWith( #8
t => { #9
try
{
var comic = t.Result;
if (comic != null &&
string.Equals(title, comic!.Title,
StringComparison.OrdinalIgnoreCase))
{
cancellationToken.Cancel(); #10
foundComic = comic;
}
}
catch (TaskCanceledException) {} #11
});
tasks.Add(continuationTask); #12
}
await Task.WhenAll(tasks); #13
return foundComic;
}
The asynchronous search creates one source and passes its Token to comic-fetching tasks. section 4.4
Listing 4.34 Modifying GetComic to be asynchronous
public static async Task<Comic?> GetComicAsync( #1
int number, #2
CancellationToken cancellationToken) #3
{
if (cancellationToken.IsCancellationRequested) #4
{
return null;
}
try
{
var path = number == 0 ? "info.0.json"
: $"{number}/info.0.json";
var stream = await client.GetStreamAsync( #5
path, cancellationToken); #6
return await JsonSerializer.DeserializeAsync<Comic>( #7
stream, cancellationToken: cancellationToken); #6
}
catch (AggregateException e)
when (e.InnerException is HttpRequestException)
{
return null;
}
catch (HttpRequestException)
{
return null;
}
catch (TaskCanceledException) #8
{
return null;
}
}
The fetch method accepts a token, checks it, and forwards it to asynchronous I/O. section 4.4

