Serverless real-time messaging with Azure Functions and Azure SignalR Service

One missing piece for me to go all in on serverless so far was the lack of real-time messaging to clients using for example websockets. Usually we do this using SignalR for ASP.NET Core but this requires to run e.g. inside a container or a Azure Web App.

So I was quite excited to learn at Microsoft Build a couple of days ago about the new Azure SignalR Service, a full-managed offering. It seemed to me that this was a big part of the puzzle of the serverless story. Anthony Chu (@nthonyChu) has just created bindings for Azure Functions allowing to post messages to SignalR and provided a sample for Javascript: https://github.com/anthonychu/AzureAdvocates.WebJobs.Extensions.SignalRService

Since I like writing Functions in C# I wanted to see if I can get this to work in C# as well and then connect it to a simple Angular client. So I wrote I little sample using Azure Functions in C# and Angular: https://github.com/GrillPhil/ServerlessRealtimeDemo


Step 1: Create a new Azure SignalR Service instance

Log into your Azure Portal (https://portal.azure.com/) and create a new resource of type SignalR Service.

For testing purposes the Free tier is enough. If it’s hidden when selecting the Pricing tier just click on “View all” in the upper right corner of the blade to reveal it.

After the service is created copy the connection string from the Keys section


Step 2: Create a Function App

Create a new Function App in Visual Studio

Choose Azure Function v2 Preview (.NET Standard) and the Http trigger template.

Next we add a reference to the Nuget package AzureAdvocates.WebJobs.Extensions.SignalRService Anthony Chu has created that provides us with the required bindings.

We will need 2 functions: One to provide a SignalR endpoint to our client (negotiate) and one to allow to post messages to the SignalR service using a http request (message). Both functions will need the connection string of the SignalR service we just created. The default settings name is AzureSignalRConnectionString, so lets add this to our local.settings.json for local testing and later to our application settings in Azure.

In order to be able to call this function locally from our Angular app we also need to enable CORS by adding a Host section with a wildcard CORS policy.

NegotiateFunction

This function will be called by our client to retrieve the SignalR Service endpoint. To do so we need to create a new function with a Http trigger and inject an AzureSignalRConnectionInfo object using the SignalRConnectionInfo attribute. In the attribute we need to specify the name of the hub we intend to use, e.g. [SignalRConnectionInfo(HubName = “broadcast”)]AzureSignalRConnectionInfo info. This object provides the endpoint url that we then can simply return.

MessageFunction

This function will be called to broadcast a message to all connected clients through our SignalR Service. Therefore we will create a new function with a Http trigger and this time inject a IAsyncCollector<SignalRMessage> object using the SignalR attribute and specifying the same hub, e.g. [SignalR(HubName = “broadcast”)]IAsyncCollector<SignalRMessage> signalRMessages. To actually send a new message we then need to call AddAsync on the IAsyncCollector<SignalRMessage> and provide a new SignalRMessage as parameter. The property Target is the SignalR method we want to call.

And that’s it for the function part!


Step 3: Create an Angular Client App

Now let’s spin up a new Angular app that acts as our demo client to send and receive messages. We can do this e.g. by using the Angular CLI.

We need to add the @aspnet/signalr package to our project e.g. using npm.

Let’s now create a new service to handle all things SignalR in our app. This service will need an init method to get the SignalR endpoint from our function app by calling the negotiate function and then establish a new hubConnection. After we have established the connection to our SignalR hub we can then start to listen for new messages.

The second method we will need is a send method to trigger our message function and create a new message.

Now we can inject the SignalRService into a component, connect it to a sample UI and subscribe to new messages.

So let’s try this with multiple browser windows and enjoy!

Again the full demo is available on Github: https://github.com/GrillPhil/ServerlessRealtimeDemo

Conclusion

With just a few lines of code we can setup a complete serverless real-time messaging system in Azure using Azure Functions and the new Azure SignalR Service at scale.

For more information check out: