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 builtinJsonObjectSerializer
usesSystem.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 packageMicrosoft.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)
ServiceManagerOptions.JsonSerializerSettings
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
You need to install
Microsoft.AspNetCore.SignalR.Protocols.MessagePack
package.To add a MessagePack protocol side-by-side with the default JSON protocol:
var serviceManagerBuilder = new ServiceManagerBuilder() .AddHubProtocol(new MessagePackHubProtocol());
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:
- The HTTP response status code is in the 5xx range, or the request timed out with a status code of 408 (Request Timeout).
- 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.