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 (з a 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 Якщо виклик редагується await, жодна тема не заблокована. Не нитка користувальницького інтерфейсу, не нитка нитки пула, інша фонова нитка, жодна.
Тод Меньє

20

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

Рішення було зателефонувати myTask.GetAwaiter().GetResult()в Main()цієї відповіді ).


9

Інша можливість полягає в тому, що результат не чекається на стороні клієнта. Це може статися, якщо будь-який один метод у стеці викликів не використовує ключове слово очікування для очікування завершення виклику.


8
var clientHttp = new HttpClient();
clientHttp.Timeout = TimeSpan.FromMinutes(30);

Сказане - найкращий підхід для очікування на великий запит. Ви плутаєтесь близько 30 хвилин; це випадковий час, і ви можете дати будь-який час, який вам захочеться.

Іншими словами, запит не чекатиме 30 хвилин, якщо вони отримають результати до 30 хвилин. 30 хв означає, що час обробки запиту - 30 хв. Коли у нас виникла помилка, "Завдання було скасовано", або великі вимоги до даних.


0

Іншою причиною може бути те, що якщо ви запускаєте службу (API) і ставите в сервісі точку розриву (а ваш код застряг на якійсь точці розриву (наприклад, рішення Visual Studio показує налагодження замість запуску )). а потім натискання API з коду клієнта. Отже, якщо сервісний код призупинено на якійсь точці розриву, ви просто натиснете F5 в VS.


0

У моїй ситуації метод контролера не був асинхронним, а метод, який називається всередині методу контролера, був асинхронним.

Тому я здогадуюсь, що важливо використовувати асинхронізування / очікувати весь шлях до вищого рівня, щоб уникнути подібних проблем.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.