LoginSignup
1
0

More than 3 years have passed since last update.

FSharpDataでのWebExceptionの取り扱い

Last updated at Posted at 2019-08-03

要旨

FSharpDataのタイププロバイダの提供するLoad関数(以下FsDataのLoad)が投げるWebExceptionからHTTPステータスコードを確認する場合、ResponseをHttpWebResponseにキャストすることはできず、InnerExceptionのResponseをキャストして確認する必要がある。

検証の準備

404ページにアクセスして例外を投げる以下の2つのタスクを用いる

common.fsx
#load ".paket/load/netcoreapp2.2/main.group.fsx"

open System.Net
open FSharp.Data

type ExampleProvider = JsonProvider<"""{"a": 1, "b": "kamome283"}""">

let url = "https://www.wwf.or.jp/404"

// HttpWebRequestを用いたタスク
let HttpWebRequestTask =
    async {
        printfn "HttpWebRequestの場合"
        HttpWebRequest.Create(url).GetResponse() |> ignore
    }

// FsDataのLoadを用いたタスク
let FsharpDataTask =
    async {
        printfn "FSharpDataのLoadの場合"
        ExampleProvider.Load url |> ignore
    }

検証1

以下のようにどちらもWebExceptionを投げていることがわかる。

ex1.fsx
#load "./common.fsx"

let execute a =
    try
        Async.RunSynchronously a
    with ex ->
        printfn "%A" (ex.GetType())
        printfn "--------------------"

[ Common.HttpWebRequestTask; Common.FsharpDataTask ] |> List.map execute
出力
HttpWebRequestの場合
System.Net.WebException
--------------------
FSharpDataのLoadの場合
System.Net.WebException
--------------------

検証2

以下のようにFsDataのLoadが投げる例外はもとの例外をWebExceptionでくるんでいるようだ。
くるんだWebExceptionのResponseをHttpWebResponseにキャストすることはできないようなので、
InnerExceptionのResponseをキャストする必要がある。

ex2.fsx
#load "./common.fsx"

open System.Net

let execute a =
    try
        try
            Async.RunSynchronously a |> ignore
        with
        | :? WebException as ex when (ex.Response :? HttpWebResponse) ->
            printfn "WebExceptionでResponseをHttpWebResponseにキャスト可能"
            let res = ex.Response :?> HttpWebResponse
            printfn "%iエラー" <| int res.StatusCode
            printfn "InnerExceptionは%A" ex.InnerException
        | :? WebException as ex when ex.InnerException :? WebException
                                     && ((ex.InnerException :?> WebException).Response :? HttpWebResponse) ->
            printfn
                "WebExceptionでResponseをHttpWebResponseにキャスト可能ではないが、InnerExceptionはキャスト可能"
            let res =
                (ex.InnerException :?> WebException).Response :?> HttpWebResponse
            printfn "%iエラー" <| int res.StatusCode
            printfn "InnerExceptionは%A" <| ex.InnerException.GetType()
        | _ -> printfn "その他の例外"
    finally
        printfn "--------------------"

[ Common.HttpWebRequestTask; Common.FsharpDataTask ] |> List.iter execute

出力
HttpWebRequestの場合
WebExceptionでResponseをHttpWebResponseにキャスト可能
404エラー
InnerExceptionは<null>
--------------------
FSharpDataのLoadの場合
WebExceptionでResponseをHttpWebResponseにキャスト可能ではないが、InnerExceptionはキャスト可能
404エラー
InnerExceptionはSystem.Net.WebException
--------------------

後書き

コードはGitHub上から確認できる。
同様の事例があるかと思い記事を探したが見つからず、デバッガーで例外の中身をHttpWebRequestのものと比較してと解決するまでに難儀した。
書いておかないと忘れてしまいそうなので備忘録として残しておく。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0