backgroundworker.net-7.0asp.net-core-signalr

Shared SignalR HubConnection for multiple BackgroundServices in .NET


My .NET BackgroundService application have multple workers and all of them connects to the same SignalR Hub. Each worker gets a unique ConnectionId which will not work in my case.

How, if possible, can I share the HubConnection between all of the workers to prevent different ConnectionIds?


Solution

  • I found a solution that solves my issue. I've created a HubService which every worker dependency inject and then calls EnsureConnectionEstablished() to make sure the connection is established.

    public class HubService
    {
            private readonly ILogger<SystemHealthWorker> _logger;
            private readonly ConfigurationService _config;
            private HubConnection _connection;
    
            public HubService(ILogger<SystemHealthWorker> logger, ConfigurationService configService)
            {
                _logger = logger;
                _config = configService;
            }
    
            public async Task<bool> EnsureConnectionEstablished()
            {
                _logger.LogDebug("Ensures that the hub connection is established.");
    
                if (_connection == null || _connection.State == HubConnectionState.Disconnected)
                {
                    _logger.LogDebug("Hub connection is not established.");
    
                    var config = await _config.GetConfiguration();
                    if (config == null || string.IsNullOrEmpty(config.ServerAddress?.ToString()))
                    {
                        throw new Exception("Invalid config. Hub connection will not be established.");
                    }
                    else if (string.IsNullOrWhiteSpace(config.AccessToken))
                    {
                        throw new Exception("Invalid access token.");
                    }
    
                    var hubUrl = new Uri(config.ServerAddress);
                    _logger.LogInformation($"Connecting to hub ({hubUrl})");
    
                    _logger.LogDebug("Building hub connection.");
                    _connection = new HubConnectionBuilder()
                    .WithUrl(hubUrl, options => { options.AccessTokenProvider = () => Task.FromResult(config.AccessToken); })
                    .WithAutomaticReconnect(new[] { TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(60), TimeSpan.FromSeconds(120) })
                    .Build();
    
                    _connection.Reconnecting += OnReconnecting;
                    _connection.Reconnecting += OnReconnected;
                    _connection.Closed += OnClosed;
    
                    await _connection.StartAsync();
    
                    _logger.LogInformation($"Connected to hub with id {_connection.ConnectionId}.");
                }
    
                return _connection?.State == HubConnectionState.Connected;
            }
     }