在 F# WebAssembly 应用程序中管理 HttpClient

Managing HttpClient in a F# WebAssembly app

最好的做法是在一个地方“注册”http 客户端,以便可以从这个 Elmish 更新功能中重复使用它?而不是必须为每个请求创建它。

let update message model =
    match message with
    | SetMessage s -> { model with x = s }
    | Loading -> { model with x = "Doing something long ..." }

let handleClick model dispatch _ = 
    dispatch Loading
    async {
        let url = Uri "https://api.github.com"
        -- FIXME: too expensive to do this on per-update basis
        use httpClient = new HttpClient(BaseAddress = url)
        let! resp = httpClient.GetAsync "/users/srid" |> Async.AwaitTask
        let! s = resp.Content.ReadAsStringAsync() |> Async.AwaitTask
        dispatch (SetMessage s)
    } |> Async.Start

我觉得这通常会进入 Startup.fs。我使用仅限客户端的 Bolero 网络应用程序,所以它看起来像:

 builder.Services.AddSingleton<HttpClient>(new HttpClient (BaseAddress=apiBase))

但问题就变成了……如何从我的 F# 程序中访问它?惯用的方式是什么?

可能最好的方法是将 HttpClient 添加为模型中的另一个字段或作为更新函数的另一个参数。

let update (client:HttpClient) message model = // Your code

let url = Uri "https://api.github.com"
let httpClient = new HttpClient(BaseAddress = url)

一般来说,您不应该在您的视图中“做事”,推而广之,也不应该在事件处理程序中“做事”。相反,你应该使用 Elmish Cmd module 这样的东西:

let update httpClient message model =
    match message with
    | SetMessage s -> 
        { model with x = s }, Cmd.none
    | GetMessageAsync -> 
        let cmd = 
            let getHttp () = 
                async {
                    let! resp = httpClient.GetAsync "/users/srid" |> Async.AwaitTask
                    return! resp.Content.ReadAsStringAsync() |> Async.AwaitTask
                }
            Cmd.OfAsync.perform getHttp () (fun s -> SetMessage s)

        { model with x = "Doing something long ..." }, cmd

let handleClick model dispatch _ = 
    dispatch GetMessageAsync