2009-08-25 183 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" 
    }