Подтвердить что ты не робот

Различать тайм-аут от отмены пользователя

HttpClient имеет встроенную функцию тайм-аута (несмотря на то, что она является асинхронной, то есть таймауты можно считать ортогональными для функции HTTP-запроса и, таким образом, обрабатываться универсальными асинхронными утилитами, но это в стороне), и когда тайм-аут срабатывает, ll throw a TaskCanceledException (завернутый в AggregateException).

TCE содержит a CancellationToken, который равен CancellationToken.None.

Теперь, если я предоставляю HttpClient своим CancellationToken и использую это, чтобы отменить операцию до ее окончания (или таймаута), я получаю то же самое TaskCanceledException, снова с CancellationToken.None.

Есть ли еще способ, , посмотрев только на исключение, брошенное, чтобы выяснить, отменяет ли тайм-аут запрос, не делая для моего собственного CancellationToken доступным для кода, который проверяет исключение?

P.S. Может ли это быть ошибкой, а CancellationToken каким-то образом неправильно зафиксировано на CancellationToken.None? В аннулированном использовании пользовательского случая CancellationToken я бы ожидал, что TaskCanceledException.CancellationToken будет соответствовать этому пользовательскому токену.

Edit Чтобы сделать проблему более понятной, с доступом к исходному CancellationTokenSource, легко отличить таймаут и отмену пользователя:

origCancellationTokenSource.IsCancellationRequested == true

Получение CancellationToken из исключения, но дает неправильный ответ:

((TaskCanceledException) e.InnerException).CancellationToken.IsCancellationRequested == false

Здесь минимальный пример, из-за популярного спроса:

public void foo()
{
    makeRequest().ContinueWith(task =>
    {
        try
        {
            var result = task.Result;
            // do something with the result;
        }
        catch (Exception e)
        {
            TaskCanceledException innerException = e.InnerException as TaskCanceledException;
            bool timedOut = innerException != null && innerException.CancellationToken.IsCancellationRequested == false;

            // Unfortunately, the above .IsCancellationRequested
            // is always false, no matter if the request was
            // cancelled using CancellationTaskSource.Cancel()
            // or if it timed out
        }
    });
}

public Task<HttpResponseMessage> makeRequest()
{
    var cts = new CancellationTokenSource();
    HttpClient client = new HttpClient() { Timeout = TimeSpan.FromSeconds(10) };
    HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "url");

    passCancellationTokenToOtherPartOfTheCode(cts);
    return client.SendAsync(httpRequestMessage, cts.Token);
}
4b9b3361

Ответ 2

Да, они оба возвращают одно и то же исключение (возможно, из-за таймаута, используя также токен), но это можно легко понять, сделав это:

   catch (OperationCanceledException ex)
            {
                if (token.IsCancellationRequested)
                {
                    return -1;
                }

                return -2;
            }

так что в основном, если вы нажмете на исключение, но ваш токен не будет отменен, ну, это был обычный таймаут http