2012-10-01 10 views
24

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); 
} 
+0

Bitte senden Sie sich ein minimales Stück Code, das dieses Verhalten aufweist. –

+0

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 –

+1

@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. –

Antwort

4

Ja, sie beide geben die selbe Ausnahme zurück (möglicherweise wegen des Zeitlimits, das intern auch ein Token verwendet), aber es kann leicht dadurch herausgefunden werden:

catch (OperationCanceledException ex) 
      { 
       if (token.IsCancellationRequested) 
       { 
        return -1; 
       } 

       return -2; 
      } 

so im Grunde, wenn Sie die Ausnahme, aber Ihr Token getroffen wird nicht abgebrochen, und es

+0

Ich habe ** gemacht, indem ich nur auf die Ausnahme geschaut habe ** in meiner Frage fett und hinzugefügt ein bisschen mehr Details, um es klarer zu machen, was ich frage. –

+0

'OperationCanceledException' wird auch ausgelöst, wenn der' HttpClient' entsorgt wird, während die Anforderung aussteht, oder wenn 'HttpClient.CancelPendingRequests' aufgerufen wird. Diese Fälle können unterschieden werden, wenn Sie die Aufrufe dieser Methoden steuern. – Ernesto

+0

diese antwort fehlt details ... woher kommt 'token'? Ist es eine Eigenschaft der Ausnahme? Downvoting, bis Sie es verbessern – ympostor

5

Die akzeptierte Antwort ist sicherlich, wie diese sollte Arbeit in der Theorie, aber leider in der Praxis IsCancellationRequested tut eine regelmäßige http Timeout war nicht (zuverlässig) auf dem Token gesetzt bekommen, der Ausnahme angebracht ist:

Cancelling an HttpClient Request - Why is TaskCanceledException.CancellationToken.IsCancellationRequested false?

+0

Sie können das angehängte Token möglicherweise nicht verwenden, aber wenn Sie das ursprüngliche Token haben (das an 'SendAsync' übergeben wurde), können Sie das verwenden. Oder fehlt mir etwas? –

+0

Ich sehe, ich vermisse, dass die Frage erforderlich nur auf die Ausnahme Daten angewiesen ist. –

Verwandte Themen