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.RunSynchronously私は実際に( (my_array_of_async_values))を使用して複数のリクエストを並行して実行Async.Parallelしていますが、それが私が抱えている例外の問題に関連しているとは思いません。

私が遭遇した例は、おそらく何かが欠けている指標では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# ベータ 1 のブレークポイント/デバッグの「場所」に、特に非同期ワークフローに関していくつかのバグがあるという事実によってさらに混乱します。つまり、プログラムが正常に実行されている場合でも、デバッガーで表示される動作が少し奇妙に見える場合があります。 .

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 に答える