Building a cloud editor with SignalR and ASP.NET Core 2.1

With the release of 2.1, we finally got SignalR in ASP.NET Core. SignalR is used for making real-time connections on websites, which is used in applications where the response time is especially important and where you want the newest information at all times without having to poll the server for updates. I'll use the example of a multi-group collaborative text editor for this post. This will require both server-side code to manage connections, and a client using the updated SignalR.js client, which no longer relies on JQuery.

Here is a list of prerequisites you will need to install in order to get started with the project.

Launch Visual Studio and create a new ASP.NET Core Web Application.
In the next window, pick ASP.NET Core 2.1 as your SDK, then choose the option “Web Application”

Create a new class and name it TextHub. This class will need the SignalR library, and to extend the Hub class. The hub is what controls the communication between different clients and will eventually manage the different groups. For now, just add the following functions which will manage a simple communication between clients:

This handles when a new connection is started by adding that connection to a group. The OnDisconnectedAsync method removes a connection from its group when the connection is terminated both expectedly and unexpectedly. The BroadcastText method handles text-based communication between the clients by sending text that it receives to all other clients in the same group.

Now, register your TextHub in the Startup class by adding the SignalR service and specifying the route that SignalR will use in your app configuration:

Now the server part is ready for clients to connect to SignalR. The next step is to prepare the client. To get the required packages, you can use npm to install the @ASPNET/SIGNALR package, which contains a JavaScript file, so that you don't need JQuery to make it work. Move the script node_modules\@aspnet\signalr\dist\browser\signalr.min.js to your lib folder. We will reference this in the following code. We also create a JavaScript file called texteditor.js for our own client script. We can use the existing index page, by inserting the following code:

The first piece of code defines our editor's textarea. We then create a new connection using the HubConnectionBuilder, which is a new feature in this version of SignalR. The URL specified is the same as we made in the Startup class, and it may be necessary to specify the full URL, if you want to host this on a subsite (or with other special conditions that apply). In most cases though, this should be fine.

Next up, we will make a handler that manages when the connection receives a "ReceiveText", being the call we made on the server side when someone wants to broadcast their text to all clients. This also refocuses your cursor to the end of the editor, which makes collaborative writing a lot smoother. The counterpart to this, the change function, invokes the BroadcastText method that we specified on the server. You could make your own methods on the server like this and you would then be able to call them from here in the same way or with another trigger. The trigger for our use is the onkeyup action on the textarea, which means that it makes a broadcast every time you type a character into the editor.

You now have the first functioning version of the editor, and you can try it out by opening two tabs with your site on and observe how it synchronizes any text written in it between the tabs.

We now want to expand on this concept by adding dynamic groups. We first go to the server side again and add a JoinGroup function and change around how groups are handled:

The new JoinGroup takes a group as parameter and checks for an existing membership of another group through the dictionary defined first in the class (which maps from connections to groups). This is necessary, because SignalR doesn't provide us with any way of viewing which connections there are in each group.

Navigate back to the index page. Here we will need to add an input field and a button which a user can use to join a group.

The collaborative group-based text editor is now done, but we could of course make improvements to it. Examples could be error handling, so that it tries to reconnect if the client loses connection. Better cursor handling, so that multiple people could type at once without getting jumped around or a simple one could be that you get updated with the other's current text when you first join. I leave these enhancements to you for exploration.