(loginUser dispatch)), textChanged = fun e -> dispatch (UsernameChanged e.NewTextValue)) View.Button(text = "登录", command = fun _ -> (loginUser dispatch)) ]))一旦用户击中了Login按钮,我们想建立信号连接。let connectToServer = let connection = HubConnectionBuilder() .WithUrl(Config.SignalRUrl) .WithAutomaticReconnect() .Build() async { do! connection.StartAsync() |> Async.AwaitTask return connection }Since we will want to hold on to the connection, we will invoke a Command which will be evaluated in the Update method.let update msg (model: Model) = match msg with // ... other message handling | Connected connection -> { model with SignalRConnection = Some connection AppState = Ready }, Cmd.none // ... more message handling现在,在用户连接到聊天之后,我们将介绍聊天视图。此视图允许用户键入消息,发送并通过连接到服务的其他用户发送并读取响应或问题。Let’s start with writing messages. Similar as with the username we again have an Entry and a button for sending the messages. Once the user sends a message, we invoke SendAsync in our SignalR module:let sendMessage (connection: HubConnection) (message: ChatMessage) = async { let jsonMessage = JsonSerializer.Serialize(message) do! connection.SendAsync("SendMessage", jsonMessage) |> Async.AwaitTask }So thus far, we have connected to the SignalR service, and we can send messages to the server. But we are still missing one essential part, and that is how we can receive messages from the backend service. What we need to do is register a listener to a specific SignalR-method (called NewMessage). We can implement our function as follows:let startListeningToChatMessages (connection: HubConnection) dispatch = let handleReceivedMessage (msg: string) = printfn "Received message: %s" msg dispatch (Msg.MessageReceived(JsonSerializer.Deserialize(msg))) () connection.On("NewMessage", handleReceivedMessage)现在,在处理程序方法中,我们将每次从SignalR服务接收到新消息时分派命令。所以让我们从一开始就扩展我们的登录功能,不仅创建连接,还可以注册我们的接收器。let loginUser dispatch = async { let! connection = SignalR.connectToServer dispatch (Msg.Connected connection) SignalR.startListeningToChatMessages connection dispatch |> ignore dispatch (Msg.LoggedIn) } |> Async.StartImmediateWe pass in the dispatcher from the view method when registering. This allows us to dispatch a command, i.e. invoke the update method and add the new message to our list of chat messages:let update msg (model: Model) = match msg with // ... other message handling | MessageReceived chatMessage -> { model with Messages = chatMessage :: model.Messages }, Cmd.none // ... more message handling因此,用户将能够使用当前时刻使用聊天程序发送和接收聊天消息。Conclusion这就是我们如何在一个神话般的应用程序中使用信号并创建一个神话般的聊天应用程序。也许我们仍然必须覆盖设计和安全来真正获得该名称。您还看到的是如何与不源自用户输入的事件一起使用,而是发生在后台。每当您使用在后台中调用的代码时,可以使用此技术,而您的应用程序正在进行其他神话般的内容。您可以找到应用程序的完整样本GitHub.Titlephoto by Tyler Lastovich from Pexels">

与signalr和fabulous一起使用

00_title.

这个博客帖子是部分F#出现日历2020。一个大的谢谢谢尔盖为了组织今年,一定要查看其他博客帖子 - 阅读这一帖子后。

基于模型视图更新(MVU)模式,神话般的框架提供了编写功能第一移动(和桌面)客户端的手段。如果你是新的,我会建议你看看邮政经过蒂姆 (非常神话的维护者)或官方译文.

后端实现为ASP.NET核心Web应用程序,该应用程序已启用信号。你可以看到如何解决这个问题 这里.

要展示如何使用具有很棒的信号,我们将实现聊天应用程序。而且我觉得称它为“很棒的聊天” - 看看如何让这框架做很棒的事情是多么容易?所以让我们忽略这个问题:“这个世界真的需要另一个聊天应用程序吗?!”在我们的思想之后,让我们来看看我们将在这个应用程序中实现的内容,以突出显示如何在功能第一移动应用程序中使用信号。

让我们假设我们有以下要求:

  • 用户应该通过他的名字来识别自己。
  • 用户应该能够发送消息。
  • 用户应该在应用程序处于活动状态时读取消息。

换句话说,两个动作完全是UI驱动的,用户进入他的用户名,然后进入聊天。用户键入消息,然后按按钮将其发送。但是,在能够读取消息方面,该事件将从后台解雇。此外,通常建立一次信号的连接,然后用于会话的其余部分。因此,让我们在我们的应用程序中创建一个模块,这将包含关于信号的所有操作。

module SignalR =
    let connectToServer =
        // connect to SignalR service

    let startListeningToChatMessages (connection: HubConnection) dispatch =
        // receive messages

    let sendMessage (connection: HubConnection) (message: ChatMessage) =
        // send message

我们在用户提供了名称后连接到服务。不是因为它是必需的。但是,如果在一些稍后的点,我们决定添加一些适当的身份验证,这不会改变应用程序的流程。没有进一步的ADO,让我们实现登录视图。

显示登录视图的图像

我们为此部分使用的视图如下所述。

let view model dispatch =
    View.ContentPage
        (title= "登录",
         content =
             View.StackLayout
                 (verticalOptions = LayoutOptions.Center,
                  horizontalOptions = LayoutOptions.Center,
                  children =
                      [ View.Label(text = "Please enter your Username")
                        View.Entry
                            (text = model.Username,
                             maxLength = 15,
                             placeholder = "Please enter your username",
                             completed = (fun _ -> (loginUser dispatch)),
                             textChanged = fun e -> dispatch (UsernameChanged e.NewTextValue))
                        View.Button(text = "登录", command = fun _ -> (loginUser dispatch))
                        ]))

一旦用户击中了登录按钮,我们想建立信号连接。

let connectToServer =
    let connection =
        HubConnectionBuilder()
            .WithUrl(Config.SignalRUrl)
            .WithAutomaticReconnect()
            .Build()

    async {
        do! connection.StartAsync() |> Async.AwaitTask
        return connection
    }

Since we will want to hold on to the connection, we will invoke a Command which will be evaluated in the Update method.

let update msg (model: Model) =
    match msg with
    // ... other message handling
    | Connected connection ->
        { model with
              SignalRConnection = Some connection
              AppState = Ready },
        Cmd.none
    // ... more message handling

现在,在用户连接到聊天之后,我们将介绍聊天视图。此视图允许用户键入消息,发送并通过连接到服务的其他用户发送并读取响应或问题。

显示聊天视图的图像在行动

Let’s start with writing messages. Similar as with the username we again have an Entry and a button for sending the messages. Once the user sends a message, we invoke SendAsync in our SignalR module:

let sendMessage (connection: HubConnection) (message: ChatMessage) =
    async {
        let jsonMessage = JsonSerializer.Serialize(message)

        do! connection.SendAsync("SendMessage", jsonMessage)
            |> Async.AwaitTask
    }

So thus far, we have connected to the SignalR service, and we can send messages to the server. But we are still missing one essential part, and that is how we can receive messages from the backend service. What we need to do is register a listener to a specific SignalR-method (called NewMessage). We can implement our function as follows:

let startListeningToChatMessages (connection: HubConnection) dispatch =
    let handleReceivedMessage (msg: string) =
        printfn "Received message: %s" msg
        dispatch (Msg.MessageReceived(JsonSerializer.Deserialize(msg)))
        ()

    connection.On("NewMessage", handleReceivedMessage)

现在,在处理程序方法中,我们将每次从SignalR服务接收到新消息时分派命令。所以让我们从一开始就扩展我们的登录功能,不仅创建连接,还可以注册我们的接收器。

let loginUser dispatch =
    async {
        let! connection = SignalR.connectToServer
        dispatch (Msg.Connected connection)

        SignalR.startListeningToChatMessages connection dispatch
        |> ignore

        dispatch (Msg.LoggedIn)
    }
    |> Async.StartImmediate

We pass in the dispatcher from the view method when registering. This allows us to dispatch a command, i.e. invoke the update method and add the new message to our list of chat messages:

let update msg (model: Model) =
    match msg with
    // ... other message handling
    | MessageReceived chatMessage ->
        { model with
              Messages = chatMessage :: model.Messages },
        Cmd.none
    // ... more message handling

因此,用户将能够使用当前时刻使用聊天程序发送和接收聊天消息。

结论

这就是我们如何在一个神话般的应用程序中使用信号并创建一个神话般的聊天应用程序。也许我们仍然必须覆盖设计和安全来真正获得该名称。

您还看到的是如何与不源自用户输入的事件一起使用,而是发生在后台。每当您使用在后台中调用的代码时,可以使用此技术,而您的应用程序正在进行其他神话般的内容。

您可以找到应用程序的完整样本GitHub..

titlephoto by.泰勒lastovich.pexels.

更新: