Use Azure SignalR Management SDK

Azure SignalR Management SDK helps you to manage SignalR clients through Azure SignalR Service directly such as broadcast messages. Therefore, this SDK could be but not limited to be used in serverless environments. You could use this SDK to manage SignalR clients connected to your Azure SignalR Service in any environment, such as in a console app, in an Azure function or in a web server.

Note

To see guides for SDK version 1.9.x and before, go to Azure SignalR Service Management SDK (Legacy). You might also want to read Migration guidance.

Features

Feature Transient Persistent
Broadcast ✔️ ✔️
Broadcast except some clients ✔️ ✔️
Send to a client ✔️ ✔️
Send to clients ✔️ ✔️
Send to a user ✔️ ✔️
Send to users ✔️ ✔️
Send to a group ✔️ ✔️
Send to groups ✔️ ✔️
Send to a group except some clients ✔️ ✔️
Add a user to a group ✔️ ✔️
Remove a user from a group ✔️ ✔️
Check if a user in a group ✔️ ✔️
Multiple SignalR service instances support ✔️
MessagePack clients support since v1.21.0 since v1.20.0
Retry transient error since v1.22.0

Features only come with new API

Feature Transient Persistent
Check if a connection exists ✔️ Since v1.11
Check if a group exists ✔️ Since v1.11
Check if a user exists ✔️ Since v1.11
Close a client connection ✔️ Since v1.11
  • More details about different modes can be found here.

  • A full sample on management SDK can be found here.

Usage

This section shows how to use the Management SDK.

Create Service Manager

Build your instance of ServiceManager from a ServiceManagerBuilder


var serviceManager = new ServiceManagerBuilder()
                    .WithOptions(option =>
                    {
                        option.ConnectionString = "<Your Azure SignalR Service Connection String>";
                    })
                    .WithLoggerFactory(loggerFactory)
                    .BuildServiceManager();

You can use ServiceManager to check the Azure SignalR endpoint health and create service hub context. The following section provides details about creating service hub context.

To check the Azure SignalR endpoint health, you can use ServiceManager.IsServiceHealthy method. If you have multiple Azure SignalR endpoints, only the first endpoint is checked.

var health = await serviceManager.IsServiceHealthy(cancellationToken);

Create Service Hub Context

Create your instance of ServiceHubContext from a ServiceManager:

var serviceHubContext = await serviceManager.CreateHubContextAsync("<Your Hub Name>",cancellationToken);

Negotiation

In default mode, an endpoint /<Your Hub Name>/negotiate is exposed for negotiation by Azure SignalR Service SDK. SignalR clients reach this endpoint and then redirect to Azure SignalR Service later.

In serverless mode, we recommend you hosting a negotiation endpoint to serve the SignalR clients' negotiate request and redirect the clients to Azure SignalR Service.

Tip

Read more details about the redirection at SignalR's Negotiation Protocol.

Both of endpoint and access token are useful when you want to redirect SignalR clients to your Azure SignalR Service.

You could use the instance of ServiceHubContext to generate the endpoint url and corresponding access token for SignalR clients to connect to your Azure SignalR Service.

var negotiationResponse = await serviceHubContext.NegotiateAsync(new (){UserId = "<Your User Id>"});

Suppose your hub endpoint is http://<Your Host Name>/<Your Hub Name>, then your negotiation endpoint is http://<Your Host Name>/<Your Hub Name>/negotiate. Once you host the negotiation endpoint, you can use the SignalR clients to connect to your hub like this:

var connection = new HubConnectionBuilder().WithUrl("http://<Your Host Name>/<Your Hub Name>").Build();
await connection.StartAsync();

The sample on how to use Management SDK to redirect SignalR clients to Azure SignalR Service can be found here.

Send messages and manage groups

The ServiceHubContext we build from ServiceHubContextBuilder is a class that implements and extends IServiceHubContext. You could use it to send messages to your clients and managing your groups.

try
{
    // Broadcast
    await hubContext.Clients.All.SendAsync(callbackName, obj1, obj2, ...);

    // Send to user
    await hubContext.Clients.User(userId).SendAsync(callbackName, obj1, obj2, ...);

    // Send to group
    await hubContext.Clients.Group(groupId).SendAsync(callbackName, obj1, obj2, ...);

    // add user to group
    await hubContext.UserGroups.AddToGroupAsync(userId, groupName);

    // remove user from group
    await hubContext.UserGroups.RemoveFromGroupAsync(userId, groupName);
}
finally
{
    await hubContext.DisposeAsync();
}

Strongly typed hub

A strongly typed hub is a programming model that you can extract your client methods into an interface, so that avoid errors like misspelling the method name or passing the wrong parameter types.

Let's say we have a client method called ReceivedMessage with two string parameters. Without strongly typed hubs, you broadcast to clients through hubContext.Clients.All.SendAsync("ReceivedMessage", user, message). With strongly typed hubs, you first define an interface like this:

public interface IChatClient
{
    Task ReceiveMessage(string user, string message);
}

And then you create a strongly typed hub context, which implements IHubContext<Hub<T>, T>, T is your client method interface:

ServiceHubContext<IChatClient> serviceHubContext = await serviceManager.CreateHubContextAsync<IChatClient>(hubName, cancellationToken);

Finally, you could directly invoke the method:

await Clients.All.ReceiveMessage(user, message);

Except for the difference of sending messages, you could negotiate or manage groups with ServiceHubContext<T> just like ServiceHubContext.

Read more on strongly typed hubs in the ASP.NET Core docs here.

Transport type

This SDK can communicates to Azure SignalR Service with two transport types:

  • Transient: Create an Http request Azure SignalR Service for each message sent. The SDK simply wraps up Azure SignalR Service REST API in Transient mode. It's useful when you're unable to establish a WebSockets connection.
  • Persistent: Create a WebSockets connection first and then send all messages in this connection. It's useful when you send large number of messages.

Summary of serialization behaviors of the arguments in messages

Serialization Transient Persistent
Default JSON library Newtonsoft.Json The same as ASP.NET Core SignalR:
Newtonsoft.Json for .NET Standard 2.0;
System.Text.Json for .NET Core App 3.1 and above
MessagePack clients support since v1.21.0 since v1.20.0

JSON serialization

In Management SDK, the method arguments sent to clients are serialized into JSON. We have several ways to customize JSON serialization. We show all the ways in the order from the most recommended to the least recommended.

ServiceManagerOptions.UseJsonObjectSerializer(ObjectSerializer objectSerializer)

The most recommended way is to use a general abstract class ObjectSerializer, because it supports different JSON serialization libraries such as System.Text.Json and Newtonsoft.Json and it applies to all the transport types. Usually you don't need to implement ObjectSerializer yourself, as handy JSON implementations for System.Text.Json and Newtonsoft.Json are already provided.

  • When using System.Text.Json as JSON processing library The builtin JsonObjectSerializer uses System.Text.Json.JsonSerializer to for serialization/deserialization. Here's a sample to use camel case naming for JSON serialization:

    var serviceManager = new ServiceManagerBuilder()
        .WithOptions(o =>
        {
            o.ConnectionString = "***";
            o.UseJsonObjectSerializer(new JsonObjectSerializer(new JsonSerializerOptions
            {
                PropertyNamingPolicy = JsonNamingPolicy.CamelCase
            }));
        })
        .BuildServiceManager();
    
    
  • When using Newtonsoft.Json as JSON processing library First install the package Microsoft.Azure.Core.NewtonsoftJson from NuGet using .NET CLI:

    dotnet add package Microsoft.Azure.Core.NewtonsoftJson
    

    Here's a sample to use camel case naming with NewtonsoftJsonObjectSerializer:

    var serviceManager = new ServiceManagerBuilder()
        .WithOptions(o =>
        {
            o.ConnectionString = "***";
            o.UseJsonObjectSerializer(new NewtonsoftJsonObjectSerializer(new JsonSerializerSettings()
            {
                ContractResolver = new CamelCasePropertyNamesContractResolver()
            }));
        })
        .BuildServiceManager();
    
  • When using other JSON processing libraries

    You could also implement ObjectSerializer on your own. The following links might help:

ServiceManagerBuilder.WithNewtonsoftJson(Action<NewtonsoftServiceHubProtocolOptions> configure)

This method is only for Newtonsoft.Json users. Here's a sample to use camel case naming:

var serviceManager = new ServiceManagerBuilder()
    .WithNewtonsoftJson(o =>
    {
        o.PayloadSerializerSettings = new JsonSerializerSettings
        {
            ContractResolver = new CamelCasePropertyNamesContractResolver()
        };
    })
    .BuildServiceManager();
ServiceManagerOptions.JsonSerializerSettings (Deprecated)

This method only applies to transient transport type. Don't use this.

var serviceManager = new ServiceManagerBuilder()
    .WithOptions(o =>
    {
        o.JsonSerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
    })
    .BuildServiceManager();

Message Pack serialization

  1. You need to install Microsoft.AspNetCore.SignalR.Protocols.MessagePack package.

  2. To add a MessagePack protocol side-by-side with the default JSON protocol:

    var serviceManagerBuilder = new ServiceManagerBuilder()
        .AddHubProtocol(new MessagePackHubProtocol());
    
  3. To fully control the hub protocols, you can use

        var serviceManagerBuilder = new ServiceManagerBuilder()
            .WithHubProtocols(new MessagePackHubProtocol(), new JsonHubProtocol());
    

    WithHubProtocols first clears the existing protocols, and then adds the new protocols. You can also use this method to remove the JSON protocol and use MessagePack only.

For transient mode, by default the service side converts JSON payload to MessagePack payload and it's the legacy way to support MessagePack. However, we recommend you to add a MessagePack hub protocol explicitly as the legacy way might not work as you expect.

HTTP requests retry

For the transient mode, this SDK provides the capability to automatically resend requests when transient errors occur, as long as the requests are idempotent. To enable this capability, you can use the ServiceManagerOptions.RetryOptions property.

In particular, the following types of requests are retried:

  • For message requests that send messages to SignalR clients, the SDK retries the request if the HTTP response status code is greater than 500. When the HTTP response code is equal to 500, it might indicate a timeout on the service side, and retrying the request could result in duplicate messages.

  • For other types of requests, such as adding a connection to a group, the SDK retries the request under the following conditions:

    1. The HTTP response status code is in the 5xx range, or the request timed out with a status code of 408 (Request Timeout).
    2. The request timed out with a duration longer than the timeout length configured in ServiceManagerOptions.HttpClientTimeout.

The SDK can only retry idempotent requests, which are requests that have no other effect if they're repeated. If your requests aren't idempotent, you might need to handle retries manually.

Next steps

In this article, you learn how to use SignalR Service in your applications. Check the following articles to learn more about SignalR Service.