Skip to content

9kbx/SignalRClient

Repository files navigation

Pandax.SignalRClient

SignalRClient is a lightweight wrapper around the ASP.NET Core SignalR client for building resilient .NET consumers.

NuGet package: Pandax.SignalRClient

中文文档

Features

  • 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

Target Framework

  • .NET 9.0

Installation

dotnet add package Pandax.SignalRClient

Core Types

  • BaseSignalRClient<TOptions>: the base class that creates and manages HubConnection
  • SignalRClientOptions: base options with Url and RetryPolicy
  • IAuthenticationProvider: abstraction used to provide an access token for SignalR requests
  • DefaultRetryPolicy: built-in retry policy that retries 5 times with a 5 second interval

Quick Start

The recommended integration pattern is:

  1. Implement IAuthenticationProvider
  2. Create your options type derived from SignalRClientOptions
  3. Create a client class derived from BaseSignalRClient<TOptions>
  4. Register the client in dependency injection
  5. Start it from a hosted service or your application entry point

1. Implement an authentication provider

using Pandax.SignalRClient;

public sealed class JwtAuthenticationProvider : IAuthenticationProvider
{
    public Task<string?> GetAccessTokenAsync()
    {
        return Task.FromResult<string?>("your-jwt-token");
    }
}

2. Create client options

using Pandax.SignalRClient;

public sealed class ChatClientOptions : SignalRClientOptions
{
}

Basic Usage

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);
    }
}

4. Register the client with DI

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;
    }
}

5. Configure and run it

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();

Example hosted service

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);
        }
    }
}

Configuration

The client options support at least these settings:

  • Url: the SignalR hub endpoint
  • RetryPolicy: a custom IRetryPolicy implementation for reconnects

Example configuration:

{
  "SignalR": {
    "HubUrl": "https://localhost:5001/chatHub"
  }
}

Reconnect Behavior

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();
});

Sample Projects

  • SignalRClientSample: sample client application using the library
  • SignalRServerSample: sample SignalR server for local testing

Release Workflow

This repository includes a GitHub Actions workflow that publishes the NuGet package when a GitHub Release is published.

  • Only the SignalRClient library is packed and published as Pandax.SignalRClient
  • Pre-releases are skipped
  • Both .nupkg and .snupkg packages are pushed to NuGet

Repository

About

简单封装了SignalR客户端库

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages