HttpClient - Задача была отменена?

191

Он отлично работает, когда есть одна или две задачи, однако выдает ошибку «Задача была отменена», когда у нас в списке более одной задачи.

введите описание изображения здесь

List<Task> allTasks = new List<Task>();
allTasks.Add(....);
allTasks.Add(....);
Task.WaitAll(allTasks.ToArray(), configuration.CancellationToken);


private static Task<T> HttpClientSendAsync<T>(string url, object data, HttpMethod method, string contentType, CancellationToken token)
{
    HttpRequestMessage httpRequestMessage = new HttpRequestMessage(method, url);
    HttpClient httpClient = new HttpClient();
    httpClient.Timeout = new TimeSpan(Constants.TimeOut);

    if (data != null)
    {
        byte[] byteArray = Encoding.ASCII.GetBytes(Helper.ToJSON(data));
        MemoryStream memoryStream = new MemoryStream(byteArray);
        httpRequestMessage.Content = new StringContent(new StreamReader(memoryStream).ReadToEnd(), Encoding.UTF8, contentType);
    }

    return httpClient.SendAsync(httpRequestMessage).ContinueWith(task =>
    {
        var response = task.Result;
        return response.Content.ReadAsStringAsync().ContinueWith(stringTask =>
        {
            var json = stringTask.Result;
            return Helper.FromJSON<T>(json);
        });
    }).Unwrap();
}
Картикеян Виджаякумар
источник
Что говорит Внутреннее Исключение?
RagtimeWilly
1
Почему вы берете в CancellationTokenкачестве параметра и не используете его?
Джим Ахо
1
Причиной для меня было выбрасывание HttpClientпо ошибке, напримерasync Task<HttpResponseMessage> Method(){ using(var client = new HttpClient()) return client.GetAsync(request); }
JobaDiniz
3
Для тех, кто использует HttpClientкак @JobaDiniz (с using()), пожалуйста, остановитесь! Причина: aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong
Филипп

Ответы:

274

Есть 2 вероятные причины, по TaskCanceledExceptionкоторым будет брошено:

  1. То , что называется Cancel()на CancellationTokenSourceсвязанное с отменой маркера , прежде чем завершения задачи.
  2. Время запроса истекло, т.е. оно не было выполнено в течение указанного вами времени HttpClient.Timeout.

Я думаю, это был тайм-аут. (Если бы это была явная отмена, вы, вероятно, поняли бы это.) Вы можете быть более уверенным, изучив исключение:

try
{
    var response = task.Result;
}
catch (TaskCanceledException ex)
{
    // Check ex.CancellationToken.IsCancellationRequested here.
    // If false, it's pretty safe to assume it was a timeout.
}
Тодд менье
источник
3
Итак, что является возможным решением? У меня похожая проблема. stackoverflow.com/questions/36937328/…
разработчик
49
@Dimi - это довольно старое, но решение, которое я использовал, состояло в том, чтобы установить для свойства Timeout большее значение:httpClient.Timeout = TimeSpan.FromMinutes(30)
RQDQ
2
@RQDQ, ты мужчина, мужчина! Неиспользование конструктора решило проблему для меня. В моем конкретном случае я хотел тайм-аут в миллисекундах. Использование TimeSpan.FromMilliseconds(Configuration.HttpTimeout)в отличие от new TimeSpan(Configuration.HttpTimeout)полученного удовольствия. Спасибо!
Виктор Удэ,
6
@RQDQ httpClient.Timeout = TimeSpan.FromMinutes(30)не очень хороший подход, потому что он блокирует этот конкретный поток на 30 минут, а также не достигнет конечной точки HTTP (что является вашей главной задачей). Кроме того, если ваша программа заканчивается до 30 минут, то вы, скорее всего, столкнетесь ThreadAbortException. Лучшим подходом было бы выяснить, почему эта конечная точка HTTP не поражена, для этого может потребоваться VPN или некоторый ограниченный доступ к сети.
Амит Упадхьяй,
6
@AmitUpadhyay Если вызов awaited, то ни один поток не заблокирован. Не поток пользовательского интерфейса, не поток потоков другого фонового потока, ни один.
Тодд Менье
20

Я столкнулся с этой проблемой, потому что мой Main()метод не ожидал завершения задачи перед возвратом, поэтому Task<HttpResponseMessage> myTaskон отменялся при выходе из моей консольной программы.

Решение было позвонить myTask.GetAwaiter().GetResult()в Main()(из этого ответа ).

Бен Хатчисон
источник
9

Другая возможность заключается в том, что результат не ожидается на стороне клиента. Это может произойти, если какой-либо один метод в стеке вызовов не использует ключевое слово await для ожидания завершения вызова.

Manish
источник
8
var clientHttp = new HttpClient();
clientHttp.Timeout = TimeSpan.FromMinutes(30);

Вышесказанное - лучший подход для ожидания большого запроса. Вы запутались около 30 минут; это случайное время, и вы можете дать любое время, которое вы хотите.

Другими словами, запрос не будет ждать 30 минут, если он получит результаты до 30 минут. 30 минут означает, что время обработки запроса составляет 30 минут. Когда произошла ошибка «Задача была отменена», или возникли большие требования к данным.

Навдип Капил
источник
0

Другая причина может заключаться в том, что если вы запускаете службу (API) и ставите точку останова в службе (а ваш код застревает на некоторой точке останова (например, решение Visual Studio показывает отладку вместо запуска )). а затем нажав API из клиентского кода. Таким образом, если служебный код приостановлен на некоторой точке останова, вы просто нажимаете F5 в VS.

Вивек Нуна
источник
0

В моей ситуации метод контроллера не был выполнен как асинхронный, а метод, вызываемый внутри метода контроллера, был асинхронным.

Поэтому я думаю, что важно использовать async / await вплоть до верхнего уровня, чтобы избежать подобных проблем.

chaitanyasingu
источник