c# - 取消 HttpClient 请求 - 为什么 TaskCanceledException.CancellationToken.IsCancellationRequested 为假?

标签 c# .net async-await dotnet-httpclient cancellationtokensource

给定以下代码:

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");
}

我希望 ex.CancellationToken.IsCancellationRequested 在 catch block 内为 true,但事实并非如此。我是不是误会了什么?

最佳答案

之所以如此,是因为 HttpClient 内部(在 SendAsync 中)使用 TaskCompletionSource 来表示 async 操作.它返回 TaskCompletionSource.Task,这就是您等待的任务。

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

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

您可以通过查看 TaskCanceledException 来了解这一点。除了 ex.CancellationToken.IsCancellationRequestedfalse ex.CancellationToken.CanBeCanceled 也是 false,这意味着这CancellationToken 永远无法取消,因为它不是使用 CancellationTokenSource 创建的。


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

关于c# - 取消 HttpClient 请求 - 为什么 TaskCanceledException.CancellationToken.IsCancellationRequested 为假?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29319086/

相关文章:

Swift 等同于 Unity3d 协程?

c# - 等待回调方法

javascript - 仅从内容页刷新母版页

c# - Script# 数字映射到 Javascript 的效果如何?

c# - .Net UI 和 Java 中间件

c# - 在 TreeNode (WinForms) 中访问文本选择

c# - 使用异步等待时出现意外结果

c# - 如何使用 Quartz.net 和 log4net 配置 ninject

c# - ActiveX 组件无法创建对象? .NET 通讯

c# - 在 C# 中同步线程