2009-08-25 10 views
5

Próbuję użyć asynchronicznych przepływów pracy w F #, aby pobrać kilka żądań internetowych.F # asynchroniczne żądanie sieciowe, obsługa wyjątków

Jednak niektóre z moich żądań są czasami zwróconymi błędami (np. Http 500) i nie wiem, jak sobie z tym poradzić. Wygląda na to, że mój program F # utknął w nieskończonej pętli podczas działania w debugerze.

Prawdopodobnie brakuje mi niektórych rzeczy, bo przykłady, które widziałem, nie zostały skompilowane po wyjęciu z pudełka. Pierwszą rzeczą, jaką okazało się, że było to trochę pomogło kodu:

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

a potem mam bitowy kod, aby pobrać wnioski, co jest dość standardowy z przykładów widziałem:

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

a następnie staram się uzyskać wynik:

let status = Async.RunSynchronously(async_value) 

Ale gdy uruchomię mój program w debugger, to rozkłada się req.EndGetResponse ponieważ serwer zwrócił wewnętrzny błąd serwera 500. Gdybym tylko utrzymać stałą wykonanie dane Wchodzi w funky loop, łamiąc na req.EndGetResponse (czasami kilka z rzędu), a na status = Async.RunSynchronously niech (async_value).

Jak obejść problem wyjątku, aby uzyskać kod statusu? Poza tym, czy potrzebuję czegoś, co zrobiłem powyżej? Czy może brakuje mi biblioteki/biblioteki dll dla F #/VS 2010 Beta 1, której jest już częścią?

Właściwie uruchamiam kilka żądań równolegle, używając Async.RunSynchronously (Async.Parallel (my_array_of_async_values)), ale nie sądzę, że jest to związane z problemem wyjątku, który mam.

Fakt przykłady Natknąłem używać tylko Async.Run zamiast Async.RunSynchronously jest prawdopodobnie wskaźnikiem Ja czegoś brakuje ... =/

Odpowiedz

2

to teraz nazywa się „AsyncGetResponse” (nie „GetResponseAsync”) . Nazwa "Run" została zmieniona na "RunSynchronously". Więc nie sądzę, że brakuje ci czegoś istotnego tutaj, tylko wymień zmiany w najnowszym wydaniu.

Jakie są twoje ustawienia debuggera w odniesieniu do "Narzędzia \ Opcje \ Debugowanie \ Ogólne \ Włącz tylko mój kod" i "Debugowanie \ Wyjątki" (np. Ustawione na rozbijanie, gdy zgłaszany jest wyjątek CLR pierwszej szansy)? Nie jestem pewien, czy twoje pytanie dotyczy zachowania programu, czy zachowania narzędzi VS (brzmi jak to drugie). Jest to dodatkowo utrudnione faktem, że punkty końcowe/debugowanie "lokalizacji" w F # Beta1 mają pewne błędy, szczególnie w odniesieniu do przepływu pracy asynchronicznej, co oznacza, że ​​zachowanie widoczne w debugerze może wyglądać trochę dziwnie, nawet jeśli program jest wykonywany prawidłowo.

Czy używasz VS2008 CTP lub VS2010 Beta1?

W każdym przypadku wygląda na to, że wyjątek ze względu na odpowiedź 500 jest oczekiwany, tak działa WebRequest. Oto krótki program demo:

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

Tak, widzę, co zrobiłem źle. Było to również zachowanie częściowe (vers2010b1) dotyczące wyjątkowych błędów debugowania. Próbowałem po prostu uzyskać kod stanu, jedyną część odpowiedzi, o którą się troszczyłem, bez obsługi wyjątku. – jessicah

1

Można użyć try ... z wewnątrz async złapać wyjątki:

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