SignalRClient is a lightweight wrapper around the ASP.NET Core SignalR client for building resilient .NET consumers.
NuGet package: Pandax.SignalRClient
- Wraps SignalR client connection setup into a reusable base client
- Supports access token injection through a custom authentication provider
- Supports configurable retry policies for reconnect behavior
- Works well in background services and long-running worker processes
- .NET 9.0
dotnet add package Pandax.SignalRClientBaseSignalRClient<TOptions>: the base class that creates and managesHubConnectionSignalRClientOptions: base options withUrlandRetryPolicyIAuthenticationProvider: abstraction used to provide an access token for SignalR requestsDefaultRetryPolicy: built-in retry policy that retries 5 times with a 5 second interval
The recommended integration pattern is:
- Implement
IAuthenticationProvider - Create your options type derived from
SignalRClientOptions - Create a client class derived from
BaseSignalRClient<TOptions> - Register the client in dependency injection
- Start it from a hosted service or your application entry point
using Pandax.SignalRClient;
public sealed class JwtAuthenticationProvider : IAuthenticationProvider
{
public Task<string?> GetAccessTokenAsync()
{
return Task.FromResult<string?>("your-jwt-token");
}
}using Pandax.SignalRClient;
public sealed class ChatClientOptions : SignalRClientOptions
{
}using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Pandax.SignalRClient;
public interface IChatClient
{
Task StartAsync(CancellationToken ct = default);
Task SendMessageAsync(string user, string message);
event Action<string, string>? OnMessageReceived;
}
public sealed class ChatClient : BaseSignalRClient<SignalRClientOptions>
{
public event Action<string, string>? OnMessageReceived;
public ChatClient(
IAuthenticationProvider authenticationProvider,
IOptions<SignalRClientOptions> options,
ILogger<ChatClient> logger)
: base(authenticationProvider, options, logger)
{
}
protected override void OnRegisterHubEvents()
{
_connection.On<string, string>("ReceiveMessage", (user, message) =>
{
OnMessageReceived?.Invoke(user, message);
});
}
public Task SendMessageAsync(string user, string message)
{
return _connection.InvokeAsync("SendMessage", user, message);
}
}using Microsoft.Extensions.DependencyInjection;
public static class ChatClientServiceCollectionExtensions
{
public static IServiceCollection AddChatClient(
this IServiceCollection services,
Action<ChatClientOptions> configure)
{
services.Configure(configure);
services.AddSingleton<IChatClient, ChatClient>();
return services;
}
}using Microsoft.Extensions.Hosting;
using Pandax.SignalRClient;
var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddHttpClient();
builder.Services.AddSingleton<IAuthenticationProvider, JwtAuthenticationProvider>();
builder.Services.AddChatClient(options =>
{
options.Url = builder.Configuration["SignalR:HubUrl"]
?? throw new InvalidOperationException("Missing configuration: SignalR:HubUrl");
});
builder.Services.AddHostedService<ChatWorker>();
await builder.Build().RunAsync();using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
public sealed class ChatWorker(IChatClient chatClient, ILogger<ChatWorker> logger)
: BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
chatClient.OnMessageReceived += (user, message) =>
{
logger.LogInformation("New message from {User}: {Message}", user, message);
};
await chatClient.StartAsync(stoppingToken);
while (!stoppingToken.IsCancellationRequested)
{
await chatClient.SendMessageAsync("ConsoleApp", $"Heartbeat {DateTime.Now:O}");
await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken);
}
}
}The client options support at least these settings:
Url: the SignalR hub endpointRetryPolicy: a customIRetryPolicyimplementation for reconnects
Example configuration:
{
"SignalR": {
"HubUrl": "https://localhost:5001/chatHub"
}
}By default, the library uses DefaultRetryPolicy, which retries up to 5 times with a 5 second delay.
You can replace it with your own implementation:
using Microsoft.AspNetCore.SignalR.Client;
public sealed class CustomRetryPolicy : IRetryPolicy
{
public TimeSpan? NextRetryDelay(RetryContext retryContext)
{
return retryContext.PreviousRetryCount < 10
? TimeSpan.FromSeconds(3)
: null;
}
}Then register it through options:
builder.Services.AddChatClient(options =>
{
options.Url = builder.Configuration["SignalR:HubUrl"]!;
options.RetryPolicy = new CustomRetryPolicy();
});SignalRClientSample: sample client application using the librarySignalRServerSample: sample SignalR server for local testing
This repository includes a GitHub Actions workflow that publishes the NuGet package when a GitHub Release is published.
- Only the
SignalRClientlibrary is packed and published asPandax.SignalRClient - Pre-releases are skipped
- Both
.nupkgand.snupkgpackages are pushed to NuGet
- Source: github.com/9kbx/SignalRClient
- License: MIT