使用Scott Wlashin的AsyncResult,想知道如何从错误轨道切换到成功轨道。
伪代码:
let orchestratorFunction() : AsyncResult<Customer, CustomerError> = asyncResult {
let! output1 = callFunction1 arg1 arg2 |> AsyncResult.MapError CustomerError.Val1
let! output2 = callFunction2 arg1 arg2 |> AsyncResult.MapError CustomerError.Val2
let! output3 = callFunction3 arg1 arg2 |> AsyncResult.MapError (fun e -> ********HERE I WANT TO GET BACK TO THE SUCCESS PATH AND RETURN output3*********)
}
or a more realistic example:
let createCustomer() : AsyncResult<Customer, CustomerError> = asyncResult {
let! customerDto = mapDtoFromHttpRequest arg1 arg2 |> AsyncResult.MapError CustomerError.Val1
let! validatedCustomer = validateCustomer arg1 arg2 |> AsyncResult.MapError CustomerError.Val2
let! validatedCustomer = insertCustomer arg1 arg2
|> AsyncResult.MapError (fun e ->
match e with
| DuplicateCustomer _ ->
loadCustomerById xx
|> (fun c ->
if c.LastCausationId = validatedCustomer.LastCausationId
then c
else e))
}
所以基本上我试图摆脱不愉快的路径,因为这是一个幂等 REST 操作,任何重复的请求都将以 200 OK 回答,就好像它们是原始请求一样,以便客户端可以有一个简单的逻辑。
根据@Gus对这个问题的回答(AsyncResult 和处理回滚(,似乎 bindError 是我需要的。我创建了一个类似于他的 bindError bindExn,它似乎也可以工作,所以现在错误和 exns 都可以转换为 Ok:
(来自格斯(:
/// Apply a monadic function to an AsyncResult error
let bindError (f: 'a -> AsyncResult<'b,'c>) (xAsyncResult : AsyncResult<_, _>) :AsyncResult<_,_> = async {
let! xResult = xAsyncResult
match xResult with
| Ok x -> return Ok x
| Error err -> return! f err
}
(我的代码(:
let bindExn
(f: exn -> AsyncResult<'a,'b>)
(xAsyncResult:AsyncResult<_,_>)
: AsyncResult<'a,'b>
=
async {
let! res =
xAsyncResult
|> Async.Catch
|> Async.map(function
| Choice1Of2 res -> res |> AsyncResult.ofResult
| Choice2Of2 (ex:exn) ->
f ex
)
return! res
}