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?

27
demandé sur Todd Menier 2015-03-28 18:44:30

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.

39
répondu i3arnon 2017-09-13 22:15:48