2009-08-25 8 views
5

Ich versuche Async-Workflows in F # zu verwenden, um mehrere Webanforderungen abzurufen.F # asynchrone Webanforderung, die Ausnahmen behandelt

Einige meiner Anfragen geben jedoch gelegentlich Fehler (z. B. http 500), und ich weiß nicht, wie Sie damit umgehen. Es scheint, als ob mein F # -Programm in einer Endlosschleife stecken bleibt, wenn es im Debugger läuft.

Ich vermisse wahrscheinlich einige Sachen, weil Beispiele, die ich gesehen habe, nicht aus der Box kompilieren. Das erste, was ich gefunden, die half, war dieses Stück Code:

type System.Net.WebRequest with 
    member req.GetResponseAsync() = 
    Async.BuildPrimitive(req.BeginGetResponse, req.EndGetResponse) 

und dann habe ich mein Stück Code, um die Anforderungen zu holen, die aus den Beispielen ist ziemlich Standard ich gesehen habe:

let async_value = async { 
    let req = WebRequest.Create(url) 
    let! rsp = req.GetResponseAsync() 
    return (rsp :?> HttpWebResponse).StatusCode 
} 

und dann versuche ich das Ergebnis zu erhalten:

let status = Async.RunSynchronously(async_value) 

Aber wenn ich mein Programm in Debugger ausführen, bricht es bei req.EndGetResponse weil Server interne Serverfehler zurückgegeben 500. Wenn ich einfach fort Execu Es kommt in eine funky Schleife, brechen bei req.EndGetResponse (manchmal mehrere in einer Reihe), und lassen Sie status = Async.RunSynchronously (async_value).

Wie kann ich das Ausnahmeproblem umgehen, damit ich meinen Statuscode bekommen kann? Brauche ich auch die Art, die ich oben getan habe? Oder fehlt mir eine Bibliothek/DLL für F #/VS 2010 Beta 1, von der dies bereits ein Teil ist?

Ich tatsächlich mehrere Anfragen parallel laufen, mit Async.RunSynchronously (Async.Parallel (my_array_of_async_values)), obwohl ich glaube nicht, dass das mit der Ausnahme Problem, das ich habe.

Die Tatsache, die Beispiele, die ich über nur Async.Run anstatt Async.RunSynchronously verwenden gekommen ist wahrscheinlich ein Indikator ich etwas fehlt bin ... =/

Antwort

2

Es ist jetzt ‚AsyncGetResponse‘ (nicht mehr ‚GetResponseAsync‘) genannt . Und "Ausführen" wurde in "RunSynchronously" umbenannt. Ich glaube also nicht, dass Sie etwas Wesentliches vermissen, nur Namensänderungen in der neuesten Version.

Was sind Ihre Debugger-Einstellungen in Bezug auf "Extras \ Optionen \ Debuggen \ Allgemein \ Nur Code aktivieren" und "Debug \ Ausnahmen" (z. B. gesetzt, um zu brechen, wenn eine CLR-Ausnahme der ersten Chance ausgelöst wird oder nicht)? Ich bin unklar, ob Ihre Frage das Programmverhalten oder das VS-Werkzeugverhalten betrifft (klingt wie letzteres). Dies wird noch durch die Tatsache verwirrt, dass Breakpoints/Debugging 'locations' in F # Beta1 einige Bugs haben, besonders in Bezug auf Async-Workflows, was bedeutet, dass das Verhalten im Debugger etwas seltsam aussieht, selbst wenn das Programm korrekt ausgeführt wird. .

Verwenden Sie VS2008 CTP oder VS2010 Beta1?

In jedem Fall scheint die Ausnahme aufgrund einer 500 Antwort erwartet wird, so funktioniert WebRequest. Hier ist ein kurzes Demo-Programm:

open System 
open System.ServiceModel 
open System.ServiceModel.Web 

[<ServiceContract>] 
type IMyContract = 
    [<OperationContract>] 
    [<WebGet(UriTemplate="/Returns500")>] 
    abstract Returns500 : unit -> unit 
    [<OperationContract>] 
    [<WebGet(UriTemplate="/Returns201")>] 
    abstract Returns201 : unit -> unit 

type MyService() = 
    interface IMyContract with 
     member this.Returns500() = 
      WebOperationContext.Current.OutgoingResponse.StatusCode <- 
       System.Net.HttpStatusCode.InternalServerError 
     member this.Returns201() = 
      WebOperationContext.Current.OutgoingResponse.StatusCode <- 
       System.Net.HttpStatusCode.Created 

let addr = "http://localhost/MyService" 
let host = new WebServiceHost(typeof<MyService>, new Uri(addr)) 
host.AddServiceEndpoint(typeof<IMyContract>, new WebHttpBinding(), "") |> ignore 
host.Open() 

open System.Net 

let url500 = "http://localhost/MyService/Returns500" 
let url201 = "http://localhost/MyService/Returns201" 
let async_value (url:string) = 
    async { 
     let req = WebRequest.Create(url) 
     let! rsp = req.AsyncGetResponse() 
     return (rsp :?> HttpWebResponse).StatusCode 
    } 
let status = Async.RunSynchronously(async_value url201) 
printfn "%A" status 
try 
    let status = Async.RunSynchronously(async_value url500) 
    printfn "%A" status 
with e -> 
    printfn "%s" (e.ToString()) 
+0

Ja, ich sehen, was ich falsch gemacht hatte. Es war auch Teil Tooling-Verhalten (vs2010b1) in Bezug auf die Exception Debugging Seltsamkeit. Ich hatte versucht, nur den StatusCode zu bekommen, der einzige Teil der Antwort, der mir sogar wichtig war, ohne die Ausnahme zu behandeln. – jessicah

1

Sie verwenden versuchen ... mit innerhalb der Asynchron-Ausnahmen zu fangen:

let async_value = 
    async { 
     let req = WebRequest.Create("http://unknown") 
     try 
      let! resp = req.AsyncGetResponse() 
      return "success" 
     with 
     | :? WebException as e -> return "failure" 
    } 
Verwandte Themen