Adding websockets to a C#Bot application

We walk you through setting up a simple chat websocket in a C#Bot application.


Codebots currently has two bots, SpringBot and C#Bot, which both assist in creating full stack applications with a Spring Boot back-end and a C# .Net Core back-end respectively. Both these server-side languages have good support for websockets (or an abstraction over websockets) out of the box, here we will focus on adding a very simple chat example to a C#Bot project as C#Bot websocket support is provided through the use of the SignalR library which is included in .NET Core by default.

Creating a new application

We are going to begin by creating a new application on the Codebots Platform, a video of this process is shown below.

  1. First, select C#Bot and then name the application.
  2. Leaving the Entity diagram empty, select the UI diagram and add a page called Chat and drag on a Custom Area. This will allow us to add some client-side code later that will make a simple chat component which communicates over websockets.
  3. On the Security diagram, allow visitors to access the Chat page.
  4. Finally, hit ‘Build’ and let Codebots setup a git repository which produces a fully fledged C# .NET Core 5 (and a react client-side) project which can be cloned down and customised further.

Creating a new C#Bot Application

Configuring the server-side

Now that we have a .Net Core project ready to go, we can leverage a tutorial from the official documentation on adding and configuring the SignalR library. The tutorial in the documentation applies to a generic .NET Core application and this example will be roughly following along with it, with more specific examples for using it inside a C#Bot project. Let’s get started and configure the server-side with the following steps:

  1. Add a Hubs folder in serverside/src
  2. Create a new file for our Hub, which will be responsible for handling the client-server websockets communication. As in the SignalR guide let’s call this ChatHub.cs :
using Microsoft.AspNetCore.SignalR;
using System.Threading.Tasks;

namespace [projectname].Hubs
{
    public class ChatHub : Hub
    {
        public async Task SendMessage(string message)
        {
            await Clients.All.SendAsync("ReceiveMessage", message);
        }
    }
}
  1. In Startup.cs inside the ConfigureServices method we enable SignalR by:
// % protected region % [Add extra startup methods here] on begin
services.AddSignalR();
// % protected region % [Add extra startup methods here] end
  1. In Startup.cs inside the Configure method modify the useEndpoints protected region to look like:
// % protected region % [Configure endpoints here] on begin
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute("default", "{controller}/{action=Index}/{id?}");
        endpoints.MapHealthChecks("/api/health");
        endpoints.MapHub<ChatHub>("/hub");
    });
// % protected region % [Configure endpoints here] end
  1. Finally we make sure to import the Hub at the beginning of Startup.cs:
// % protected region % [Add any extra imports here] on begin
using [project name here].Hubs;
// % protected region % [Add any extra imports here] end

It’s time to move onto the client-side configuration.

Configuring the client-side

First we start by including SignalR javascript library by running the following in the clientside folder of our project:

`yarn add @microsoft/signalr`

Next let’s create our simple chat react component which will:

  • Import SignalR client library
  • Connect to our ChatHub
  • Listen for new messages coming in and update our state
  • Send a message event when we submit a message
  • Add a basic UI for displaying messages and send messages

The below achieves this with a functional react component which is added to a file called Chat.tsx in the clientside/src/Views/Components folder:

import React, {useEffect, useState, useRef} from 'react';
import * as signalR from "@microsoft/signalr";

export default function Chat() {
    // Represents the list of messages we have received
    const [messages, setMessages] = useState<string[]>([]);
    // Controlled component for the message we are going to send
    const [messageText, setMessageText] = useState("");

    // On load we connect to the hub and listen for messages
    const connectionRef = useRef<signalR.HubConnection>();
    useEffect(() => {
        const connection = new signalR.HubConnectionBuilder()
            .withUrl("/hub")
            .build();
        // Store a reference to the connection so we can send messages from it outside of this function
        connectionRef.current = connection;

        connection.on("ReceiveMessage", (message: string) => {
            setMessages((oldMessages) => [...oldMessages, message]);
        });

        connection.start();
    }, [])

    const sendMessage = async (e: React.FormEvent<HTMLFormElement>) => {
        e.preventDefault();

        // First argument corresponds to the name of the function we defined in 'ChatHub.cs'
        await connectionRef.current?.send("SendMessage", messageText);
        // Reset the text
        setMessageText("");
    }

    return (
        <div>
            {messages.map(message => <p>{message}</p>)}
            <form onSubmit={sendMessage}>
                <input value={messageText} onChange={(e) => setMessageText(e.target.value)}/>
            </form>
        </div>
    );
}

Now we want to add this component to the Chat page we added in the Codebots Platform earlier; located in clientside/src/Views/Pages/ChatPage.tsx. Let’s edit the protected region that was added in the ‘body-content’ section so that the code looks like:

<div className="body-content">
    {
    // % protected region % [Add code for 5650d771-ea3b-4a1f-9283-14c496bf4d45 here] on begin
    <Chat/>
    }
    {
    // % protected region % [Add code for 5650d771-ea3b-4a1f-9283-14c496bf4d45 here] end
    }
</div>

Finally, don’t forget to add our import at the top of the ChatPage.tsx file:

// % protected region % [Add any extra imports here] on begin
import Chat from 'Views/Components/Chat/Chat';
// % protected region % [Add any extra imports here] end

Demo time

Okay so now we have configured our server-side and client-side, let’s boot up our application and see our little chat demo in action. When we run our application and visit the home page we get the page shown in the demo below:

Demo

Let’s unpack what we have built:

  • We added a class called ChatHub which is a SignalR Hub. SignalR official docs describe this concept: "A hub is a class that serves as a high-level pipeline that handles client-server communication".
  • In this Hub we added a method called SendMessage which sends an event called ReceiveMessage to all connected clients and it includes the message as data.
  • We enabled SignalR in our Application through services.AddSignalR() and we add a route to our hub at /hub through endpoints.MapHub<ChatHub>("/hub");
  • We added the SignalR javascript library to our project via yarn add @microsoft/signalr
  • We create a react component that uses the SignalR javascript library. It renders a list of messages and a box to type a message, as well as, starting a connection to /hub. It also handles sending SendMessage events and listening for ReceiveMessage events.
  • We render the above react component on our ChatPage.tsx which we setup when we created our application on the Codebots Platform.

Summary

It can be quite easy to leverage websockets to facilitate the communication between client and server to create interactive experiences for web applications. For .Net Core the SignalR library provides this support and makes setting this up for a C#Bot application a piece of cake.