In this lesson, you will learn how to map transient SignalR connection IDs to persistent user identities to maintain state across network interruptions.
When a client connects to a SignalR Hub, it is assigned a unique Context.ConnectionId. However, this ID is volatile—if the user refreshes their browser or experiences a brief network flicker, the connection drops, a new ID is generated, and your server loses track of the previous session state. To manage state persistence, you must decouple the transport-level ID from the application-level User Identity.
Mapping Identity to Connection
The most robust approach involves using IUserIdProvider or associating a persistent identifier (like a UserId claim) with the active connection. By default, SignalR uses the NameIdentifier claim. You can leverage Groups to manage this relationship. Instead of sending messages to a specific ConnectionId, you add that connection to a group named after the user’s permanent ID:
public override async Task OnConnectedAsync()
{
string userId = Context.UserIdentifier; // Extracted from claims
await Groups.AddToGroupAsync(Context.ConnectionId, userId);
// Retrieve persistent state from your service layer
var state = await _stateService.GetStateAsync(userId);
await Clients.Caller.SendAsync("RestoreState", state);
await base.OnConnectedAsync();
}
Handling Reconnections
When a client reconnects, the OnConnectedAsync method triggers again. Because you are using the persistent userId as a Group identifier, you don't need to manually update your database mappings every time. When you need to send a message to that user, you broadcast to the group: Clients.Group(userId).SendAsync(...). Even if the underlying ConnectionId changed, the user remains part of their unique group, ensuring your messages reach the correct destination regardless of the physical connection state.
By anchoring your messaging logic to a persistent identity rather than the fleeting ConnectionId, you ensure that the application state remains coherent even as the underlying transport layer resets.
Key Takeaway: Always map transient SignalR Connection IDs to persistent User IDs via Groups to maintain a seamless session experience across transport reconnections.