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

给出以下代码:

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

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

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

然后它调用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 。 我认为这是一个错误(虽然是一个小错误),我提交了关于它的连接问题 。