2009-08-25 13 views
5

Sto provando a utilizzare i flussi di lavoro asincroni in F # per recuperare diverse richieste web.Richiesta web asincrona F #, gestione delle eccezioni

Tuttavia, alcune delle mie richieste occasionalmente restituiscono errori (ad esempio http 500) e non so come gestirlo. Sembra che il mio programma F # rimanga bloccato in un ciclo infinito durante l'esecuzione nel debugger.

Probabilmente mi mancano alcune cose, perché gli esempi che ho visto non sono stati compilati immediatamente. La prima cosa che ho trovato che ha aiutato è stato questo pezzo di codice:

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

e poi ho la mia parte di codice per prendere le richieste, che è abbastanza standard da esempi che ho visto:

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

e poi cerco di ottenere il risultato:

let status = Async.RunSynchronously(async_value) 

Ma quando eseguo il mio programma nel debugger, si rompe a causa req.EndGetResponse server ha restituito errore interno del server 500. Se continuo solo continuare execu zione, entra in un loop funky, rompendo a req.EndGetResponse (a volte più di una riga), e a lasciare status = Async.RunSynchronously (async_value).

Come posso risolvere il problema di eccezione in modo da poter ottenere il mio codice di stato? Inoltre, ho bisogno del tipo di cosa che ho fatto sopra? O mi manca qualche libreria/dll per F #/VS 2010 Beta 1, di cui questa è già una parte?

Io in realtà gestiscono diverse richieste in parallelo, utilizzando Async.RunSynchronously (Async.Parallel (my_array_of_async_values)), anche se non credo che è legato alla questione eccezione che sto avendo.

Il fatto gli esempi che ho incontrato solo per uso Async.Run piuttosto che Async.RunSynchronously è probabilmente un indicatore che mi manca qualcosa ... =/

risposta

2

E adesso si chiama 'AsyncGetResponse' (non piu 'GetResponseAsync') . E 'Run' è stato rinominato in 'RunSynchronously'. Quindi non penso che qui manchi qualcosa di sostanziale, basta nominare le modifiche nell'ultima versione.

Quali sono le impostazioni del debugger relative a "Strumenti \ Opzioni \ Debug \ Generale \ Abilita solo il mio codice" e "Debug \ Eccezioni" (ad es. Impostato per interrompere quando viene generata o esclusa un'eccezione CLR di prima scelta)? Non sono chiaro se la tua domanda riguarda il comportamento del programma, o il comportamento degli strumenti VS (suona come quest'ultimo). Ciò è ulteriormente confuso dal fatto che i breakpoint/debug di "location" in F # Beta1 hanno alcuni bug, specialmente riguardo i flussi di lavoro asincroni, il che significa che il comportamento che si vede nel debugger può sembrare un po 'strano anche se il programma è in esecuzione correttamente.

Si sta utilizzando VS2008 CTP o VS2010 Beta1?

In ogni caso, sembra che l'eccezione dovuta a una risposta 500 sia prevista, è così che funziona WebRequest. Ecco un breve programma 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

Sì, vedo quello che avevo fatto di sbagliato. Era anche il comportamento degli strumenti di parte (vs2010b1) per quanto riguarda le eccezioni di debugging. Avevo tentato di ottenere solo lo StatusCode, l'unica parte della risposta di cui mi preoccupavo, senza gestire l'eccezione. – jessicah

1

È possibile utilizzare provare ... con dentro l'asincrono per intercettare le eccezioni:

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