简体   繁体   English

F#异步Web请求,处理异常

[英]F# async web request, handling exceptions

I'm trying to use async workflows in F# to fetch several web requests. 我正在尝试在F#中使用异步工作流来获取多个Web请求。

However, some of my requests are occasionally returning errors (eg http 500), and I don't know how to handle this. 但是,我的一些请求偶尔会返回错误(例如http 500),我不知道如何处理这个问题。 It appears like my F# program gets stuck in an infinite loop when running in the debugger. 看起来我的F#程序在调试器中运行时陷入无限循环。

I'm probably missing some stuff, cause examples I seen didn't compile out of the box. 我可能错过了一些东西,因为我看到的例子没有开箱即用。 First thing I found that helped was this bit of code: 我找到的第一件事就是帮助了这段代码:

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

and then I have my bit of code to fetch the requests, which is pretty standard from examples I've seen: 然后我有一些代码来获取请求,这是我见过的例子中非常标准的:

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

and then I try to get the result: 然后我试着得到结果:

let status = Async.RunSynchronously(async_value)

But when I run my program in debugger, it breaks at req.EndGetResponse because server returned internal server error 500. If I keep just continuing execution, it gets in a funky loop, breaking at req.EndGetResponse (sometimes several in a row), and at let status = Async.RunSynchronously (async_value). 但是当我在调试器中运行我的程序时,它在req.EndGetResponse中断,因为服务器返回内部服务器错误500.如果我继续执行,它会进入一个时髦的循环,在req.EndGetResponse (有时连续几个)中断,和at status = Async.RunSynchronously (async_value)。

How do I get around the exception problem so I can get my status code? 如何解决异常问题以便获取状态代码? Also, do I need the type thing I did above? 另外,我需要上面做的类型吗? Or am I missing some library/dll for F#/VS 2010 Beta 1, of which this is already a part of? 或者我错过了F#/ VS 2010 Beta 1的一些库/ dll,其中这已经是其中的一部分了?

I actually run several requests in parallel, using Async.RunSynchronously ( Async.Parallel (my_array_of_async_values)), though I don't think that is related to the exception issue I'm having. 我实际上使用Async.RunSynchronouslyAsync.Parallel (my_array_of_async_values))并行运行多个请求,尽管我认为这与我遇到的异常问题无关。

The fact the examples I've come across only use Async.Run rather than Async.RunSynchronously is probably an indicator I'm missing something... =/ 事实上我遇到的例子只使用Async.Run而不是Async.RunSynchronously可能是一个指标,我错过了一些东西...... = /

It's now called 'AsyncGetResponse' (no longer 'GetResponseAsync'). 它现在被称为'AsyncGetResponse'(不再是'GetResponseAsync')。 And 'Run' was renamed to 'RunSynchronously'. 并且'Run'被重命名为'RunSynchronously'。 So I don't think you're missing anything substantial here, just name changes in the latest release. 所以我不认为你在这里遗漏任何实质内容,只是在最新版本中命名更改。

What are your debugger settings with regard to "Tools\\Options\\Debugging\\General\\Enable Just My Code" and "Debug\\Exceptions" (eg set to break when any first-chance CLR exception is thrown or not)? 关于“Tools \\ Options \\ Debugging \\ General \\ Enable Just My Code”和“Debug \\ Exceptions”的调试器设置是什么(例如,当抛出任何第一次机会CLR异常时设置为中断)? I am unclear if your question involves the program behavior, or the VS tooling behavior (sounds like the latter). 我不清楚你的问题是否涉及程序行为或VS工具行为(听起来像后者)。 This is further confounded by the fact that breakpoint/debugging 'locations' in F# Beta1 have some bugs, especially regarding async workflows, which means that the behavior you see in the debugger may look a little strange even if the program is executing properly... F#Beta1中的断点/调试“位置”存在一些错误,特别是对于异步工作流,这进一步使这一点更加困惑,这意味着即使程序正常执行,您在调试器中看到的行为可能看起来有点奇怪。 。

Are you using VS2008 CTP or VS2010 Beta1? 您使用的是VS2008 CTP还是VS2010 Beta1?

In any case, it appears the exception due to a 500 response is expected, this is how WebRequest works. 在任何情况下,由于预期500响应,它似乎是异常,这就是WebRequest的工作方式。 Here's a short demo program: 这是一个简短的演示程序:

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())

You can use try...with inside the async to catch exceptions: 您可以在异步内部使用try ...来捕获异常:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM