Recap: Creating a demo of real-time communication app using AspNetCore.SignalR

I believe the best way to learn a new technology is to create a proof of concept demo application. In this post, I would like to give you a brief recap of what I’ve learned about Microsoft.AspNetCore.SignalR while creating a real-time Planning Poker app.

A user's hand of Planning Poker cards

It’s a tiny web application which I built over the weekend and which you can try out here. Note, for the first time it may take up to 20 seconds for applications startup. To test it you have to join the same group from two different browser tabs or browsers. The source code can be found on Github.

The Recap

The requirements for this app are:

  • It should allow us to create or join a planning group,
  • List group members who are online,
  • Play card (give estimate) and notify rest of the members about cards currently played,
  • Reveal the cards and show the estimates to all group members simultaneously,
  • And start a new game plus clear previously played cards to all group members.

To fullfill requirements above, I am going to use AspNetCore.SignalR library. Which will allow to communicate between browsers a.k.a clients.

By the way, for the frontend, I am using the vue.js client-side framework. And vuetify, the material components library built on top of vue.js.

What's SignalR?

ASP.NET SignalR is a library for ASP.NET developers that simplifies the process of adding real-time web functionality to applications. Real-time web functionality is the ability to have server code push content to connected clients instantly as it becomes available, rather than having the server wait for a client to request new data.

As we can read the main functionality SingalR provides is pushing data to the Client. Which means that a browser doesn’t need to make a request to pull data from the backend. Instead, the server side code can directly invoke a JavaScript on the browser by sending a message that client-side code is listening to.

The following example of server-side method accepts group name and a message as a parameter and immediately sends the message to all connected Clients of a certain group.

// C# server side method
public async Task Send(string groupName, string message)
{
await Clients.Group(groupName).InvokeAsync("EVENT_SENT", message);
}

Meanwhile, the client side script is waiting for an event invoked from server and process the received message.

/* JavaScript example of SignalR client's side */
/* Connect to the backend's Hub */
let pokerHub = new HubConnection(HUBS.POKER);
/* Attach event listener to Send event */
pokerHub.on("Send", message => {
// Process the message
});
/* Start the real time communication with the hub */
pokerHub.start();
/* Message to other clients by executing backend's Send() method */
let sendMessage = message => pokerHub.invoke("Send", message);

To start developing you have to add the reference to SignalR package to the AspNetCore project.

<ItemGroup>
<PackageReference Include=”Microsoft.AspNetCore.SignalR” Version=”1.0.0-alpha2-final” />
</ItemGroup>

And must configure the routing for SingalR Hubs in Startup.cs

app.UseSignalR(routes => {
routes.MapHub<Poker>('Poker');
});

SignalR Hub

To create a hub one must create a class derived from Microsoft.AspNetCore.SignalR.Hub. This class allows us to get the connected Clients and Groups which are linked to the Hub. As well as getting the context of the Client who has invoked server-side code.

Microsoft.AspNetCore.SignalR.Hub is also responsible for calling OnConnected and OnDisconnected methods each time user visits or leaves a web page on which client-side hub connections are made.

In derived class, we can define our public methods that clients can call, for example

// Poker.cs
public class Poker : Hub
public async Task Send(string message)
{
await Clients.Client(Context.ConnectionId).InvokeAsync(“Send”, message);
}
}

The above code will send the Message back to the same client which called Send method. In this case, the receiving Client is determined from the current HubCallerContext and its ConnectionId property.

HubCallerContext

From this class, our server-side code can get a ConnectionId which is a GUID for each Client’s connection to the Hub. As well as ClaimsPrincipal of the calling Client and HubConnectionContext with more information about the connection itself.

I will not go into more details about this context, just want to note that in this demo I use HubCallerContext.HubConnectionContext to map the online users with their data into an in-memory dictionary.

private readonly ConcurrentDictionary<HubConnectionContext, UserDetails> _usersOnline;

Client-side connection to the Hub

import { HubConnection } from '@aspnet/signalr-client';let pokerHub = new HubConnection("/poker");pokerHub.on("Connected", message => { /*handleConnected */ });
pokerHub.on("Disconnected", message => { /*handleDisconnected */ });
pokerHub.start();

In the example above I have first created a new HubConnection and passed the server side's Hub route as a parameter. This route should match the one, configured in AspNetCore Startup.cs class.

Next, we have to register the methods which we will allow to invoke from the server side. And set the corresponding handler functions which will receive server-sent Message as a parameter. The message can be a primitive type or a JSON object in case we are passing a complex object to Client’s method.

After this small setup, we can start the Hub and handle the Connected and Disconnected methods when invoked from the server side.

Finally the last JavaScript snippet. To execute a server side method we need to perform invoke() method’s call on the Client’s HubConnection. It will then invoke the server side Hub’s Send method and will pass “message” string as a parameter to it.

pokerHub.invoke("Send", "message");

Conclusion

Hopefully, this will encourage you to try it out in your web applications. And will help you to make the user experience of the applications more exciting and more productive.

Once more before I go, you can try out the app on https://planning-poker-web.azurewebsites.net/ or see the source code on https://github.com/AndrejsAbrickis/PlanningPoker

If you want to share some feedback, I would more than welcome it. As usual you can leave a comment here or contact me on Twitter@andrejsabrickis.

Writing JS, TS, Vue, #C, and fostering teams to release customer value n-times a day. Creator of billid.app and writer on abrickis.me

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store