HttpClient - Tugas dibatalkan?

191

Ini berfungsi dengan baik ketika memiliki satu atau dua tugas namun melontarkan kesalahan "Tugas dibatalkan" ketika kami memiliki lebih dari satu tugas yang terdaftar.

masukkan deskripsi gambar di sini

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();
}
Karthikeyan Vijayakumar
sumber
Apa kata Pengecualian Batin?
RagtimeWilly
1
Mengapa Anda mengambil CancellationTokenparameter sebagai dan tidak menggunakannya?
Jim Aho
1
Alasan saya untuk membuang HttpClientkarena kesalahan, misalnyaasync Task<HttpResponseMessage> Method(){ using(var client = new HttpClient()) return client.GetAsync(request); }
JobaDiniz
3
Bagi mereka yang menggunakan HttpClient@JobaDiniz (dengan a using()), silakan berhenti! Alasannya: aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong
Philippe

Jawaban:

274

Ada 2 kemungkinan alasan yang TaskCanceledExceptionakan dilemparkan:

  1. Sesuatu yang disebut Cancel()pada CancellationTokenSourceterkait dengan pembatalan tanda sebelum tugas selesai.
  2. Batas waktu permintaan, yaitu tidak selesai dalam rentang waktu yang Anda tentukan HttpClient.Timeout.

Dugaan saya adalah batas waktu. (Jika itu adalah pembatalan eksplisit, Anda mungkin akan mengetahuinya.) Anda dapat lebih yakin dengan memeriksa pengecualian:

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.
}
Todd Menier
sumber
3
Jadi apa solusi yang mungkin? Saya memiliki masalah serupa. stackoverflow.com/questions/36937328/…
Pengembang
49
@Dimi - ini cukup tua, tetapi solusi yang saya gunakan adalah untuk mengatur properti Timeout ke nilai yang lebih besar:httpClient.Timeout = TimeSpan.FromMinutes(30)
RQDQ
2
@RQDQ, Anda laki-laki, laki-laki! Tidak menggunakan konstruktor menyelesaikan masalah untuk saya. Dalam kasus spesifik saya, saya ingin batas waktu dalam milidetik. Menggunakan TimeSpan.FromMilliseconds(Configuration.HttpTimeout)sebagai lawan new TimeSpan(Configuration.HttpTimeout)bekerja memperlakukan. Terima kasih!
Victor Ude
6
@RQDQ httpClient.Timeout = TimeSpan.FromMinutes(30)bukan pendekatan yang baik, karena akan memblokir utas tertentu selama 30 menit dan juga tidak akan mencapai titik akhir HTTP (yang merupakan tugas utama Anda). Juga, jika program Anda selesai sebelum 30 menit maka kemungkinan besar Anda akan bertemu ThreadAbortException. Pendekatan yang lebih baik adalah mencari tahu mengapa titik akhir HTTP itu tidak terkena, mungkin memerlukan VPN atau akses jaringan terbatas.
Amit Upadhyay
6
@AmitUpadhyay Jika panggilan tersebut disunting await, maka tidak ada utas yang diblokir. Bukan utas UI, bukan utas threadpool utas latar belakang lainnya, tidak ada.
Todd Menier
20

Saya mengalami masalah ini karena Main()metode saya tidak menunggu tugas selesai sebelum kembali, jadi Task<HttpResponseMessage> myTaskdibatalkan ketika program konsol saya keluar.

Solusinya adalah untuk memanggil myTask.GetAwaiter().GetResult()di Main()(dari jawaban ini ).

Ben Hutchison
sumber
9

Kemungkinan lain adalah bahwa hasilnya tidak ditunggu di sisi klien. Ini dapat terjadi jika salah satu metode pada tumpukan panggilan tidak menggunakan kata kunci tunggu untuk menunggu panggilan selesai.

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

Di atas adalah pendekatan terbaik untuk menunggu permintaan besar. Anda bingung sekitar 30 menit; ini waktu acak dan Anda dapat memberikan waktu yang Anda inginkan.

Dengan kata lain, permintaan tidak akan menunggu selama 30 menit jika mereka mendapatkan hasil sebelum 30 menit. 30 mnt berarti waktu pemrosesan permintaan adalah 30 mnt. Ketika kami terjadi kesalahan "Tugas dibatalkan", atau persyaratan permintaan data besar.

Navdeep Kapil
sumber
0

Alasan lain bisa jadi adalah jika Anda menjalankan layanan (API) dan meletakkan breakpoint di layanan (dan kode Anda macet di beberapa breakpoint (misalnya solusi Visual Studio menunjukkan Debugging alih-alih Menjalankan )). dan kemudian memukul API dari kode klien. Jadi, jika kode layanan berhenti pada beberapa breakpoint, Anda cukup menekan F5 di VS.

vivek nuna
sumber
0

Dalam situasi saya, metode pengontrol tidak dibuat sebagai async dan metode yang disebut di dalam metode pengontrol adalah async.

Jadi saya kira sangat penting untuk menggunakan async / menunggu sampai ke tingkat atas untuk menghindari masalah seperti ini.

chaitanyasingu
sumber