HttpClient: un'attività è stata annullata?


191

Funziona bene quando hanno una o due attività, tuttavia genera un errore "Un'attività è stata annullata" quando abbiamo elencato più di un'attività.

inserisci qui la descrizione dell'immagine

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();
}

Cosa dice l'eccezione interiore?
RagtimeWilly,

1
Perché prendi un CancellationTokenparametro as e non lo usi?
Jim Aho,

1
La ragione per me era l'eliminazione HttpClientper errore, ad esasync Task<HttpResponseMessage> Method(){ using(var client = new HttpClient()) return client.GetAsync(request); }
JobaDiniz,

3
Per quelli che usano HttpClientcome @JobaDiniz (con a using()), per favore fermati! Il motivo: aspnetmonsters.com/2016/08/2016 08-08-27
Philippe

Risposte:


274

Ci sono 2 probabili motivi per cui un TaskCanceledExceptionverrebbe lanciato:

  1. Qualcosa chiamato Cancel()sul CancellationTokenSourceassociata alla cancellazione token prima che l'operazione completata.
  2. La richiesta è scaduta, ovvero non è stata completata entro l'intervallo di tempo specificato HttpClient.Timeout.

Suppongo sia stato un timeout. (Se si fosse trattato di una cancellazione esplicita, probabilmente l'avresti capito.) Puoi essere più sicuro controllando l'eccezione:

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
Quindi qual è una possibile soluzione? Ho un problema simile. stackoverflow.com/questions/36937328/…
Sviluppatore

49
@Dimi: è piuttosto vecchio, ma la soluzione che ho usato è stata quella di impostare la proprietà Timeout su un valore maggiore:httpClient.Timeout = TimeSpan.FromMinutes(30)
RQDQ

2
@RQDQ, tu l'uomo, amico! Non usare il costruttore ha risolto il problema per me. Nel mio caso specifico, volevo un timeout in millisecondi. Usando TimeSpan.FromMilliseconds(Configuration.HttpTimeout)invece di aver new TimeSpan(Configuration.HttpTimeout)funzionato a meraviglia. Grazie!
Victor Ude,

6
@RQDQ httpClient.Timeout = TimeSpan.FromMinutes(30)non è un buon approccio, perché bloccherà quel particolare thread per 30 minuti e non colpirà nemmeno l'endpoint HTTP (che è la tua attività principale). Inoltre, se il programma termina prima di 30 minuti, è molto probabile che si verifichino ThreadAbortException. Un approccio migliore sarebbe scoprire perché quell'endpoint HTTP non viene colpito, potrebbe richiedere VPN o un accesso limitato alla rete.
Amit Upadhyay,

6
@AmitUpadhyay Se la chiamata viene modificata await, nessun thread viene bloccato. Non il thread dell'interfaccia utente, non un thread threadpool altro thread in background, nessuno.
Todd Menier,

20

Ho riscontrato questo problema perché il mio Main()metodo non era in attesa del completamento dell'attività prima di tornare, quindi Task<HttpResponseMessage> myTaskè stato annullato all'uscita dal programma della console.

La soluzione era quella di chiamare myTask.GetAwaiter().GetResult()in Main()(da questa risposta ).


9

Un'altra possibilità è che il risultato non sia atteso dal lato client. Ciò può accadere se uno qualsiasi dei metodi nello stack di chiamate non utilizza la parola chiave wait per attendere il completamento della chiamata.


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

Quanto sopra è l'approccio migliore per l'attesa di una grande richiesta. Sei confuso circa 30 minuti; è tempo casuale e puoi dare tutto il tempo che vuoi.

In altre parole, la richiesta non attenderà 30 minuti se ottengono risultati prima di 30 minuti. 30 min significa che il tempo di elaborazione della richiesta è di 30 min. Quando si è verificato l'errore "L'attività è stata annullata" o requisiti di richiesta di dati di grandi dimensioni.


0

Un altro motivo può essere che se si esegue il servizio (API) e si inserisce un punto di interruzione nel servizio (e il codice è bloccato in corrispondenza di un punto di interruzione (ad esempio, la soluzione di Visual Studio mostra Debug anziché Esecuzione )). e quindi colpire l'API dal codice client. Quindi, se il codice di servizio viene messo in pausa su un punto di interruzione, premi F5 in VS.


0

Nella mia situazione, il metodo controller non è stato reso asincrono e il metodo chiamato all'interno del metodo controller era asincrono.

Quindi immagino sia importante usare asincrono / attendere fino al massimo livello per evitare problemi come questi.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.