Cocoar.SignalARRR.ProxyGenerator 5.0.0-beta.3

This is a prerelease version of Cocoar.SignalARRR.ProxyGenerator.
dotnet add package Cocoar.SignalARRR.ProxyGenerator --version 5.0.0-beta.3
                    
NuGet\Install-Package Cocoar.SignalARRR.ProxyGenerator -Version 5.0.0-beta.3
                    
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="Cocoar.SignalARRR.ProxyGenerator" Version="5.0.0-beta.3" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Cocoar.SignalARRR.ProxyGenerator" Version="5.0.0-beta.3" />
                    
Directory.Packages.props
<PackageReference Include="Cocoar.SignalARRR.ProxyGenerator" />
                    
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 Cocoar.SignalARRR.ProxyGenerator --version 5.0.0-beta.3
                    
#r "nuget: Cocoar.SignalARRR.ProxyGenerator, 5.0.0-beta.3"
                    
#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 Cocoar.SignalARRR.ProxyGenerator@5.0.0-beta.3
                    
#: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=Cocoar.SignalARRR.ProxyGenerator&version=5.0.0-beta.3&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Cocoar.SignalARRR.ProxyGenerator&version=5.0.0-beta.3&prerelease
                    
Install as a Cake Tool

SignalARRR

CI NuGet npm License

Typed bidirectional RPC over ASP.NET Core SignalR.

Server and client call each other's methods through shared interfaces — with compile-time proxy generation, streaming, cancellation propagation, and ASP.NET Core authorization. Clients available for .NET, TypeScript/JavaScript, and Swift.

Read the full documentation

Upgrading from 4.x? v5 carries breaking changes from a full code review. Most need nothing from you; what does is in the migration guide, grouped by whether it is likely to affect you at all.

Packages

.NET

Package Purpose
Cocoar.SignalARRR.Contracts [SignalARRRContract] attribute + source generator — reference from shared interface projects
Cocoar.SignalARRR.Server Server-side: HARRR hub, ServerMethods, authorization, ClientManager
Cocoar.SignalARRR.Client Client-side: HARRRConnection, typed proxies, event handlers
Cocoar.SignalARRR.DynamicProxy Opt-in runtime proxy fallback via DispatchProxy
Cocoar.SignalARRR.Client.FullFramework Client for .NET Framework 4.6.2+ — typed proxies, streaming, file transfer

TypeScript / JavaScript

npm install @cocoar/signalarrr

Swift (iOS / macOS)

.package(url: "https://github.com/cocoar-dev/Cocoar.SignalARRR.git", from: "5.0.0")

Quick Start

Define shared interfaces, set up the server, and call methods with full type safety:

// Shared interface
[SignalARRRContract]
public interface IChatHub {
    Task SendMessage(string user, string message);
    Task<List<string>> GetHistory();
}

// Client usage — one line to get a typed proxy
var chat = connection.GetTypedMethods<IChatHub>();
await chat.SendMessage("Alice", "Hello!");
// TypeScript client
const history = await connection.invoke<string[]>('ChatMethods.GetHistory');
// Swift client — @HubProxy macro generates the proxy
@HubProxy protocol IChatHub { ... }
let chat = connection.getTypedMethods(IChatHubProxy.self)

For full setup guides, streaming, authorization, and server-to-client calls, see the documentation.

Features

  • Typed bidirectional RPC — server and client call each other through shared interfaces
  • Compile-time proxy generation — Roslyn source generator (zero reflection)
  • Organized hub methods — split logic across ServerMethods<T> classes with full DI
  • StreamingIAsyncEnumerable<T>, IObservable<T>, ChannelReader<T> in both directions
  • HTTP stream references — file download/upload through SignalR hub methods
  • CancellationToken propagation — server can cancel client operations remotely
  • Authorization — method-level, class-level, and hub-level [Authorize]
  • Server-to-client calls from anywhere — inject ClientManager in controllers, background services, etc.
  • Four clients — .NET, .NET Framework, TypeScript/JavaScript, Swift
  • Typed broadcastsWithHub<T>().WithGroup().SendAsync<T>() for groups and filtered clients
  • Redis-compatible multi-node backplane — opt-in scale-out with Redis, Valkey, or Garnet

Redis-compatible backplane

SignalARRR stays pure in-memory by default. If you do not configure a backplane, behavior remains single-node and process-local exactly as before.

For multi-node scale-out, add the Cocoar.SignalARRR.Server.Backplane.Redis package and opt in. It is a separate package as of 5.0, so single-node applications do not carry StackExchange.Redis:

builder.Services.AddSignalARRR(b =>
    b.AddServerMethodsFrom(typeof(ChatHub).Assembly));

builder.Services.AddSignalARRRRedisBackplane(options => options
    .WithConnectionString("localhost:6379,abortConnect=false")
    .WithChannelPrefix("my-app")
    .WithNodeId($"{Environment.MachineName}-api-1"));

This works with Redis, Valkey, and Garnet because SignalARRR talks to a Redis-compatible backend via StackExchange.Redis.

What becomes cluster-aware

  • GetTypedMethods<T>(connectionId) send/invoke across nodes
  • WithHub<T>().SendAsync(...) across all nodes
  • WithGroup(...), WithUser(...), and WithAttribute(...) across nodes
  • InvokeAllAsync(...) and InvokeOneAsync(...) across nodes
  • AddToGroupAsync(...) / RemoveFromGroupAsync(...) for remote connections
  • Presence APIs on ClientManager:
    • GetConnectionsAsync<THub>()
    • GetConnectionsByUserAsync<THub>(...)
    • GetConnectionsInGroupAsync<THub>(...)
    • GetConnectionsByAttributeAsync<THub>(...)
    • GetOnlineUsersAsync<THub>()
    • IsUserOnlineAsync<THub>(...)

Cluster semantics

  • Transient transport: the backplane distributes live messages; it is not a durable queue or event store.
  • Eventual convergence: connection, group, user, and attribute metadata propagate quickly, but not atomically across all nodes. Right after connect/disconnect/group changes there can be a short convergence window.
  • Crash cleanup: dead nodes are removed by heartbeat + timeout sweep. Tune WithHeartbeatInterval(...) and WithNodeTimeout(...) if you want faster stale-node cleanup.
  • Safe fallback: without AddSignalARRRRedisBackplane(...), all APIs continue to use the old in-memory single-node path.

Connection loss semantics

What happens to in-flight work when a connection drops — worth knowing before you rely on it:

  • Pending invocations fail immediately, and are not safely retryable. When the connection drops, every outstanding invoke fails right away — a 50 ms blip is no different from a long outage. After reconnecting it is a new connection with a new ConnectionId; the lost answer is gone for good. And if the drop happened after the server executed but before the response arrived, the caller cannot know whether the call took effect — retry only operations that are idempotent.
  • SignalR's resilience features are available, but pass-through. MapSignalARRRHub<THub>(...) returns SignalR's HubEndpointConventionBuilder (so AllowStatefulReconnects() can be applied), and HARRRConnection.Create(...) hands you the real HubConnectionBuilder (so WithAutomaticReconnect() / WithStatefulReconnect() work as documented by SignalR). SignalARRR does not interfere with either: its own lifetime signals hang off SignalR's, which Stateful Reconnect extends. Under Stateful Reconnect the connection is resumed rather than replaced, keeping its ConnectionId, and SignalARRR's ClientManager registration — including group membership — comes through intact; there is an integration test for exactly that, severing the transport underneath a live connection. Note that a resume raises no Reconnecting/Reconnected events: the connection never counts as lost. Two pieces of connection-bound state are not covered by that test and remain unverified: an in-flight stream's ownership, and an outstanding upload slot. WithAutomaticReconnect() on its own always yields a new ConnectionId, so nothing connection-bound carries over there, by design.
  • A fire-and-forget call to a client cannot report failure. For a contract member returning void or Task, the server's send completes when the message reaches the transport — before the client runs the method. If the handler then throws, the error is logged on the client and nowhere else; the server saw a successful send. Members returning Task<T> or T do surface client-side failures, as a HubException. Give a member a return value when the server needs to know it worked.
  • Two deadlines run independently of connection state. The stream upload wait (StreamUploadTimeout, default 2 minutes) and the backplane invoke timeout (WithInvokeTimeout(...), default 15 seconds) keep ticking while a reconnect is bridging a gap — a long enough outage fails them even though the connection technically survives. Both are configurable; size them with reconnect windows in mind.

Framework Support

Target Version
.NET (server + client) .NET 8 / .NET 9 / .NET 10
.NET Framework (client) 4.6.2+ (via Cocoar.SignalARRR.Client.FullFramework)
TypeScript / JavaScript Node.js 22 / modern browsers
Swift (iOS / macOS) Swift 5.10+, iOS 14+ / macOS 11+

Building from Source

# .NET
dotnet build src/Cocoar.SignalARRR.slnx
dotnet test src/Cocoar.SignalARRR.slnx

# TypeScript
cd src/Cocoar.SignalARRR.Typescript && npm install && npm run build

# Swift
swift build && swift test

License

Apache License 2.0 — see LICENSE for details.

Contributing

See CONTRIBUTING.md for guidelines.

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

Showing the top 4 NuGet packages that depend on Cocoar.SignalARRR.ProxyGenerator:

Package Downloads
Cocoar.SignalARRR.Contracts

Contracts, attributes and source generator for SignalARRR proxy generation. Reference this package from any project that defines [SignalARRRContract] interfaces.

Cocoar.SignalARRR.Server

SignalARRR server library — typed bidirectional RPC over SignalR with authorization, streaming, server-to-client calls, and ServerMethods organization.

Cocoar.SignalARRR.DynamicProxy

Dynamic proxy fallback for Cocoar.SignalARRR — uses DispatchProxy for runtime interface proxy generation. Opt-in package for scenarios where compile-time source generation is not available.

Cocoar.SignalARRR.Client

SignalARRR client library — typed bidirectional RPC over SignalR with streaming, cancellation, and source-generated proxies.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
5.0.0-beta.3 158 8/18/2026
5.0.0-beta.2 87 8/18/2026
5.0.0-beta.1 88 8/14/2026
4.3.2 1,701 6/13/2026
4.3.1 306 6/5/2026
4.3.0 602 5/16/2026
4.3.0-beta.7 81 4/3/2026
4.2.3 613 4/10/2026
4.2.2 195 4/3/2026
4.2.1 186 4/2/2026
4.2.0 179 4/2/2026
4.1.0 178 3/26/2026
4.0.0 147 3/23/2026
4.0.0-beta.16 73 3/22/2026
4.0.0-beta.15 69 3/22/2026
4.0.0-beta.8 79 3/3/2026
4.0.0-beta.6 75 3/3/2026
4.0.0-beta.2 80 3/3/2026
0.1.0-beta.85 80 2/28/2026