6

我正在尝试在 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因为服务器返回了内部服务器错误 500。如果我继续执行,它会进入一个时髦的循环,在req.EndGetResponse(有时连续几个)和 let status = Async.RunSynchronously(async_value) 中断.

如何解决异常问题以便获取状态码?另外,我需要上面做的那种类型的事情吗?还是我错过了 F#/VS 2010 Beta 1 的一些库/dll,这已经是其中的一部分?

我实际上使用Async.RunSynchronouslyAsync.Parallel(my_array_of_async_values))并行运行了几个请求,尽管我认为这与我遇到的异常问题无关。

我遇到的示例仅使用Async.Run而不是Async.RunSynchronously可能表明我缺少某些东西的事实... =/

4

2 回答 2

3

它现在称为“AsyncGetResponse”(不再是“GetResponseAsync”)。并且“Run”被重命名为“RunSynchronously”。所以我认为您在这里没有遗漏任何实质性内容,只是在最新版本中进行了名称更改。

关于“Tools\Options\Debugging\General\Enable Just My Code”和“Debug\Exceptions”,您的调试器设置是什么(例如,设置为在抛出任何第一次机会 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())
于 2009-08-25T05:24:51.277 回答
1

您可以在 async 中使用 try...with 来捕获异常:

let async_value =
    async {
        let req = WebRequest.Create("http://unknown")
        try
            let! resp = req.AsyncGetResponse()
            return "success"
        with
        |   :? WebException as e -> return "failure"
    }
于 2009-09-01T02:29:05.187 回答