Socket.IO Azure Function trigger and binding (Preview)

This article explains how to use Socket.IO serverless integrate with Azure Functions.

Action Binding Type
Get client negotiate result including url and access token Input binding
Triggered by messages from the service Trigger binding
Invoke service to send messages or manage clients Output binding

Source code | Package | API reference documentation | Product documentation | Samples

Important

Azure Function bindings can only integrate with Web PubSub for Socket.IO in Serverless Mode.

Authenticate and Connection String

In order to let the extension work with Web PubSub for Socket.IO, you need to provide either access keys or identity based configuration to authenticate with the service.

Access key based configuration

Configuration Name Description
WebPubSubForSocketIOConnectionString Required. Key based connection string to the service

You can find the connection string in Keys blade in you Web PubSub for Socket.IO in the Azure portal.

For the local development, use the local.settings.json file to store the connection string. Set WebPubSubForSocketIOConnectionString to the connection string copied from the previous step:

{
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    `WebPubSubForSocketIOConnectionString`: "Endpoint=https://<webpubsub-name>.webpubsub.azure.com;AccessKey=<access-key>;Version=1.0;"
  }
}

When deployed use the application settings to set the connection string.

Identity based configuration

Configuration Name Description
WebPubSubForSocketIOConnectionString__endpoint Required. The Endpoint of the service. For example, https://mysocketio.webpubsub.azure.com
WebPubSubForSocketIOConnectionString__credential Defines how a token should be obtained for the connection. This setting should be set to managedidentity if your deployed Azure Function intends to use managed identity authentication. This value is only valid when a managed identity is available in the hosting environment.
WebPubSubForSocketIOConnectionString__clientId When credential is set to managedidentity, this property can be set to specify the user-assigned identity to be used when obtaining a token. The property accepts a client ID corresponding to a user-assigned identity assigned to the application. If not specified, the system-assigned identity is used.

The function binding follows the common properties for identity based configuration. See Common properties for identity-based connections for more unmentioned properties.

For the local development, use the local.settings.json file to store the connection string. Set WebPubSubForSocketIOConnectionString to the connection string copied from the previous step:

{
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "WebPubSubForSocketIOConnectionString__endpoint": "https://<webpubsub-name>.webpubsub.azure.com",
    "WebPubSubForSocketIOConnectionString__tenant": "<tenant id you're in>",
  }
}

If you want to use identity based configuration and running online, the AzureWebJobsStorage should refer to Connecting to host storage with an identity.

Input Binding

Socket.IO Input binding generates a SocketIONegotiationResult to the client negotiation request. When a Socket.IO client tries to connect to the service, it needs to know the endpoint, path, and access token for authentication. It's a common practice to have a server to generate these data, which is called negotiation.

[FunctionName("SocketIONegotiate")]
public static IActionResult Negotiate(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get")] HttpRequest req,
    [SocketIONegotiation(Hub = "hub", UserId = "userId")] SocketIONegotiationResult result)
{
    return new OkObjectResult(result);
}

Attribute

The attribute for input binding is [SocketIONegotiation].

Attribute property Description
Hub The hub name that a client needs to connect to.
Connection The name of the app setting that contains the Socket.IO connection string (defaults to WebPubSubForSocketIOConnectionString).
UserId The userId of the connection. It applies to all sockets in the connection. It becomes the sub claim in the generated token.

Trigger Binding

Azure Function uses trigger binding to trigger a function to process the events from the Web PubSub for Socket.IO.

Trigger binding exposes a specific path followed the Azure Function endpoint. The url should be set as the URL Template of the service (Portal: settings -> event handler -> URL Template). In the endpoint pattern, the query part code=<API_KEY> is REQUIRED when you're using Azure Function App for security reasons. The key can be found in Azure portal. Find your function app resource and navigate to Functions -> App keys -> System keys -> socketio_extension after you deploy the function app to Azure. Though, this key isn't needed when you're working with local functions.

<Function_App_Endpoint>/runtime/webhooks/socketio?code=<API_KEY>

Function triggers for socket connect event.

[FunctionName("SocketIOTriggerConnect")]
public static async Task<SocketIOEventHandlerResponse> Connect(
    [SocketIOTrigger("hub", "connect")] SocketIOConnectRequest request)
{
    return new SocketIOConnectResponse();
}

Function triggers for socket connected event.

[FunctionName("SocketIOTriggerConnected")]
public static async Task Connected(
    [SocketIOTrigger("hub", "connected")] SocketIOConnectedRequest request)
{
}

Function triggers for socket disconnect event.

[FunctionName("SocketIOTriggerDisconnected")]
public static async Task Disconnected(
    [SocketIOTrigger("hub", "disconnected")] SocketIODisconnectedRequest request)
{
}

Function triggers for normal messages from clients.

[FunctionName("SocketIOTriggerMessage")]
public static async Task NewMessage(
    [SocketIOTrigger("hub", "new message")] SocketIOMessageRequest request,
    [SocketIOParameter] string arg)
{
}

Attributes

The attribute for trigger binding is [SocketIOTrigger].

Attribute property Description
Hub The hub name that a client needs to connect to.
Namespace The namespace of the socket. Default: "/"
EventName The event name that the function triggers for. Some event names are predefined: connect for socket connect event. connected for socket connected event. disconnected for socket disconnected event. And other events are defined by user and it need to match the event name sent by client side.
ParameterNames The parameter name list of the event. The length of list should be consistent with event sent from client. And the name uses the Binding expressions and access by the same-name function parameter.

Binding Data

[SocketIOTrigger] binds some variables to binding data. You can learn more about it from Azure Functions binding expression patterns

SocketIOAttribute

SocketIOAttribute is an alternative of ParameterNames, which simplifies the function definition. For example, the following two definitions have the same effect:

[FunctionName("SocketIOTriggerMessage")]
public static async Task NewMessage(
    [SocketIOTrigger("hub", "new message")] SocketIOMessageRequest request,
    [SocketIOParameter] string arg)
{
}
[FunctionName("SocketIOTriggerMessage")]
public static async Task NewMessage(
    [SocketIOTrigger("hub", "new message", ParameterNames = new[] {"arg"})] SocketIOMessageRequest request,
    string arg)
{
}

Note that ParameterNames and [SocketIOParameter] can't be used together.

Request of Input Binding

The data structure of input binding arguments varies depending on the message type.

Connect

{
    "namespace": "",
    "socketId": "",
    "claims": {
        "<claim-type>": [ "<claim-value>" ]
    },
    "query": {
        "<query-key>": [ "<query-value>" ]
    },
    "headers":{
        "<header-name>": [ "<header-value>" ]
    },
    "clientCertificates":{
        {
            "thumbprint": "",
            "content": ""
        }
    }
}
Property Description
namespace The namespace of the socket.
socketId The unique identity of the socket.
claims The claim of JWT of the client connection. Note, it's not the JWT when the service request the function, but the JWT when the Engine.IO client connects to the service.
query The query of the client connection. Note, it's not the query when the service request the function, but the query when the Engine.IO client connects to the service.
headers The headers of the client connection. Note, it's not the headers when the service request the function, but the headers when the Engine.IO client connects to the service.
clientCertificates The client certificate if it's enabled

Connected

{
    "namespace": "",
    "socketId": "",
}
Property Description
namespace The namespace of the socket.
socketId The unique identity of the socket.

Disconnected

{
    "namespace": "",
    "socketId": "",
    "reason": ""
}
Property Description
namespace The namespace of the socket.
socketId The unique identity of the socket.
reason The connection close reason description.

Normal events

{
    "namespace": "",
    "socketId": "",
    "payload": "",
    "eventName": "",
    "parameters": []
}
Property Description
namespace The namespace of the socket.
socketId The unique identity of the socket.
payload The message payload in Engine.IO protocol
eventName The event name of the request.
parameters List of parameters of the message.

Output Binding

The output binding currently support the following functionality:

  • Add a socket to room
  • Remove a socket from room
  • Send messages to a socket
  • Send messages to a room
  • Send messages to a namespace
  • Disconnect sockets
[FunctionName("SocketIOOutput")]
public static async Task<IActionResult> SocketIOOutput(
    [SocketIOTrigger("hub", "new message")] SocketIOMessageRequest request,
    [SocketIO(Hub = "hub")] IAsyncCollector<SocketIOAction> collector)
{
    await collector.AddAsync(SocketIOAction.CreateSendToNamespaceAction("new message", new[] { "arguments" }));
}

Attribute

The attribute for input binding is [SocketIO].

Attribute property Description
Hub The hub name that a client needs to connect to.
Connection The name of the app setting that contains the Socket.IO connection string (defaults to WebPubSubForSocketIOConnectionString).

Actions

Output binding uses actions to perform operations. Currently, we support the following actions:

AddSocketToRoomAction

{
    "type": "AddSocketToRoom",
    "socketId": "",
    "room": ""
}

RemoveSocketFromRoomAction

{
    "type": "RemoveSocketFromRoom",
    "socketId": "",
    "room": ""
}

SendToNamespaceAction

{
    "type": "SendToNamespace",
    "eventName": "",
    "parameters": [],
    "exceptRooms": []
}

SendToRoomsAction

{
    "type": "SendToRoom",
    "eventName": "",
    "parameters": [],
    "rooms": [],
    "exceptRooms": []
}

SendToSocketAction

{
    "type": "SendToSocket",
    "eventName": "",
    "parameters": [],
    "socketId": ""
}

DisconnectSocketsAction

{
    "type": "DisconnectSockets",
    "rooms": [],
    "closeUnderlyingConnection": false
}