Annulation D'une requête HttpClient-pourquoi TaskCanceledException.CancellationToken.IsCancellationRequested faux?
Étant donné le code suivant:
var cts = new CancellationTokenSource();
try
{
// get a "hot" task
var task = new HttpClient().GetAsync("http://www.google.com", cts.Token);
// request cancellation
cts.Cancel();
await task;
// pass:
Assert.Fail("expected TaskCanceledException to be thrown");
}
catch (TaskCanceledException ex)
{
// pass:
Assert.IsTrue(cts.Token.IsCancellationRequested,
"expected cancellation requested on original token");
// fail:
Assert.IsTrue(ex.CancellationToken.IsCancellationRequested,
"expected cancellation requested on token attached to exception");
}
Je m'attendrais à ce que ex.CancellationToken.IsCancellationRequested
soit true
à l'intérieur du bloc catch, mais ce n'est pas le cas. Suis-je un malentendu quelque chose?
1 réponses
C'est le cas parce que HttpClient
en interne (dans SendAsync
) utilise un TaskCompletionSource
pour représenter l'opération async
. Il retourne TaskCompletionSource.Task
et c'est la tâche sur laquelle vous await
.
Il appelle alors base.SendAsync
et enregistre une continuation sur la tâche renvoyée qui annule/complète / faults la tâche de TaskCompletionSource
en conséquence.
Dans le cas d'annulation, il utilise TaskCompletionSource.TrySetCanceled
qui associe à la tâche annulée avec un nouveau CancellationToken
(default(CancellationToken)
).
Comme Vous pouvez le voir en regardant le TaskCanceledException
. Sur le dessus de ex.CancellationToken.IsCancellationRequested
étant false
ex.CancellationToken.CanBeCanceled
est également false
, ce qui signifie que ce CancellationToken
ne peut jamais être annulé car il n'a pas été créé en utilisant un CancellationTokenSource
.
IMO il devrait utiliser TaskCompletionSource.TrySetCanceled(CancellationToken)
au lieu de cela. De cette façon, le {[2] } sera associé au CancellationToken
transmis par le consommateur et pas simplement au CancellationToken
par défaut. Je pense que c'est un bug (bien que mineur) et j'ai soumis un problème sur connect à ce sujet.