Shaunebu.Common.SignalRManager 1.0.0

dotnet add package Shaunebu.Common.SignalRManager --version 1.0.0
                    
NuGet\Install-Package Shaunebu.Common.SignalRManager -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Shaunebu.Common.SignalRManager" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Shaunebu.Common.SignalRManager" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Shaunebu.Common.SignalRManager" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Shaunebu.Common.SignalRManager --version 1.0.0
                    
#r "nuget: Shaunebu.Common.SignalRManager, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Shaunebu.Common.SignalRManager@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Shaunebu.Common.SignalRManager&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Shaunebu.Common.SignalRManager&version=1.0.0
                    
Install as a Cake Tool

A comprehensive, enterprise-grade SignalR client library for .NET that provides robust connection management, advanced resilience patterns, and production-ready observability. NuGet Version

NET Support NET Support NET Support Support

https://img.shields.io/badge/license-MIT-green

✨ Features

🔌 Connection Management

  • Automatic Reconnection - Handles transient failures gracefully

  • Connection State Tracking - Real-time state monitoring with events

  • Configurable Timeouts - Customizable connection and handshake timeouts

  • Multi-Transport Support - WebSockets, Server-Sent Events, Long Polling

📨 Message Processing

  • Intelligent Batching - Configurable batch sizes and intervals

  • Priority Queuing - Priority-based message processing

  • Offline Queue - Message persistence during disconnections

  • Batch Processing - Efficient bulk message delivery

🛡️ Resilience & Reliability

  • Polly Integration - Advanced retry policies with exponential backoff

  • Circuit Breaker - Prevents cascade failures

  • Error Isolation - Handler errors don't break the system

  • Graceful Degradation - Maintains partial functionality during failures

📊 Observability

  • Comprehensive Metrics - Connection, message, and performance metrics

  • Structured Logging - Detailed logging with configurable levels

  • State Change Events - Real-time connection state notifications

  • Custom Exporters - Extensible metrics exporting

🔧 Developer Experience

  • Type-Safe Wrappers - Compile-time safety for hub methods

  • Fluent Configuration - Intuitive builder pattern setup

  • Dependency Injection - Seamless ASP.NET Core integration

  • Async/Await Support - Full asynchronous operation support

🚀 Quick Start

Installation

dotnet add package Shaunebu.SignalRManager

Basic Usage

// Create and configure the manager
var manager = new SignalRManagerBuilder()
    .WithHubUrl("https://api.example.com/hubs/chat")
    .WithBatching(batchSize: 20, batchInterval: TimeSpan.FromMilliseconds(250))
    .WithPollyRetryPolicy(maxRetries: 5)
    .WithMetricsExporter(new ConsoleMetricsExporter())
    .WithAutoReconnect(enabled: true, maxAttempts: 3)
    .Build();

// Initialize connection
await manager.InitializeAsync();

// Register message handlers
manager.RegisterHandler<string, string>("ReceiveMessage", 
    (user, message) => Console.WriteLine($"{user}: {message}"));

// Send messages
await manager.InvokeAsync("SendMessage", new object[] { "John", "Hello World!" });

// Clean shutdown
await manager.ShutdownAsync();

📖 Comprehensive Examples

Type-Safe Hub Clients

// Create type-safe client wrapper
public class ChatHubClient
{
    private readonly ISignalRManager _manager;
    
    public ChatHubClient(ISignalRManager manager) => _manager = manager;
    
    public Task SendMessageAsync(string user, string message) =>
        _manager.InvokeAsync<object>("SendMessage", new object[] { user, message });
    
    public IDisposable OnMessageReceived(Action<string, string> handler) =>
        _manager.RegisterHandler<string, string>("ReceiveMessage", handler);
}

// Usage
var chatClient = new ChatHubClient(manager);
await chatClient.SendMessageAsync("Alice", "Hello from type-safe client!");
chatClient.OnMessageReceived((user, msg) => Console.WriteLine($"{user}: {msg}"));

Advanced Configuration

var manager = new SignalRManagerBuilder()
    .WithHubUrl("https://api.example.com/hubs/notifications")
    // Resilience
    .WithPollyRetryPolicy(
        maxRetries: 5, 
        initialDelay: TimeSpan.FromSeconds(1),
        maxDelay: TimeSpan.FromMinutes(2))
    .WithCircuitBreakerPersistence(new RedisCircuitBreakerPersistence())
    // Performance
    .WithBatching(batchSize: 50, batchInterval: TimeSpan.FromMilliseconds(500))
    .WithOfflineQueue(enabled: true)
    // Security
    .WithEncryptor(new AesEncryptor(key, iv))
    .WithHeader("Authorization", "Bearer your-token")
    // Observability
    .WithMetricsExporter(new ApplicationInsightsMetricsExporter())
    .WithLogger(logger)
    // Advanced
    .WithTransport(TransportType.WebSockets)
    .WithTimeout(connectionTimeout: TimeSpan.FromSeconds(30))
    .ConfigureConnection(builder => 
        builder.WithAutomaticReconnect(new[] { TimeSpan.Zero, TimeSpan.FromSeconds(2) }))
    .Build();

ASP.NET Core Integration

// Program.cs
builder.Services.AddSignalRManager(options =>
{
    options.HubUrl = "https://api.example.com/hubs/chat";
    options.EnableBatching = true;
    options.BatchSize = 20;
    options.EnableOfflineQueue = true;
    options.AutoReconnect = true;
})
.AddTypedHubClients(); // Optional: for type-safe clients

// Controller usage
public class NotificationController(ISignalRManager signalRManager)
{
    [HttpPost]
    public async Task<IActionResult> SendNotification([FromBody] NotificationRequest request)
    {
        await signalRManager.InvokeAsync("SendNotification", new object[] { request.Message });
        return Ok();
    }
}

🔧 Configuration Options

SignalRManagerOptions

Property Default Description
HubUrl Required SignalR hub URL
EnableBatching true Enable message batching
BatchSize 10 Maximum messages per batch
BatchInterval 250ms Maximum time to wait for batch
EnableOfflineQueue true Persist messages when offline
HeartbeatInterval 30s Heartbeat check interval
AutoReconnect true Automatic reconnection
MaxReconnectAttempts 5 Maximum reconnection attempts
ConnectionTimeout 30s Connection establishment timeout
TransportType All Preferred transport type

📊 Monitoring & Metrics

Built-in Metrics

public interface IMetricsExporter
{
    void OnConnected(string connectionId);
    void OnDisconnected(string? connectionId);
    void OnReconnectAttempt(int attempt);
    void OnMessageSent();
    void OnMessageBatchProcessed(int batchSize);
    void OnCircuitBreakerStateChange(CircuitBreakerState state);
    void OnError(Exception exception, string operation);
}

Custom Metrics Exporter

public class CustomMetricsExporter : IMetricsExporter
{
    public void OnConnected(string connectionId)
    {
        // Integrate with your monitoring system
        Metrics.Increment("signalr.connections.active");
        Logger.LogInformation("Client connected: {ConnectionId}", connectionId);
    }
    
    // Implement other methods...
}

🛡️ Resilience Patterns

Custom Retry Policy

public class CustomRetryPolicy : IRetryPolicy
{
    public TimeSpan? NextDelay(int attempt, Exception? lastException)
    {
        if (IsFatalException(lastException)) return null;
        
        return attempt switch
        {
            < 3 => TimeSpan.FromSeconds(1 * attempt),
            < 5 => TimeSpan.FromSeconds(5),
            _ => null // Stop retrying
        };
    }
    
    private bool IsFatalException(Exception? ex) => 
        ex is OperationCanceledException or ObjectDisposedException;
}

Circuit Breaker with Persistence

// Redis persistence example
public class RedisCircuitBreakerPersistence : ICircuitBreakerPersistence
{
    private readonly IDatabase _redis;
    
    public async Task<CircuitState?> LoadStateAsync(string circuitName) =>
        await _redis.StringGetAsync($"circuitbreaker:{circuitName}");
    
    public async Task SaveStateAsync(string circuitName, CircuitState state) =>
        await _redis.StringSetAsync($"circuitbreaker:{circuitName}", state);
}

📊 Feature Comparison Table

Feature SignalRManager Microsoft SignalR Client Azure SignalR Service SDK SignalR.Client.Core
Connection Management ✅ Advanced ✅ Basic ✅ Managed ✅ Basic
Automatic Reconnection ✅ Configurable ✅ Limited ✅ Managed ✅ Limited
Message Batching ✅ Intelligent ❌ None ❌ None ❌ None
Priority Queuing ✅ Yes ❌ No ❌ No ❌ No
Offline Queue ✅ Persistent ❌ No ❌ No ❌ No
Retry Policies ✅ Polly + Custom ✅ Basic ✅ Basic ✅ Basic
Circuit Breaker ✅ Yes ❌ No ❌ No ❌ No
State Persistence ✅ Yes ❌ No ❌ No ❌ No
Metrics & Telemetry ✅ Comprehensive ❌ Minimal ✅ Limited ❌ No
Type-Safe Wrappers ✅ Yes ❌ No ❌ No ❌ No
DI Integration ✅ First-class ✅ Basic ✅ Basic ✅ Basic
Configuration ✅ Fluent API ✅ Basic ✅ Basic ✅ Basic
Performance ✅ Optimized ✅ Good ✅ Good ✅ Good
Learning Curve 🟡 Moderate 🟢 Easy 🟢 Easy 🟢 E

🔍 Troubleshooting

Common Issues

Connection Failures

// Enable detailed logging
var manager = new SignalRManagerBuilder()
    .WithHubUrl("your-hub-url")
    .WithLogger(LoggerFactory.Create(builder => 
        builder.AddConsole().SetMinimumLevel(LogLevel.Debug)))
    .Build();

Message Delivery Issues

// Monitor batch events
manager.OnMessageBatched += (method, count) => 
    Console.WriteLine($"{count} messages batched for {method}");

// Check offline queue
manager.OnOfflineQueueSizeChanged += size =>
    Console.WriteLine($"Offline queue size: {size}");

📈 Performance Tips

  1. Batch Sizing: Adjust BatchSize and BatchInterval based on your throughput requirements

  2. Priority Queuing: Use message priorities for critical messages

  3. Connection Pooling: Reuse SignalRManager instances when possible

  4. Memory Management: Monitor offline queue size in high-volume scenarios

📄 License

This project is licensed under the MIT License.

🏆 Acknowledgments

  • Built on top of Microsoft's SignalR Client

  • Resilience patterns inspired by Polly

  • Metrics design influenced by OpenTelemetry standards

<br><br>

🎯 Hub Generator - Type-Safe SignalR Development

⚡ Automatic Interface Generation

SignalRManager includes a powerful Source Generator that automatically creates strongly-typed interfaces for ALL classes that inherit from Hub, eliminating magic strings and providing compile-time safety.

🔧 How It Works

1. Simply Inherit from Hub (No Attributes Needed!)
// No attributes required! The generator automatically detects Hub classes
public class ChatHub : Hub
{
    [ServerMethod]
    public Task SendMessage(string user, string message)
    {
        return Clients.All.SendAsync("ReceiveMessage", user, message);
    }
    
    [ServerMethod]
    public Task JoinGroup(string groupName)
    {
        return Groups.AddToGroupAsync(Context.ConnectionId, groupName);
    }
    
    [ClientMethod]
    private Task ReceiveMessage(string user, string message) => Task.CompletedTask;
    
    [ClientMethod]
    private Task UserJoined(string user) => Task.CompletedTask;
}

public class NotificationHub : Hub
{
    [ServerMethod]
    public Task SendNotification(string message)
    {
        return Clients.All.SendAsync("ReceiveNotification", message);
    }
    
    [ClientMethod]
    private Task ReceiveNotification(string message) => Task.CompletedTask;
}
2. Generated Interfaces (Automatically Created)

IChatHubServer.g.cs (Server-side interface):

public interface IChatHubServer
{
    Task SendMessage(string user, string message);
    Task JoinGroup(string groupName);
}

IChatHubClient.g.cs (Client-side interface):

public interface IChatHubClient
{
    Task ReceiveMessage(string user, string message);
    Task UserJoined(string user);
}

INotificationHubServer.g.cs:

public interface INotificationHubServer
{
    Task SendNotification(string message);
}

INotificationHubClient.g.cs:

public interface INotificationHubClient
{
    Task ReceiveNotification(string message);
}

🚀 Usage with Generated Interfaces

Client-Side Usage
// Type-safe handler registration
await manager.RegisterHandler<IChatHubClient, string, string>(
    c => c.ReceiveMessage,
    async (user, msg) => Console.WriteLine($"{user}: {msg}"));

// Type-safe method invocation
await manager.InvokeAsync<IChatHubServer, string, string>(
    s => s.SendMessage,
    "John", 
    "Hello from type-safe client!");

// Multiple hubs support
await manager.RegisterHandler<INotificationHubClient, string>(
    c => c.ReceiveNotification,
    async (msg) => Console.WriteLine($"Notification: {msg}"));
Server-Side Usage (Optional)
// Implement the generated interface on your hub (optional)
public class ChatHub : Hub, IChatHubServer
{
    public async Task SendMessage(string user, string message)
    {
        // Your implementation
        await Clients.All.SendAsync("ReceiveMessage", user, message);
    }
    
    public async Task JoinGroup(string groupName)
    {
        await Groups.AddToGroupAsync(Context.ConnectionId, groupName);
    }
}

⚙️ Method Attributes

// Use these attributes to specify which methods to include
[ServerMethod]  // Marks hub methods callable by clients (REQUIRED)
[ClientMethod]  // Marks client methods callable by server (REQUIRED)

// Examples:
public class ChatHub : Hub
{
    [ServerMethod]  // This method can be called by clients
    public Task SendMessage(string user, string message) 
        => Clients.All.SendAsync("ReceiveMessage", user, message);
    
    [ClientMethod]  // This method can be called by server on clients
    private Task ReceiveMessage(string user, string message) => Task.CompletedTask;
}

🎯 Benefits of Hub Generator

1. Zero Configuration
  • ✅ Automatically detects ALL Hub classes

  • ✅ No attributes needed on classes

  • ✅ Generates interfaces at compile time

2. Compile-Time Safety
// ✅ Compiles - type-safe
await manager.InvokeAsync<IChatHubServer, string, string>(
    s => s.SendMessage, "user", "message");

// ❌ Compile error - method doesn't exist
await manager.InvokeAsync<IChatHubServer, string, string>(
    s => s.NonExistentMethod, "user", "message"); // ERROR!
3. IntelliSense Support
  • ✅ Full IntelliSense for hub methods

  • ✅ Parameter type checking

  • ✅ Method discovery

4. Refactoring Friendly
  • ✅ Rename hub methods safely

  • ✅ Change parameters with compile-time checks

  • ✅ Find all references works perfectly

🔧 Setup Requirements

1. Add to Your Project

<PackageReference Include="Shaunebu.SignalRManager.HubGenerator" Version="1.0.0" />
2. Enable in Project File
<PropertyGroup>
  <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
  <CompilerGeneratedFilesOutputPath>Generated</CompilerGeneratedFilesOutputPath>
</PropertyGroup>

📁 Generated Files Location

Generated interfaces are created in:

/bin/Debug/net8.0/Generated/Shaunebu.SignalRManager.HubGenerator/
  - IChatHubClient.g.cs
  - IChatHubServer.g.cs
  - INotificationHubClient.g.cs
  - INotificationHubServer.g.cs

🚀 Advanced Usage

Multiple Hubs Project
// All hubs are automatically processed
public class ChatHub : Hub { /* ... */ }
public class NotificationHub : Hub { /* ... */ }
public class AdminHub : Hub { /* ... */ }
public class AnalyticsHub : Hub { /* ... */ }

// All interfaces are generated automatically:
// IChatHubClient, IChatHubServer
// INotificationHubClient, INotificationHubServer  
// IAdminHubClient, IAdminHubServer
// IAnalyticsHubClient, IAnalyticsHubServer
Custom Method Filtering
public class SecureHub : Hub
{
    [ServerMethod]
    public Task PublicMethod(string data) { /* ... */ }
    
    // This won't be included in the interface (no attribute)
    public Task InternalMethod(string data) { /* ... */ }
    
    [ClientMethod] 
    private Task ClientCallback(string result) => Task.CompletedTask;
}

The Hub Generator transforms SignalR development from string-based magic to type-safe, compiler-verified code, making your SignalR applications more maintainable and less error-prone! 🎯

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 185 10/31/2025