取消HttpClient请求 - 为什么TaskCanceledException.CancellationToken.IsCancellationRequested为false?

Tod*_*ier 30 .net c# async-await cancellationtokensource dotnet-httpclient

给出以下代码:

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");
}
Run Code Online (Sandbox Code Playgroud)

我希望ex.CancellationToken.IsCancellationRequestedtrue在catch块内,但事实并非如此.我误会了什么吗?

i3a*_*non 43

情况就是这样,因为HttpClient内部(in SendAsync)使用a TaskCompletionSource来表示async操作.它返回TaskCompletionSource.Task,这是你的任务await.

然后base.SendAsync,它会在返回的任务上调用并注册一个延续,从而相应地取消/完成/排除TaskCompletionSource任务.

在取消的情况下,它使用TaskCompletionSource.TrySetCanceled将取消的任务与new CancellationToken(default(CancellationToken))相关联.

你可以通过查看来看到TaskCanceledException.在顶部ex.CancellationToken.IsCancellationRequested的存在false ex.CancellationToken.CanBeCanceled也是false,这意味着这CancellationToken因为它不使用创建不能被取消CancellationTokenSource.


IMO应该使用它TaskCompletionSource.TrySetCanceled(CancellationToken).这样,TaskCompletionSource它将与CancellationToken消费者传入而不仅仅是默认值相关联CancellationToken.我认为这是一个错误(虽然是一个小错误),我提交了关于它的连接问题.

  • 很好的答案,+1报告问题.我不太确定它是次要的,因为我(和[其他人](http://stackoverflow.com/q/12666922/62600))依赖于此来区分用户取消和超时的情况下`HttpClient`. (5认同)
  • @StriplingWarrior你打开的问题就在同一个地方.无论如何,他们上周回复说并将修复.NET 4.7.2 (2认同)