This blog is extracted from the MSIgnite session on “Build Real-Time Serverless Application with Azure Functions and SignalR” presented by Anthony Chu (Cloud Developer Advocate – Microsoft).
Azure SignalR Service
Today, SignalR has evolved to be one of the most popular real-time connection technologies around the world. The Azure version of SignalR Service is a fully managed SignalR service that enables you to focus on building real-time web experiences without worrying about setting up, hosting, scaling, or load balancing your SignalR server.
SignalR provides an abstraction over several techniques used for building real-time web applications. Generally, WebSocket is the optimal transport that is used, but, if a WebSocket connection cannot be established, the SignalR client will fall back to either Server-Sent Events or long polling.
Sending Messages on SignalR service
Azure SignalR Service can be used in three different ways:
Scale an ASP.NET Core SignalR App – Integrate Azure SignalR Service with an ASP.NET Core SignalR application to scale out for large connections.
Build serverless real-time apps – Use Azure Functions integration with Azure SignalR Service to build serverless real-time applications in languages such as JavaScript, C#, and Java.
Send messages from the server to clients via REST API – Azure SignalR Service provides REST API to enable applications to post messages to clients connected with SignalR Service, in any REST capable programming languages.
Azure Functions + SignalR Service
When you build a fully functional serverless application, sometimes you will have a need to send real-time messages. This requires a persistent connection, here you can use Web Apps for this requirement. But with Azure SignalR available now, you can use SignalR with Functions to send real-time messages from your serverless solutions. Azure Functions works well with different languages like JavaScript, C#, Java, Python etc., Therefore you can program SignalR with any of the languages that Functions support. Also, the SignalR service works well with other Azure Services.
Real-time messaging everywhere
You have clients like browser, desktop, mobiles, games etc connecting with SignalR service. Azure Functions works between the Event and SignalR service to publish the messages. For instance, you want a message to be published when an HTTP event is occurring, just set up an HTTP trigger with SignalR. Similarly, you can use timers and orchestrations when you have long-running durable functions. You can use SignalR service to broadcast the intermediate updates as well.
You can also trigger Events from Azure services, such as:
- Event Grid
- Event Hubs
- Service Bus
- Microsoft Graph
- Cosmos DB change feed
- Storage – blobs and queues
- Logic Apps connectors such as Salesforce, Slack etc
SignalR Service bindings for Azure Functions
The SignalR Service bindings for Azure Functions allow an Azure Function app to publish messages to clients connected to SignalR Service. Clients can connect to the service using a SignalR client SDK that is available in .NET, JavaScript, and Java, with more languages coming soon. Right now there are 2 binding for Azure SignalR Service.
- SignalRConnectionInfo (Input) – For a client to connect with SignalR service, you need a token. Basically, it is a connection information. This binding generates that token to connect to the client.
- SignalR (Output) – This is an output binding that allows Azure Functions to send messages to SignalR service to broadcast to all the other services.
Sample SignalRConnectionInfo input binding for JavaScript
This is a JavaScript Functions, it has 2 sections, the first one is functions.js where you define the bindings. This is an input binding, therefore; the type is mentioned as “SignalRConnectionInfo”.
// function.json
{
"type": "signalRConnectionInfo",
"name": "connectionInfo",
"hubName": "chat",
"direction": "in"
}
The bindings give us the token and the endpoint information which is transferred to the client.
// index.js – HTTP Trigger
module.exports = function (context, req, connectionInfo) {
context.res = { body: connectionInfo };
context.done();
};
Sample SignalRConnectionInfo input binding for C#
[FunctionName(nameof(GetSignalRInfo))]
public static IActionResult GetSignalRInfo(
[HttpTrigger()] HttpRequest req,
[SignalRConnectionInfo(HubName = "chat")]
SignalRConnectionInfo connectionInfo)
{
return new OkObjectResult(connectionInfo);
}
Connecting from a browser
Now that we have an endpoint that the client can call to retrieve the information through SignalR Services, here is how you can use it from a client. Typically, when you retrieve the information from the endpoint, you can use the standard SignalR library to create the connection.
// connectionInfo – retrieved from Azure Function
const connection = new signalR.HubConnectionBuilder()
.withUrl(connectionInfo.url, {
accessTokenFactory: () => connectionInfo.accessToken
})
.build();
The next step is you create one or more listeners or event triggers. In this code, we are listening for a message called “newMessage”. This JavaScript is executed when there is a “newMessage” from the server.
connection.on('newMessage', message => {
// message received, update UI
});
await connection.start();
Sample SignalR output binding for JavaScript
Now that we have clients connected to our SignalR service, let us see how to broadcast these messages to the clients from Functions. This is an output binding therefore, the type is mentioned as “SignalR”.
{
"type": "signalR",
"name": "signalRMessages",
"hubName": "chat",
"direction": "out"
}
module.exports = function (context, req) {
context.bindings.signalRMessages = [{
"target": "newMessage",
"arguments": [ req.body ]
}];
context.done();
};
Sample SignalR output binding for C#
[FunctionName(nameof(SendMessage))]
public static Task SendMessage(
[HttpTrigger()] object message,
[SignalR(HubName = "chat")]
IAsyncCollector<SignalRMessage> signalRMessages)
{
// function body
}
// function body
return signalRMessages.AddAsync(
new SignalRMessage
{
Target = "newMessage",
Arguments = new [] { message }
});
Authentication and users
SignalR Service allows you to broadcast messages to all clients or only to a subset of clients, such as those belonging to a single user. Authentication and Authorization in function app allow us to use external services like Facebook, Twitter, Google+ and other services. By configuring these services, you can use them in Azure Function Apps.
Whenever a user is authenticated by an app service authentication, a list of headers are returned, from which the username is taken and sent to the signalRConnectionInfo binding. This results in a token with the authenticated user’s userId. This is used to deliver appropriate messages to appropriate users.
// function.json
{
"type": "signalRConnectionInfo",
"name": "connectionInfo",
"userId": "{headers.x-ms-client-principal-name}",
" hubName": "chat",
"direction": "in"
}
Sending to a user
module.exports = function (context, req) {
context.bindings.signalRMessages = [{
"userId": "anthony",
"target": "newMessage",
"arguments": [ req.body ]
}];
context.done();
};
Wrap up
All it needs is just a few lines of code to set up a complete serverless real-time messaging system in Azure using Azure Functions and the new Azure SignalR Service.