SignalR Service¶
This recipe covers adding real-time messaging to Azure Functions .NET isolated worker with Azure SignalR Service in serverless mode. It uses the SignalRConnectionInfoInput attribute to implement the required negotiate endpoint and the SignalROutput attribute to broadcast messages to connected clients.
Architecture¶
flowchart TD
CLIENT[Browser Client] --> NEG[Negotiate Function]
NEG --> INFO[SignalRConnectionInfoInput]
INFO --> SR[(Azure SignalR Service)]
CLIENT -->|WebSocket| SR
PUB[Broadcast Function] --> OUT[SignalROutput]
OUT --> SR
SR -->|push| CLIENT Prerequisites¶
Install the isolated worker SignalR extension package:
| CLI element | Explanation |
|---|---|
| Command(s) | dotnet add package |
| Key flags | (package name argument) |
| Variables | None |
| Expected result | The package reference is added to the .csproj; confirm the restore succeeds before continuing. |
Configure the connection in app settings. A connection string (stored as AzureSignalRConnectionString) or an identity-based connection is supported:
az functionapp config appsettings set \
--name $APP_NAME \
--resource-group $RG \
--settings "AzureSignalRConnectionString__serviceUri=https://$SIGNALR_NAME.service.signalr.net"
| CLI element | Explanation |
|---|---|
| Command(s) | az functionapp config appsettings set |
| Key flags | --name, --resource-group, --settings |
| Variables | $APP_NAME, $RG, $SIGNALR_NAME |
| Expected result | Azure CLI returns the updated app settings as JSON; confirm the setting is present before continuing. |
The SignalR Service instance must be in Serverless mode. When using an identity-based connection, grant the function app's managed identity the SignalR Service Owner role on the resource.
Command Groups¶
The negotiate Endpoint¶
Before a client connects, it calls a negotiate endpoint to obtain the service URL and a short-lived access token. The SignalRConnectionInfoInput binding produces this payload. The framework serializes the connection info as camel case, which the SignalR client SDK requires.
[Function(nameof(Negotiate))]
public static string Negotiate(
[HttpTrigger(AuthorizationLevel.Anonymous, "post")] HttpRequestData req,
[SignalRConnectionInfoInput(HubName = "serverless")] string connectionInfo)
{
return connectionInfo;
}
Broadcast a Message¶
Return a SignalRMessageAction decorated with the SignalROutput attribute to send a message to all connected clients. The action specifies a Target (the client-side handler name) and Arguments.
[Function(nameof(Broadcast))]
[SignalROutput(HubName = "serverless")]
public static async Task<SignalRMessageAction> Broadcast(
[HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req)
{
string message = await req.ReadAsStringAsync() ?? string.Empty;
return new SignalRMessageAction("newMessage")
{
Arguments = new[] { (object)message },
};
}
Target a User or Group¶
Set UserId or GroupName on the SignalRMessageAction to target a subset of clients instead of broadcasting.
return new SignalRMessageAction("newMessage")
{
UserId = "user1",
Arguments = new[] { (object)message },
};
Review Matrix¶
| Property | Purpose |
|---|---|
Target | Name of the client-side method invoked by SignalR |
Arguments | Arguments passed to the client method |
UserId | Restrict delivery to a single user identifier |
GroupName | Restrict delivery to members of a named group |
Secure the negotiate endpoint
The example uses AuthorizationLevel.Anonymous for clarity. In production, protect the endpoint with App Service Authentication and bind the authenticated user via UserId = "{headers.x-ms-client-principal-id}".