Ich möchte CancellationToken
verwenden, um einen Aufruf von HttpClient.PostAsJsonAsync
abzubrechen. Mit dem folgenden Setup hängt der Aufruf von PostAsJsonAsync
jedoch unbegrenzt (ich habe ihn für einige Minuten laufen lassen).
Beachten Sie, dass ich ein bereits abgebrochenes CancellationTokenSource
übergebe - ich habe das gleiche Problem, wenn ich das Token mit Task.Delay
mit einer kurzen Verzögerung abbreche.
Ich weiß, ich könnte einfach überprüfen, ob das Token vor dem Aufruf abgebrochen wurde, aber trotzdem habe ich das gleiche Problem, wenn das Token nach einer kurzen Verzögerung abgebrochen wird, dh es wird nicht vor dem Methodenaufruf abgebrochen, sondern wird so kurz danach.
Meine Frage ist also, was verursacht das und was kann ich tun, um es zu umgehen / reparieren?
Bearbeiten
Für diejenigen, die nach einem Workaround suchen, der von @Darrel Millers Antwort inspiriert wurde, habe ich die folgende Erweiterungsmethode entwickelt:
%Vor%Es scheint definitiv ein Fehler zu sein, den Sie treffen. Sie können umgehen, indem Sie das HttpContent / ObjectContent-Objekt selbst konstruieren, so wie dies.
%Vor% Der Aufruf von content.LoadIntoBufferAsync
erzwingt die Deserialisierung vor dem PostAsync und scheint den Deadlock zu vermeiden.
Stimmen Sie der Antwort von @Darrel Miller zu. Dies ist ein Fehler. Fügen Sie einfach mehr Details für den Fehlerbericht hinzu.
Das Problem ist, dass intern ein TaskCompletionSource
verwendet wird, aber wenn eine Ausnahme aufgrund der Stornierung in diesem speziellen Fall ausgelöst wird, wird es nicht abgefangen, und der TaskCompletionSource
wird nie in einen der abgeschlossenen Zustände gesetzt ( und daher wird das Warten auf die TaskCompletionSource
Task
niemals zurückkehren.
Wenn Sie ILSpy verwenden und HttpClientHandler.SendAsync
betrachten, sehen Sie TaskCompletionSource
:
Später, durch die Zeile Task.Factory.StartNew(this.startRequest, requestState);
, kommen wir zur folgenden Methode:
Sie werden feststellen, dass der Delegat im Aufruf von ContinueWithStandard
keine Ausnahmebehandlung innerhalb des Delegaten hat, und niemand hält sich an der zurückgegebenen Aufgabe fest (und wenn diese Aufgabe daher eine Ausnahme auslöst, wird sie ignoriert). Der Aufruf von this.StartGettingRequestStream(state);
löst eine Ausnahme aus:
Hier ist der vollständige Callstack zum Zeitpunkt der Ausnahme:
%Vor% Ich glaube, die Absicht ist es nicht zu ignorieren, und im Falle einer Ausnahme rufen Sie die Methode HandleAsyncException
auf, die TaskCompletionSource
in einen endgültigen Zustand versetzt.
Tags und Links c# task-parallel-library dotnet-httpclient cancellationtokensource