取消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.IsCancellationRequested
为true
,但事实并非如此。 我误会了什么吗?
情况就是这样,因为HttpClient
内部(在SendAsync
)使用TaskCompletionSource
来表示async
操作。 它返回TaskCompletionSource.Task
,这是你要await
的任务。
然后它调用base.SendAsync
并在返回的任务上注册一个延续,相应地取消/完成/完成TaskCompletionSource
的任务。
在取消的情况下,它使用TaskCompletionSource.TrySetCanceled
,它将取消的任务与新的CancellationToken
相关联( default(CancellationToken)
)。
您可以通过查看TaskCanceledException
来查看。 在ex.CancellationToken.IsCancellationRequested
为false
ex.CancellationToken.CanBeCanceled
也是false
,这意味着此CancellationToken
永远不会被取消,因为它不是使用CancellationTokenSource
创建的。
IMO应该使用TaskCompletionSource.TrySetCanceled(CancellationToken)
代替。 这样, TaskCompletionSource
将与消费者传入的CancellationToken
相关联,而不仅仅是默认的CancellationToken
。 我认为这是一个错误(虽然是一个小错误),我提交了关于它的连接问题 。