要旨
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のものと比較してと解決するまでに難儀した。
書いておかないと忘れてしまいそうなので備忘録として残しておく。