我正在尝试在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
处断开(有时几个连续),并在status = Async.RunSynchronously
(async_value)。
如何解决异常问题,以便获取状态代码?另外,我需要上面做的类型吗?或者我错过了F#/ VS 2010 Beta 1的一些库/ dll,这已经是其中的一部分了?
我实际上使用Async.RunSynchronously
(Async.Parallel
(my_array_of_async_values))并行运行多个请求,但我认为这与我遇到的异常问题无关。
我遇到的例子只使用Async.Run
而不是Async.RunSynchronously
,这可能是我错过的一个指标... = /
答案 0 :(得分: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())
答案 1 :(得分: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"
}