Azure Functions SignalR Service Bindings
The Azure Functions SignalR Service binding allows you to integrate Azure Functions with Azure SignalR Service to build real-time web applications. This binding provides declarative ways to send messages to connected clients and to handle incoming client connections and messages.
Getting Started
To use the SignalR Service binding, you need to add the SignalR Service extension to your Azure Functions project. You can do this using the Azure Functions Core Tools:
func extensions install --package Microsoft.Azure.WebJobs.Extensions.SignalRService --version 1.x.x
You also need to configure your SignalR Service connection string in your local.settings.json or application settings:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
"AzureSignalRConnectionString": "Endpoint=YOUR_SIGNALR_ENDPOINT;AccessKey=YOUR_ACCESS_KEY;Version=1.0;"
}
}
Output Binding: Sending Messages
The output binding allows your Azure Function to send messages to connected SignalR clients. You can specify the target hub and connection(s) to send messages to.
Example (C#)
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.SignalRService;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
public static class SendMessage
{
[FunctionName("SendMessage")]
public static IActionResult Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "post")] HttpRequest req,
[SignalR(HubName = "chat")] IAsyncCollector signalRMessages)
{
string message = req.Query["message"];
if (string.IsNullOrEmpty(message))
{
message = req.Body.ToString();
}
if (string.IsNullOrEmpty(message))
{
return new BadRequestObjectResult("Please provide a message in the query string or request body.");
}
// Send to all clients in the 'chat' hub
return new OkObjectResult(signalRMessages.AddAsync(new SignalRMessage
{
Target = "newMessage",
Arguments = new[] { message }
}));
}
}
Example (JavaScript)
module.exports = async function (context, req) {
const message = (req.query.message || (req.body && req.body.message));
if (message) {
context.bindings.signalRMessages = {
target: "newMessage",
arguments: [message]
};
context.res = {
status: 200,
body: "Message sent successfully."
};
} else {
context.res = {
status: 400,
body: "Please pass a message in the query string or in the request body"
};
}
};
SignalR Message Properties
- Target: The name of the server-side method to invoke on the client.
- Arguments: An array of arguments to pass to the client-side method.
- Sender (Optional): The connection ID of the client to send the message to (if sending to a specific client).
- Excluded (Optional): An array of connection IDs to exclude from receiving the message.
Input Binding: Handling Client Connections and Messages
The SignalR Service binding can also be used as an input binding to trigger a function when a client connects, disconnects, or sends a message.
SignalRConnectionInfo Input Binding
This binding provides negotiation information to clients, allowing them to connect to the SignalR hub.
Example (C#)
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.SignalRService;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
public static class Negotiate
{
[FunctionName("negotiate")]
public static IActionResult Run(
[HttpTrigger(AuthorizationLevel.Anonymous)] HttpRequest req,
[SignalRConnectionInfo(HubName = "chat")] SignalRConnectionInfo connectionInfo)
{
return new OkObjectResult(connectionInfo);
}
}
SignalRTrigger Binding
This binding triggers a function based on events from SignalR clients.
Event Types:
- Connected: Triggered when a client successfully connects.
- Disconnected: Triggered when a client disconnects.
- Message: Triggered when a client sends a message.
Example (C#)
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.SignalRService;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
public static class SignalRHandler
{
[FunctionName("SignalRHandler")]
public static void Run(
[SignalRTrigger(HubName = "chat", EventName = "newMessage")] SignalRMessage message,
[SignalR(HubName = "chat")] IAsyncCollector broadcast,
[Queue("notifications")] out string notification)
{
// Handle incoming message
string payload = message.Arguments[0].ToString();
context.log.LogInformation($"Received message: {payload}");
// Broadcast the message to all clients
notification = payload; // Send to a queue for other processing
broadcast.AddAsync(new SignalRMessage
{
Target = "newMessage",
Arguments = new[] { $"Server received: {payload}" }
});
}
[FunctionName("OnConnected")]
public static void OnConnected(
[SignalRTrigger(HubName = "chat", EventName = "connected")] InvocationContext invocationContext)
{
context.log.LogInformation($"Client connected: {invocationContext.ConnectionId}");
}
[FunctionName("OnDisconnected")]
public static void OnDisconnected(
[SignalRTrigger(HubName = "chat", EventName = "disconnected")] InvocationContext invocationContext)
{
context.log.LogInformation($"Client disconnected: {invocationContext.ConnectionId}");
}
}
Example (JavaScript)
module.exports = async function (context) {
if (context.bindingData.event === 'newMessage') {
const message = context.bindingData.message.arguments[0];
context.log.info(`Received message: ${message}`);
// Broadcast the message to all clients
context.bindings.signalRMessages = {
target: "newMessage",
arguments: [`Server received: ${message}`]
};
} else if (context.bindingData.event === 'connected') {
context.log.info(`Client connected: ${context.bindingData.connectionId}`);
} else if (context.bindingData.event === 'disconnected') {
context.log.info(`Client disconnected: ${context.bindingData.connectionId}`);
}
};
SignalR Trigger Properties
- HubName: The name of the SignalR hub to listen to.
- EventName: The type of event to trigger on (e.g., "connected", "disconnected", "newMessage").
Advanced Scenarios
Targeting Specific Clients
You can send messages to specific clients by providing their connection IDs in the SignalRMessage object:
// C# Example
signalRMessages.AddAsync(new SignalRMessage
{
Target = "privateMessage",
Arguments = new[] { "Hello User!", connectionId }, // Send to a specific connectionId
Sender = connectionId // Or specify the sender if needed
});
Using Groups
SignalR Service allows you to add clients to groups and broadcast messages to entire groups.
// C# Example: Adding a client to a group
[FunctionName("AddToGroup")]
public static async Task AddToGroup(
[HttpTrigger(AuthorizationLevel.Anonymous, "post")] HttpRequest req,
[SignalR(HubName = "chat")] IAsyncCollector signalRGroupActions)
{
string connectionId = req.Query["connectionId"];
string groupName = req.Query["groupName"];
await signalRGroupActions.AddAsync(new SignalRGroupAction
{
ConnectionId = connectionId,
Action = "add",
GroupName = groupName
});
}
// C# Example: Sending to a group
signalRMessages.AddAsync(new SignalRMessage
{
Target = "groupMessage",
Arguments = new[] { "Message for group members!" },
GroupName = groupName // Specify the group name
});
SignalRGroupAction, the Action property can be "add", "remove", or "removeAll".
Summary
Azure Functions SignalR Service bindings provide a powerful and declarative way to build real-time features into your serverless applications. By leveraging these bindings, you can efficiently manage client connections, send messages, and react to client events without managing the complexities of WebSocket connections yourself.