Await GetResponseAsync hält sich nicht an TimeOut

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 6 Antworten in diesem Thema. Der letzte Beitrag () ist von Dilbert.

    Await GetResponseAsync hält sich nicht an TimeOut

    Hi,

    ich rufe eine Webseite auf einem schnellen lokalen Server ab. Bei Fehlern dauert die Rückmeldung aber ewig.
    Bisher habe ich das mit einem Timeout von 800ms gut im Griff, aber die Anwendung "hängt" natürlich trotzdem kurz.
    Daher will ich das auf Async/Await umstellen, dann wird aber der Timeout nicht mehr berücksichtigt und bei Fehlern kommt die Rückmeldung wieder nach Ewigkeiten.

    Ohne Async klappt das prima:

    VB.NET-Quellcode

    1. Dim qt As String = ""
    2. Dim wr As Net.WebRequest = Net.WebRequest.Create("http://1.3.3.3") 'Gibt es nicht, soll ja einen Fehler produzieren...
    3. wr.Timeout = 800
    4. Dim response As Net.WebResponse = wr.GetResponse
    5. Using reader = New IO.StreamReader(DirectCast(response, Net.HttpWebResponse).GetResponseStream, System.Text.Encoding.UTF8)
    6. qt = reader.ReadToEnd()
    7. End Using
    8. Console.WriteLine(qt)


    Ändere ich die Zeile Nr. 4 (Dim response As Net.WebResponse = wr.GetResponse) auf

    VB.NET-Quellcode

    1. Dim response As Net.WebResponse = Await wr.GetResponseAsync

    muss ich viele lange Sekunden auf die Fehlermeldung warten.
    Was mache ich falsch? Oder gibt es Alternativen?
    ?(

    Bye,

    Dilbert
    Du machst nix falsch - man fragt sich echt, was die da machen bei MS - das muss man erstmal schaffen, so einen Bug einzubauen.

    Zum glück gibts Alternativen:

    VB.NET-Quellcode

    1. Private Async Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
    2. Dim qt As String = ""
    3. Dim wr As Net.WebRequest = Net.WebRequest.Create("http://1.3.3.3") 'Gibt es nicht, soll ja einen Fehler produzieren...
    4. wr.Timeout = 800
    5. Dim response As Net.WebResponse = Await Task.Run(Function() wr.GetResponse)
    6. Using reader = New IO.StreamReader(DirectCast(response, Net.HttpWebResponse).GetResponseStream, System.Text.Encoding.UTF8)
    7. qt = reader.ReadToEnd()
    8. End Using
    9. Console.WriteLine(qt)
    10. End Sub
    Das funktioniert aber nur wenn als Release kompiliert - weil Task.Run ist auch buggy, was die Behandlung nebenläufiger Exceptions angeht.
    In Async/Await: modaler IsBusy-Dialog, bis Nebenläufigkeit abgeschlossen verteile ich eine AsyncHelper-Klasse, die auch inne Debug-Version Exceptions korrekt behandelt.
    Hi,

    erstmal war ich beruhigt, dass ich nix gravierendes falsch mache, immerhin war's spät!
    Aber dann war ich beunruhigt, dass es nix besseres gibt außer 'nen Bug durch 'nen anderen zu ersetzen.

    Heute morgen bin ich über das gestolpert:

    VB.NET-Quellcode

    1. Dim client As New Net.Http.HttpClient ' Global machen...
    2. client.Timeout = New TimeSpan(0, 0, 1)
    3. Try
    4. Dim response As Net.Http.HttpResponseMessage = Await client.GetAsync("http://1.3.3.3")
    5. response.EnsureSuccessStatusCode()
    6. Dim qt As String = Await response.Content.ReadAsStringAsync()
    7. Console.WriteLine(qt)
    8. Catch ex As Exception
    9. Console.WriteLine(ex.Message)
    10. End Try


    Das sieht soweit recht gut aus, bin aber noch am testen ...
    Was ich nicht verstehe: was macht EnsureSuccessStatusCode?
    Das knallt, wenn es einen Fehler zurück bekommen hat.
    Aber tut es das nicht eine Zeile später sowieso?!?

    Bye,

    Dilbert
    Einmal HttpResponseMessage in Google eingegeben, und ein kurzer Blick in die Dokumentation zeigt:
    Dass EnsureSuccessStatusCode() eine Exception wirft, wenn von der Gegenstelle ein anderer ResponseCode als 200 OK ankommt. Praktischerweise wird die Instanz von HttpResponseMessage auch gleich disposed. Zumindest bis .NET Core 2.2 (also einschließlich .NET FX bis 4.8)
    Hi,

    ja, die Doku hab' ich gelesen, aber was ich nicht verstehe, warum er dort eine Exception werfen SOLLTE?
    Denn die Exception kommt bei Fehlern ja eine Zeile darunter sowieso.
    Ich sehe dann einen Vorteil, wenn danach nichts anderes mehr gemacht werden soll, ich aber einen Status sehen will?
    Und vielleicht dass die HttpResponseMessage gleich disposed wird.
    Oder gibt es andere Gründe dafür?
    Lasse ich die Zeile weg, klappt es jedenfalls genauso mit den gleichen Exceptions.

    Bye,

    Dilbert
    Hi,

    OK, wenn der Content bei Fehler 404 (oder 418 :D ) geliefert wird, ... stimmt, das könnte sein.
    Ich nehm' das mal so hin.
    Aber selbst dann lässt sich der Status einfach abfragen und man bekommt seine Fehlernummer, das finde ich 1000 mal eleganter als ihn in eine Exception rennen zu lassen.

    Aber viel wichtiger:
    ES GEHT!
    Ich hab's gründlich getestet und es geht!
    Wer also in Zukunft async Webseiten abrufen will, vergesst den Webclient, vergesst WebRequest,
    besser ist der Net.Http.HttpClient !

    Für alle die's wollen hier nochmal der komplette Code:

    VB.NET-Quellcode

    1. Async Sub HoleWebDaten()
    2. Dim client As New Net.Http.HttpClient ' Sollte man aus Ressourcen-Schonungs-Gründen global machen... (braucht sonst viele System-Sockets)
    3. client.Timeout = New TimeSpan(0, 0, 1) ' Hiermit geht das natürlich auch Millisekunden genau
    4. Try
    5. Dim response As Net.Http.HttpResponseMessage = Await client.GetAsync("http://1.3.3.3")
    6. response.EnsureSuccessStatusCode() ' nur in seltenen Fällen sinnvoll, klappt hervorragend auch OHNE diese Zeile
    7. Dim QuellText As String = Await response.Content.ReadAsStringAsync()
    8. Console.WriteLine(QuellText) ' Ergebnis ausgeben
    9. Catch ex As Exception
    10. Console.WriteLine(ex.Message) ' Fehler ausgeben
    11. End Try
    12. End Sub


    Dann schließe ich das Thema mal ab...

    Bye,

    Dilbert