HttpClient
hat eine eingebaute Timeout-Funktion (obwohl alle asynchron sind, dh Timeouts können als orthogonal zur http-Anfrage-Funktionalität betrachtet werden und somit von generischen asynchronen Dienstprogrammen behandelt werden, aber das beiseite) und wenn das Timeout eintritt , wird es eine TaskCanceledException
(in einer AggregateException
verpackt) werfen.Unterscheiden Timeout von Benutzerunterdrückung
Das TCE enthält eine CancellationToken
, die CancellationToken.None
entspricht.
Nun, wenn ich HttpClient
mit einem CancellationToken
meiner eigenen liefern und verwenden, um den Vorgang abzubrechen, bevor sie beendet (oder mal aus), erhalte ich die exakt gleichen TaskCanceledException
, wieder mit einem CancellationToken.None
.
Gibt es noch eine Möglichkeit, nur in Ausnahme, geworfen suchen, ob ein Timeout die Anfrage abgebrochen, um herauszufinden, ohne dass meine eigene CancellationToken
zugänglich, um den Code zu machen, der die Ausnahme überprüft?
P.S. Könnte das ein Fehler sein und CancellationToken
wurde irgendwie falsch auf CancellationToken.None
behoben? In der , die mit benutzerdefinierten CancellationToken Fall abgebrochen wird, würde ich TaskCanceledException.CancellationToken
erwarten, diesem benutzerdefinierten Token zu entsprechen.
bearbeiten Um das Problem ein bisschen mehr klar zu machen, mit Zugang zum ursprünglichen CancellationTokenSource
, ist es einfach Timeout und Benutzer Löschung zu unterscheiden:
origCancellationTokenSource.IsCancellationRequested == wahr
Die CancellationToken
von der Ausnahme erhalten, gibt jedoch die falsche Antwort:
((TaskCanceledException) e.InnerException) .CancellationToken.IsCancellationRequested == falsch
Hier ein minimales Beispiel, wegen der großen Nachfrage:
public void foo()
{
makeRequest().ContinueWith(task =>
{
try
{
var result = task.Result;
// do something with the result;
}
catch (Exception e)
{
TaskCanceledException innerException = e.InnerException as TaskCanceledException;
bool timedOut = innerException != null && innerException.CancellationToken.IsCancellationRequested == false;
// Unfortunately, the above .IsCancellationRequested
// is always false, no matter if the request was
// cancelled using CancellationTaskSource.Cancel()
// or if it timed out
}
});
}
public Task<HttpResponseMessage> makeRequest()
{
var cts = new CancellationTokenSource();
HttpClient client = new HttpClient() { Timeout = TimeSpan.FromSeconds(10) };
HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "url");
passCancellationTokenToOtherPartOfTheCode(cts);
return client.SendAsync(httpRequestMessage, cts.Token);
}
Bitte senden Sie sich ein minimales Stück Code, das dieses Verhalten aufweist. –
Warum startet der Code nicht die Aufgabe, die die Ausnahme behandelt?Dieser Teil des Codes sollte bereits das CancellationToken haben, es könnte dieses Szenario verwalten und dann einfach die Ausnahme werfen, die Ihre höhere Ebene try/catch Block erhalten soll, ohne die TokenSource –
@FranciscoNoriega Manchmal möchten Sie Code, z. um es wiederverwendbar zu machen, und auch in asynchron ausgeführtem Code. Sie fangen also Ausnahmen an verschiedenen Stellen ab, an denen der Code ausgeführt wurde. Ich möchte nicht den ganzen Staat, der involviert ist, passieren müssen, besonders da die Ausnahme diesen Zustand zu liefern scheint, wenn es gebraucht wird - außer dass es nicht so funktioniert, wie ich es für richtig halten sollte. Schau dir das abgespeckte Beispiel an, das grob zeigt, wie ich es benutze. –