HttpClient - Eine Aufgabe wurde abgebrochen?

191

Es funktioniert einwandfrei, wenn eine oder zwei Aufgaben vorhanden sind. Es wird jedoch der Fehler "Eine Aufgabe wurde abgebrochen" ausgegeben, wenn mehr als eine Aufgabe aufgelistet ist.

Geben Sie hier die Bildbeschreibung ein

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
quelle
Was sagt die innere Ausnahme?
RagtimeWilly
1
Warum nehmen Sie einen CancellationTokenals Parameter und verwenden ihn nicht?
Jim Aho
1
Der Grund für mich war versehentlich zu entsorgen HttpClient, zBasync Task<HttpResponseMessage> Method(){ using(var client = new HttpClient()) return client.GetAsync(request); }
JobaDiniz
3
Für diejenigen, die HttpClientwie @JobaDiniz (mit einem using()) verwenden, hören Sie bitte auf! Der Grund: aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong
Philippe

Antworten:

271

Es gibt zwei wahrscheinliche Gründe, warum ein TaskCanceledExceptiongeworfen wird:

  1. Etwas, das Cancel()auf dem CancellationTokenSourcemit dem Stornierungstoken verknüpften Token aufgerufen wurde, bevor die Aufgabe abgeschlossen wurde.
  2. Die Anforderung ist abgelaufen, dh sie wurde nicht innerhalb der von Ihnen angegebenen Zeitspanne abgeschlossen HttpClient.Timeout.

Ich vermute, es war eine Auszeit. (Wenn es sich um eine explizite Stornierung handelte, hätten Sie das wahrscheinlich herausgefunden.) Sie können sicherer sein, indem Sie die Ausnahme überprüfen:

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
quelle
3
Was ist also eine mögliche Lösung? Ich habe ein ähnliches Problem. stackoverflow.com/questions/36937328/…
Entwickler
48
@ Dimi - das ist ziemlich alt, aber die Lösung, die ich verwendet habe, war, die Timeout-Eigenschaft auf einen größeren Wert zu setzen:httpClient.Timeout = TimeSpan.FromMinutes(30)
RQDQ
2
@RQDQ, du der Mann, Mann! Das Nicht-Verwenden des Konstruktors löste das Problem für mich. In meinem speziellen Fall wollte ich eine Zeitüberschreitung in Millisekunden. Verwenden TimeSpan.FromMilliseconds(Configuration.HttpTimeout)im Gegensatz zu new TimeSpan(Configuration.HttpTimeout)einem Leckerbissen gearbeitet. Vielen Dank!
Victor Ude
6
@RQDQ httpClient.Timeout = TimeSpan.FromMinutes(30)ist kein guter Ansatz, da es diesen bestimmten Thread 30 Minuten lang blockiert und auch den HTTP-Endpunkt (der Ihre Hauptaufgabe ist) nicht erreicht. Wenn Ihr Programm vor 30 Minuten beendet ist, ist es am wahrscheinlichsten, dass Sie darauf stoßen ThreadAbortException. Ein besserer Ansatz wäre, herauszufinden, warum dieser HTTP-Endpunkt nicht getroffen wird. Möglicherweise ist ein VPN oder ein eingeschränkter Netzwerkzugriff erforderlich.
Amit Upadhyay
6
@AmitUpadhyay Wenn der Anruf bearbeitet wird await, wird kein Thread blockiert. Nicht der UI-Thread, kein Threadpool-Thread anderer Hintergrund-Thread, keiner.
Todd Menier
20

Ich bin auf dieses Problem gestoßen, weil meine Main()Methode nicht darauf gewartet hat, dass die Aufgabe abgeschlossen ist, bevor sie zurückkehrt. Daher wurde die Aufgabe Task<HttpResponseMessage> myTaskabgebrochen, als mein Konsolenprogramm beendet wurde.

Die Lösung wurde nennen myTask.GetAwaiter().GetResult()in Main()(aus dieser Antwort ).

Ben Hutchison
quelle
9

Eine andere Möglichkeit besteht darin, dass das Ergebnis auf der Client-Seite nicht erwartet wird. Dies kann passieren, wenn eine Methode im Aufrufstapel das Schlüsselwort await nicht verwendet, um auf den Abschluss des Aufrufs zu warten.

Manish
quelle
7
var clientHttp = new HttpClient();
clientHttp.Timeout = TimeSpan.FromMinutes(30);

Das Obige ist der beste Ansatz, um auf eine große Anfrage zu warten. Sie sind ungefähr 30 Minuten verwirrt; Es ist zufällige Zeit und Sie können jede Zeit geben, die Sie wollen.

Mit anderen Worten, die Anfrage wartet nicht 30 Minuten, wenn sie Ergebnisse vor 30 Minuten erhält. 30 min bedeutet, dass die Bearbeitungszeit für Anfragen 30 min beträgt. Wenn der Fehler "Aufgabe wurde abgebrochen" oder Anforderungen für große Datenanforderungen aufgetreten sind.

Navdeep Kapil
quelle
0

Ein weiterer Grund kann sein, dass Sie den Dienst (API) ausführen und einen Haltepunkt in den Dienst einfügen (und Ihr Code an einem Haltepunkt hängen bleibt (z. B. zeigt die Visual Studio-Lösung Debugging anstelle von Ausführen an )). und dann die API aus dem Client-Code treffen. Wenn der Service-Code an einem Haltepunkt angehalten wurde, drücken Sie in VS einfach F5.

vivek nuna
quelle
0

In meiner Situation wurde die Controller-Methode nicht als asynchron ausgeführt, und die innerhalb der Controller-Methode aufgerufene Methode war asynchron.

Ich denke, es ist wichtig, async / await bis zur obersten Ebene zu verwenden, um solche Probleme zu vermeiden.

chaitanyasingu
quelle