You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Fable.Elmish对接第三方SignalR服务端:示例与替代方案咨询

Fable.Elmish对接C# ASP.NET Core SignalR服务端方案

一、使用Fable.SignalR.Elmish客户端实现

虽然Fable.SignalR的官方示例依赖共享F#库,但无需服务端配合,仅需手动映射服务端方法与F#类型即可实现类型安全对接。

步骤1:安装依赖

  • 安装NuGet包:Fable.SignalR.Elmish
  • 安装NPM包:@microsoft/signalr(Fable.SignalR底层依赖该JS客户端)

步骤2:定义消息类型

手动映射服务端与客户端的消息,替代共享库的类型定义:

// 服务端推送至客户端的消息类型,对应服务端的Method1方法
type ServerMessage =
    | Method1 of string

// 客户端发送至服务端的消息类型(按需定义,若无需发送可省略)
type ClientMessage =
    | SendChatMessage of string

步骤3:配置SignalR连接与Elmish集成

open Fable.SignalR
open Fable.SignalR.Elmish
open Elmish

// 创建SignalR连接,指定服务端Hub路由
let hubConnection =
    HubConnectionBuilder()
        .WithUrl("/chatHub") // 对应服务端ChatHub的路由地址
        .Build()

// 定义Hub代理,映射服务端方法到F#消息类型
let hubProxy =
    hub {
        // 绑定服务端的Method1方法,收到消息时转换为ServerMessage.Method1
        receive "Method1" (fun msg -> Method1 msg)
        // 绑定客户端发送消息的方法(按需添加)
        send "SendMessage" (fun (SendChatMessage msg) -> msg)
    }

// Elmish状态与消息定义
type Model = {
    ReceivedMessages: string list
}

type Msg =
    | SignalRInternalMsg of SignalR.Msg<ServerMessage, ClientMessage>
    | AddReceivedMessage of string

// 初始化函数
let init () =
    { ReceivedMessages = [] }, Cmd.ofMsg (SignalRInternalMsg SignalR.Connect)

// 更新函数:处理SignalR消息与业务逻辑
let update (msg: Msg) (model: Model) =
    match msg with
    | SignalRInternalMsg signalRMsg ->
        // 委托SignalR.Elmish处理连接状态与消息
        let updatedModel, cmd =
            SignalR.update hubProxy hubConnection signalRMsg model (fun serverMsg currentModel ->
                match serverMsg with
                | Method1 content ->
                    currentModel, Cmd.ofMsg (AddReceivedMessage content)
            )
        updatedModel, Cmd.map SignalRInternalMsg cmd
    | AddReceivedMessage content ->
        { model with ReceivedMessages = content :: model.ReceivedMessages }, Cmd.none

// 集成SignalR到Elmish Program
Program.mkProgram init update view
|> Program.withSignalR hubConnection hubProxy SignalRInternalMsg
|> Program.withBrowserDebugger
|> Program.run

说明

  • 无需服务端修改,仅通过字符串方法名与F#类型的映射实现类型安全
  • Program.withSignalR扩展方法自动处理连接的建立、重连等生命周期

二、无需编写绑定的替代方案:直接调用JS SignalR客户端

利用Fable的JS互操作特性,直接调用官方@microsoft/signalr的JS API,无需额外F#绑定库。

步骤1:安装依赖

安装NPM包:@microsoft/signalr

步骤2:F#代码实现

open Fable.Core.JsInterop
open Elmish

// 动态导入SignalR JS模块
let signalR = importAll "@microsoft/signalr"

type Model = {
    ReceivedMessages: string list
    HubConnection: obj option // 存储SignalR连接实例
}

type Msg =
    | ConnectToSignalR
    | ConnectionEstablished of obj
    | ReceivedMethod1Message of string
    | SendTestMessage

// 初始化
let init () =
    { ReceivedMessages = []; HubConnection = None }, Cmd.none

// 更新函数
let update (msg: Msg) (model: Model) =
    match msg with
    | ConnectToSignalR ->
        // 创建连接实例
        let connection =
            signalR.HubConnectionBuilder()
                .withUrl("/chatHub")
                .build()
        // 监听服务端的Method1方法
        connection?on("Method1", fun (content: string) ->
            dispatch (ReceivedMethod1Message content)
        ) |> ignore
        // 启动连接
        connection?start()
            .then(fun () -> dispatch (ConnectionEstablished connection))
            .catch(fun err -> console.error("连接失败:", err)) |> ignore
        model, Cmd.none
    | ConnectionEstablished conn ->
        { model with HubConnection = Some conn }, Cmd.none
    | ReceivedMethod1Message content ->
        { model with ReceivedMessages = content :: model.ReceivedMessages }, Cmd.none
    | SendTestMessage ->
        // 发送消息到服务端(若服务端有对应方法)
        match model.HubConnection with
        | Some conn ->
            conn?invoke("SendMessage", "来自Fable.Elmish的测试消息") |> ignore
            model, Cmd.none
        | None -> model, Cmd.none

// 视图部分示例(按需实现)
let view model dispatch =
    div [] [
        button [ OnClick (fun _ -> dispatch ConnectToSignalR) ] [ str "连接SignalR" ]
        button [ OnClick (fun _ -> dispatch SendTestMessage); Disabled (model.HubConnection.IsNone) ] [ str "发送测试消息" ]
        ul [] (model.ReceivedMessages |> List.map (fun msg -> li [] [ str msg ]))
    ]

// 启动Elmish程序
Program.mkProgram init update view
|> Program.withBrowserDebugger
|> Program.run

说明

  • 直接调用JS原生API,灵活度高,无需依赖第三方F#绑定库
  • 通过?操作符动态访问JS对象的方法与属性,无需提前定义类型
  • 需自行处理连接状态、错误捕获等逻辑

内容的提问来源于stack exchange,提问作者Franco Tiveron

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 13:06:24