Adding websockets to 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.
- First, select C#Bot and then name the application.
- Leaving the Entity diagram empty, select the UI diagram and add a page called
Chat
and drag on aCustom Area
. This will allow us to add some client-side code later that will make a simple chat component which communicates over websockets. - On the Security diagram, allow visitors to access the
Chat
page. -
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.
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:
- Add a
Hubs
folder inserverside/src
-
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); } } }
-
In
Startup.cs
inside theConfigureServices
method we enable SignalR by:// % protected region % [Add extra startup methods here] on begin services.AddSignalR(); // % protected region % [Add extra startup methods here] end
-
In
Startup.cs
inside theConfigure
method modify theuseEndpoints
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
-
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
-
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 theclientside/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 inclientside/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:
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 calledReceiveMessage
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
throughendpoints.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 sendingSendMessage
events and listening forReceiveMessage
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.
Was this article helpful?