In this lesson, you will learn how to orchestrate complex setup and teardown logic for singleton services that act as the backbone for your SignalR Hubs.
The Challenge of Singleton Longevity
When you use a singleton service to maintain state (like a distributed game engine or a high-frequency trading dashboard) accessed by a SignalR Hub, the Hub itself is transient. If your singleton service requires asynchronous initialization or a graceful shutdown to prevent data corruption, you cannot rely on simple constructor logic. Because the singleton is managed by the DI container, you need to tie its lifecycle to the application's overall lifetime while ensuring it remains responsive to the Hub's demands.
Implementing IHostedService for Orchestration
The most robust pattern for managing these complex dependencies is to decouple the "infrastructure" setup from the "business" singleton. By implementing IHostedService, you gain control over the StartAsync and StopAsync methods, which allows you to perform heavy setup—like establishing external message bus connections or pre-loading cache—before the SignalR Hub begins accepting traffic.
public class RealTimeStateProvider : IHostedService
{
// Singleton state accessed by Hubs
public ConcurrentDictionary<string, UserContext> ActiveUsers { get; } = new();
public async Task StartAsync(CancellationToken ct)
{
// Complex setup: Hydrate state from Redis or Database
await HydrateStateAsync();
}
public async Task StopAsync(CancellationToken ct)
{
// Critical teardown: Flush state and notify clients of server shutdown
await PersistStateAndCleanupAsync();
}
}
By registering this as both a singleton and an IHostedService in your Program.cs, you ensure the service is fully "warm" before any Hub can inject it. This prevents the "null reference" or "cold start" exceptions common when Hubs attempt to interact with uninitialized services during the brief window after the server starts but before the background workers finish their boot-up sequences.
This approach moves the burden of state management out of the Hub, keeping your Hubs lean and strictly focused on communication rather than plumbing.
Key Takeaway: Use IHostedService to wrap singleton services, ensuring complex setup and teardown routines complete fully before your SignalR Hubs attempt to access state.