Отмена запроса HttpClient-почему TaskCanceledException.CancellationToken.IsCancellationRequested ложь?
учитывая следующий код:
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
на true
внутри блока catch, но это не так. Я что-то не так понял?
1 ответов
это так, потому что HttpClient
внутренне (в SendAsync
) использует TaskCompletionSource
представлять async
операции. Он возвращается TaskCompletionSource.Task
и это задача, которую вы await
on.
затем он называет 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
. Я думаю, что это ошибка (хотя и незначительная), и я подал Ан вопрос о подключении об этом.