在管道中链接异步 REST 调用,同时管理错误



基于同步调用的上一个问题的基础上,我们如何在以下场景中处理异步方法。

let fetch1 (result: string) : Result<string, string> =
try
use request = WebRequest.Create("http://bing.com") :?> HttpWebRequest
use response = request.GetResponse()
use reader = new StreamReader(response.GetResponseStream())
let html = reader.ReadToEnd()
Ok "success"
with
| :? WebException as e ->
Error "error with the url"
let fetch2 (result: string) : Result<string, string> =
try
use request = WebRequest.Create("http://google.com") :?> HttpWebRequest
use response = request.GetResponse()
use reader = new StreamReader(response.GetResponseStream())
let html = reader.ReadToEnd()
Ok "success"
with
| :? WebException as e ->
Error "error with the url"
let fetch3 (result: string) : Result<string, string> =
try
use request = WebRequest.Create("http://invalid.com") :?> HttpWebRequest
use response = request.GetResponse()
use reader = new StreamReader(response.GetResponseStream())
let html = reader.ReadToEnd()
Ok "success"
with
| :? WebException as e ->
Error "error with the url"

测试

let chain = fetch1 >> Result.bind fetch2 >> Result.bind fetch3
match chain("") with 
| Ok message -> Debug.WriteLine(message)
| Error error -> Debug.WriteLine(error)

尝试

let fetch1 (result: string) :Result<string, string> = async {
try
use! request = WebRequest.Create("http://bing.com") :?> HttpWebRequest
use response = request.GetResponse()
use reader = new StreamReader(response.GetResponseStream())
let html = reader.ReadToEnd()
Ok "success"
with
| :? WebException as e ->
Error "error with the url"
}

错误

此表达式被指定为具有"结果"类型,但此处具有"异步<"a>

您应该解释一下您实际上尝试在此处实现的异常处理机制。对于许多事情,仅使用普通的 F# 内置异常就可以正常工作。

您正在使用Result.bind这是一种实现异常处理行为的方法,如果任何步骤引发异常,则整体计算将失败。这是您想要实现的目标吗?如果是这样,则只需依靠内置的 F# 异步支持进行异常处理,并在调用两个fetch函数的异步计算中try .. with。一个最小的例子:

let fetch url = async {
use wc = new WebClient()
let! res = wc.AsyncDownloadString(System.Uri(url))
return res }
let fetchAllOrNothing = async {
try 
let! goog = fetch "http://www.google.com"
let! bing = fetch "http://www.bing.com"
return Some(goog.Length, bing.Length)
with _ ->
return None }

如果要调用所有 fetch 函数并且仅在所有函数都失败时才失败,则需要使用异常处理程序包装单个fetch函数(就像您所做的那样),然后选择第一个结果。使用普通的 F# 选项类型,可以使用Array.tryPick来完成此操作:

let fetch url = async {
try
use wc = new WebClient()
let! res = wc.AsyncDownloadString(System.Uri(url))
return Some res 
with _ -> 
return None }
let fetchFirstOne = async {
let! all = 
[ fetch "http://www.google.com"
fetch "http://www.bing.com" ] |> Async.Parallel
return Array.tryPick (fun x -> x) all }

如果从 F# 开始,则开始使用核心async函数和选项等内容要容易得多 - 一旦熟悉了这些,查看更复杂的方法就有意义了。

最新更新