SignalR Service bindings for Azure Functions

This article explains how to authenticate and send real-time messages to clients connected to Azure SignalR Service by using SignalR Service bindings in Azure Functions. Azure Functions supports input and output bindings for SignalR Service.

This is reference information for Azure Functions developers. If you're new to Azure Functions, start with the following resources:

Packages - Functions 2.x

The SignalR Service bindings are provided in the Microsoft.Azure.WebJobs.Extensions.SignalRService NuGet package, version 1.*. Source code for the package is in the azure-functions-signalrservice-extension GitHub repository.

The following table tells how to add support for this binding in each development environment.

Development environment To add support in
Functions 2.x
Local development - C# class library Install the package
Local development - C# script, JavaScript, F# Register the extension
Portal development Register the extension

To learn how to update existing binding extensions in the portal without having to republish your function app project, see Update your extensions.

Java annotations

To use the SignalR Service annotations in Java functions, you need to add a dependency to the azure-functions-java-library-signalr artifact (version 1.0 or higher) to your pom.xml.

<dependency>
    <groupId>com.microsoft.azure.functions</groupId>
    <artifactId>azure-functions-java-library-signalr</artifactId>
    <version>1.0.0</version>
</dependency>

Note

To use the SignalR Service bindings in Java, make sure you are using version 2.4.419 or higher of the Azure Functions Core Tools (host version 2.0.12332).

Using SignalR Service with Azure Functions

For details on how to configure and use SignalR Service and Azure Functions together, refer to Azure Functions development and configuration with Azure SignalR Service.

SignalR connection info input binding

Before a client can connect to Azure SignalR Service, it must retrieve the service endpoint URL and a valid access token. The SignalRConnectionInfo input binding produces the SignalR Service endpoint URL and a valid token that are used to connect to the service. Because the token is time-limited and can be used to authenticate a specific user to a connection, you should not cache the token or share it between clients. An HTTP trigger using this binding can be used by clients to retrieve the connection information.

See the language-specific example:

For more information on how this binding is used to create a "negotiate" function that can be consumed by a SignalR client SDK, see the Azure Functions development and configuration article in the SignalR Service concepts documentation.

2.x C# input examples

The following example shows a C# function that acquires SignalR connection information using the input binding and returns it over HTTP.

[FunctionName("negotiate")]
public static SignalRConnectionInfo Negotiate(
    [HttpTrigger(AuthorizationLevel.Anonymous)]HttpRequest req,
    [SignalRConnectionInfo(HubName = "chat")]SignalRConnectionInfo connectionInfo)
{
    return connectionInfo;
}

Authenticated tokens

If the function is triggered by an authenticated client, you can add a user ID claim to the generated token. You can easily add authentication to a function app using App Service Authentication.

App Service Authentication sets HTTP headers named x-ms-client-principal-id and x-ms-client-principal-name that contain the authenticated user's client principal ID and name, respectively. You can set the UserId property of the binding to the value from either header using a binding expression: {headers.x-ms-client-principal-id} or {headers.x-ms-client-principal-name}.

[FunctionName("negotiate")]
public static SignalRConnectionInfo Negotiate(
    [HttpTrigger(AuthorizationLevel.Anonymous)]HttpRequest req, 
    [SignalRConnectionInfo
        (HubName = "chat", UserId = "{headers.x-ms-client-principal-id}")]
        SignalRConnectionInfo connectionInfo)
{
    // connectionInfo contains an access key token with a name identifier claim set to the authenticated user
    return connectionInfo;
}

2.x JavaScript input examples

The following example shows a SignalR connection info input binding in a function.json file and a JavaScript function that uses the binding to return the connection information.

Here's binding data in the function.json file:

Example function.json:

{
    "type": "signalRConnectionInfo",
    "name": "connectionInfo",
    "hubName": "chat",
    "connectionStringSetting": "<name of setting containing SignalR Service connection string>",
    "direction": "in"
}

Here's the JavaScript code:

module.exports = async function (context, req, connectionInfo) {
    context.res.body = connectionInfo;
};

Authenticated tokens

If the function is triggered by an authenticated client, you can add a user ID claim to the generated token. You can easily add authentication to a function app using App Service Authentication.

App Service Authentication sets HTTP headers named x-ms-client-principal-id and x-ms-client-principal-name that contain the authenticated user's client principal ID and name, respectively. You can set the userId property of the binding to the value from either header using a binding expression: {headers.x-ms-client-principal-id} or {headers.x-ms-client-principal-name}.

Example function.json:

{
    "type": "signalRConnectionInfo",
    "name": "connectionInfo",
    "hubName": "chat",
    "userId": "{headers.x-ms-client-principal-id}",
    "connectionStringSetting": "<name of setting containing SignalR Service connection string>",
    "direction": "in"
}

Here's the JavaScript code:

module.exports = async function (context, req, connectionInfo) {
    // connectionInfo contains an access key token with a name identifier
    // claim set to the authenticated user
    context.res.body = connectionInfo;
};

2.x Java input examples

The following example shows a Java function that acquires SignalR connection information using the input binding and returns it over HTTP.

@FunctionName("negotiate")
public SignalRConnectionInfo negotiate(
        @HttpTrigger(
            name = "req",
            methods = { HttpMethod.POST },
            authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> req,
        @SignalRConnectionInfoInput(
            name = "connectionInfo",
            hubName = "chat") SignalRConnectionInfo connectionInfo) {
    return connectionInfo;
}

Authenticated tokens

If the function is triggered by an authenticated client, you can add a user ID claim to the generated token. You can easily add authentication to a function app using App Service Authentication.

App Service Authentication sets HTTP headers named x-ms-client-principal-id and x-ms-client-principal-name that contain the authenticated user's client principal ID and name, respectively. You can set the UserId property of the binding to the value from either header using a binding expression: {headers.x-ms-client-principal-id} or {headers.x-ms-client-principal-name}.

@FunctionName("negotiate")
public SignalRConnectionInfo negotiate(
        @HttpTrigger(
            name = "req",
            methods = { HttpMethod.POST },
            authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> req,
        @SignalRConnectionInfoInput(
            name = "connectionInfo",
            hubName = "chat",
            userId = "{headers.x-ms-client-principal-id}") SignalRConnectionInfo connectionInfo) {
    return connectionInfo;
}

SignalR output binding

Use the SignalR output binding to send one or more messages using Azure SignalR Service. You can broadcast a message to all connected clients, or you can broadcast it only to connected clients that have been authenticated to a given user.

You can also use it to manage the groups that a user belongs to.

See the language-specific example:

2.x C# send message output examples

Broadcast to all clients

The following example shows a C# function that sends a message using the output binding to all connected clients. The Target is the name of the method to be invoked on each client. The Arguments property is an array of zero or more objects to be passed to the client method.

[FunctionName("SendMessage")]
public static Task SendMessage(
    [HttpTrigger(AuthorizationLevel.Anonymous, "post")]object message, 
    [SignalR(HubName = "chat")]IAsyncCollector<SignalRMessage> signalRMessages)
{
    return signalRMessages.AddAsync(
        new SignalRMessage 
        {
            Target = "newMessage", 
            Arguments = new [] { message } 
        });
}

Send to a user

You can send a message only to connections that have been authenticated to a user by setting the UserId property of the SignalR message.

[FunctionName("SendMessage")]
public static Task SendMessage(
    [HttpTrigger(AuthorizationLevel.Anonymous, "post")]object message, 
    [SignalR(HubName = "chat")]IAsyncCollector<SignalRMessage> signalRMessages)
{
    return signalRMessages.AddAsync(
        new SignalRMessage 
        {
            // the message will only be sent to this user ID
            UserId = "userId1",
            Target = "newMessage",
            Arguments = new [] { message }
        });
}

Send to a group

You can send a message only to connections that have been added to a group by setting the GroupName property of the SignalR message.

[FunctionName("SendMessage")]
public static Task SendMessage(
    [HttpTrigger(AuthorizationLevel.Anonymous, "post")]object message,
    [SignalR(HubName = "chat")]IAsyncCollector<SignalRMessage> signalRMessages)
{
    return signalRMessages.AddAsync(
        new SignalRMessage
        {
            // the message will be sent to the group with this name
            GroupName = "myGroup",
            Target = "newMessage",
            Arguments = new [] { message }
        });
}

2.x C# group management output examples

SignalR Service allows users to be added to groups. Messages can then be sent to a group. You can use the SignalRGroupAction class with the SignalR output binding to manage a user's group membership.

Add user to a group

The following example adds a user to a group.

[FunctionName("addToGroup")]
public static Task AddToGroup(
    [HttpTrigger(AuthorizationLevel.Anonymous, "post")]HttpRequest req,
    string userId,
    [SignalR(HubName = "chat")]
        IAsyncCollector<SignalRGroupAction> signalRGroupActions)
{
    return signalRGroupActions.AddAsync(
        new SignalRGroupAction
        {
            UserId = userId,
            GroupName = "myGroup",
            Action = GroupAction.Add
        });
}

Remove user from a group

The following example removes a user from a group.

[FunctionName("removeFromGroup")]
public static Task RemoveFromGroup(
    [HttpTrigger(AuthorizationLevel.Anonymous, "post")]HttpRequest req,
    string userId,
    [SignalR(HubName = "chat")]
        IAsyncCollector<SignalRGroupAction> signalRGroupActions)
{
    return signalRGroupActions.AddAsync(
        new SignalRGroupAction
        {
            UserId = userId,
            GroupName = "myGroup",
            Action = GroupAction.Remove
        });
}

2.x JavaScript send message output examples

Broadcast to all clients

The following example shows a SignalR output binding in a function.json file and a JavaScript function that uses the binding to send a message with Azure SignalR Service. Set the output binding to an array of one or more SignalR messages. A SignalR message consists of a target property that specifies the name of the method to invoke on each client, and an arguments property that is an array of objects to pass to the client method as arguments.

Here's binding data in the function.json file:

Example function.json:

{
  "type": "signalR",
  "name": "signalRMessages",
  "hubName": "<hub_name>",
  "connectionStringSetting": "<name of setting containing SignalR Service connection string>",
  "direction": "out"
}

Here's the JavaScript code:

module.exports = async function (context, req) {
    context.bindings.signalRMessages = [{
        "target": "newMessage",
        "arguments": [ req.body ]
    }];
};

Send to a user

You can send a message only to connections that have been authenticated to a user by setting the userId property of the SignalR message.

function.json stays the same. Here's the JavaScript code:

module.exports = async function (context, req) {
    context.bindings.signalRMessages = [{
        // message will only be sent to this user ID
        "userId": "userId1",
        "target": "newMessage",
        "arguments": [ req.body ]
    }];
};

Send to a group

You can send a message only to connections that have been added to a group by setting the groupName property of the SignalR message.

function.json stays the same. Here's the JavaScript code:

module.exports = async function (context, req) {
    context.bindings.signalRMessages = [{
        // message will only be sent to this group
        "groupName": "myGroup",
        "target": "newMessage",
        "arguments": [ req.body ]
    }];
};

2.x JavaScript group management output examples

SignalR Service allows users to be added to groups. Messages can then be sent to a group. You can use the SignalR output binding to manage a user's group membership.

Add user to a group

The following example adds a user to a group.

function.json

{
  "disabled": false,
  "bindings": [
    {
      "authLevel": "anonymous",
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "methods": [
        "post"
      ]
    },
    {
      "type": "http",
      "direction": "out",
      "name": "res"
    },
    {
      "type": "signalR",
      "name": "signalRGroupActions",
      "connectionStringSetting": "<name of setting containing SignalR Service connection string>",
      "hubName": "chat",
      "direction": "out"
    }
  ]
}

index.js

module.exports = async function (context, req) {
  context.bindings.signalRGroupActions = [{
    "userId": req.query.userId,
    "groupName": "myGroup",
    "action": "add"
  }];
};

Remove user from a group

The following example removes a user from a group.

function.json

{
  "disabled": false,
  "bindings": [
    {
      "authLevel": "anonymous",
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "methods": [
        "post"
      ]
    },
    {
      "type": "http",
      "direction": "out",
      "name": "res"
    },
    {
      "type": "signalR",
      "name": "signalRGroupActions",
      "connectionStringSetting": "<name of setting containing SignalR Service connection string>",
      "hubName": "chat",
      "direction": "out"
    }
  ]
}

index.js

module.exports = async function (context, req) {
  context.bindings.signalRGroupActions = [{
    "userId": req.query.userId,
    "groupName": "myGroup",
    "action": "remove"
  }];
};

2.x Java send message output examples

Broadcast to all clients

The following example shows a Java function that sends a message using the output binding to all connected clients. The target is the name of the method to be invoked on each client. The arguments property is an array of zero or more objects to be passed to the client method.

@FunctionName("sendMessage")
@SignalROutput(name = "$return", hubName = "chat")
public SignalRMessage sendMessage(
        @HttpTrigger(
            name = "req",
            methods = { HttpMethod.POST },
            authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Object> req) {

    SignalRMessage message = new SignalRMessage();
    message.target = "newMessage";
    message.arguments.add(req.getBody());
    return message;
}

Send to a user

You can send a message only to connections that have been authenticated to a user by setting the userId property of the SignalR message.

@FunctionName("sendMessage")
@SignalROutput(name = "$return", hubName = "chat")
public SignalRMessage sendMessage(
        @HttpTrigger(
            name = "req",
            methods = { HttpMethod.POST },
            authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Object> req) {

    SignalRMessage message = new SignalRMessage();
    message.userId = "userId1";
    message.target = "newMessage";
    message.arguments.add(req.getBody());
    return message;
}

Send to a group

You can send a message only to connections that have been added to a group by setting the groupName property of the SignalR message.

@FunctionName("sendMessage")
@SignalROutput(name = "$return", hubName = "chat")
public SignalRMessage sendMessage(
        @HttpTrigger(
            name = "req",
            methods = { HttpMethod.POST },
            authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Object> req) {

    SignalRMessage message = new SignalRMessage();
    message.groupName = "myGroup";
    message.target = "newMessage";
    message.arguments.add(req.getBody());
    return message;
}

2.x Java group management output examples

SignalR Service allows users to be added to groups. Messages can then be sent to a group. You can use the SignalRGroupAction class with the SignalROutput output binding to manage a user's group membership.

Add user to a group

The following example adds a user to a group.

@FunctionName("addToGroup")
@SignalROutput(name = "$return", hubName = "chat")
public SignalRGroupAction addToGroup(
        @HttpTrigger(
            name = "req",
            methods = { HttpMethod.POST },
            authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Object> req,
        @BindingName("userId") String userId) {

    SignalRGroupAction groupAction = new SignalRGroupAction();
    groupAction.action = "add";
    groupAction.userId = userId;
    groupAction.groupName = "myGroup";
    return action;
}

Remove user from a group

The following example removes a user from a group.

@FunctionName("removeFromGroup")
@SignalROutput(name = "$return", hubName = "chat")
public SignalRGroupAction removeFromGroup(
        @HttpTrigger(
            name = "req",
            methods = { HttpMethod.POST },
            authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Object> req,
        @BindingName("userId") String userId) {

    SignalRGroupAction groupAction = new SignalRGroupAction();
    groupAction.action = "remove";
    groupAction.userId = userId;
    groupAction.groupName = "myGroup";
    return action;
}

Configuration

SignalRConnectionInfo

The following table explains the binding configuration properties that you set in the function.json file and the SignalRConnectionInfo attribute.

function.json property Attribute property Description
type Must be set to signalRConnectionInfo.
direction Must be set to in.
name Variable name used in function code for connection info object.
hubName HubName This value must be set to the name of the SignalR hub for which the connection information is generated.
userId UserId Optional: The value of the user identifier claim to be set in the access key token.
connectionStringSetting ConnectionStringSetting The name of the app setting that contains the SignalR Service connection string (defaults to "AzureSignalRConnectionString")

SignalR

The following table explains the binding configuration properties that you set in the function.json file and the SignalR attribute.

function.json property Attribute property Description
type Must be set to signalR.
direction Must be set to out.
name Variable name used in function code for connection info object.
hubName HubName This value must be set to the name of the SignalR hub for which the connection information is generated.
connectionStringSetting ConnectionStringSetting The name of the app setting that contains the SignalR Service connection string (defaults to "AzureSignalRConnectionString")

When you're developing locally, app settings go into the local.settings.json file.

Next steps