2009-08-25 316 views
5

我試圖使用異步工作流在F#中獲取一些Web請求。F#異步Web請求,處理異常

不過,我的一些要求偶爾會返回錯誤(例如HTTP 500),我不知道該如何處理這個問題。看起來像我的F#程序在調試器中運行時陷入了無限循環。

我可能錯過了一些東西,造成的例子,我看到沒有編譯開箱。第一件事,我發現,幫助了這段代碼:

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

,然後我有我的碼位獲取的要求,這是從例子很標準我看到:

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

然後我試圖得到的結果:

let status = Async.RunSynchronously(async_value) 

但是當我在調試器中運行我的程序,它在req.EndGetResponse打破,因爲服務器如果我只保留繼續execu返回內部服務器錯誤500。重刑,它得到的一個時髦的循環,在req.EndGetResponse突破(有時連續幾個),並讓status = Async.RunSynchronously(async_value)。

如何得到解決異常問題,所以我可以得到我的狀態代碼?另外,我是否需要上述類型的東西?或者我錯過了一些F#/ VS 2010 Beta 1的庫/ dll,其中這已經是其中的一部分了?

我實際上並行運行多個請求,使用Async.RunSynchronouslyAsync.Parallel(my_array_of_async_values)),雖然我不認爲這與我遇到的異常問題有關。

我遇到只例子使用Async.Run而不是Async.RunSynchronously,原因可能是我想的東西的指標... =/

回答

2

它現在被稱爲「AsyncGetResponse」(不再是「GetResponseAsync」) 。並且「運行」被重命名爲「RunSynchronously」。所以我不認爲你在這裏錯過了任何實質性的東西,只是在最新版本中改名。

對於「工具\選項\調試\常規\啓用只是我的代碼」和「調試\例外」(例如,在任何第一次機會的CLR異常被拋出時設置爲中斷),您的調試器設置是什麼?我不清楚你的問題是否涉及程序行爲或VS工具行爲(聽起來像後者)。這是一個事實,即在F#Beta1中斷點/調試「位置」有一些錯誤,特別是關於異步工作流程,這意味着你在調試器中看到的行爲可能看起來即使程序正確執行有點奇怪進一步混淆.. 。

您正在使用VS2008 CTP或VS2010 Beta1的?

在任何情況下,它出現異常,由於500響應的預期,這是WebRequest的是如何工作的。下面是一個簡短的演示程序:

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

是的,我明白我做了什麼錯。這也是部分工具行爲(vs2010b1)關於異常調試怪異的一部分。 我曾試圖獲取StatusCode,這是我甚至關心的唯一一部分響應,無需處理異常。 – jessicah 2009-09-09 03:47:26

1

你可以使用try ...與異步內捕獲異常:

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