Skip to content

Client Comparison

SignalARRR has four client implementations. This page shows what each client supports.

Platform Support

.NET.NET FrameworkTSSwift
Targetnet8.0 / net9.0 / net10.0net462+ (netstandard2.0)Node 22 / browsersiOS 14+ / macOS 11+
PackageCocoar.SignalARRR.ClientCocoar.SignalARRR.Client.FullFramework@cocoar/signalarrrCocoarSignalARRR

RPC

.NET.NET FrameworkTSSwift
Invoke (await result)
Send (fire & forget)
Generic arguments

Item Streaming

.NET.NET FrameworkTSSwift
Server→Client
Client→Server
Stream method handlers

.NET Framework streaming

The FullFramework client supports streaming via polyfill packages (Microsoft.Bcl.AsyncInterfaces and System.Threading.Channels). IAsyncEnumerable<T>, ChannelReader<T>, and await foreach all work on .NET Framework 4.6.2+.

Server-to-Client RPC

.NET.NET FrameworkTSSwift
Method handlers
Interface registration
CancellationToken

File Transfer (HTTP Stream References)

.NET.NET FrameworkTSSwift
Download (Stream return)
Upload (Stream parameter)

Authorization

.NET.NET FrameworkTSSwift
Token provider
Auto challenge/refresh

Proxy Generation

.NET.NET FrameworkTSSwift
Compile-time proxiesSource Generator@HubProxy Macro
Runtime proxiesDispatchProxyDispatchProxy

.NET Framework uses DispatchProxy only

The Roslyn source generator requires projects to reference Cocoar.SignalARRR.Contracts which targets net8.0+. On .NET Framework, typed proxies are created at runtime via DispatchProxy. The interfaces don't need [SignalARRRContract] — any C# interface works.

Connection

.NET.NET FrameworkTSSwift
Auto-reconnect
Connection events
Raw SignalR access
Raw on/off overloads168

Concurrency Model

.NET.NET FrameworkTSSwift
Async patternasync/awaitasync/awaitPromiseasync/await
CancellationCancellationTokenCancellationTokenAbortSignalActor
SerializationSystem.Text.JsonSystem.Text.JsonJSONCodable
MessagePack✓ (optional)✓ (optional)✓ (optional)✓ (built-in)

MessagePack is optional

MessagePack support is not included by default. Install the protocol package separately and register it on the connection builder:

.NET / .NET Framework:

bash
dotnet add package Microsoft.AspNetCore.SignalR.Protocols.MessagePack
csharp
builder.AddMessagePackProtocol();

TypeScript:

bash
npm install @microsoft/signalr-protocol-msgpack
ts
builder.withHubProtocol(new MessagePackHubProtocol());

Server:

csharp
builder.Services.AddSignalR().AddMessagePackProtocol();

Swift has MessagePack built-in — use hubProtocol: .messagepack when creating the connection.

SignalARRR auto-detects the active protocol and uses the correct serializer. No additional configuration needed.

Transport

.NET.NET FrameworkTSSwift
WebSockets
Server-Sent Events
Long Polling
Transport fallback

API Comparison

Creating a connection

csharp
var connection = HARRRConnection.Create(builder =>
{
    builder.WithUrl("https://server/hub");
});
await connection.StartAsync();
csharp
var connection = HARRRConnection.Create(builder =>
{
    builder.WithUrl("https://server/hub");
});
await connection.StartAsync();
ts
const connection = HARRRConnection.create(builder => {
    builder.withUrl('https://server/hub');
});
await connection.start();
swift
let connection = await HARRRConnection.create(
    url: "https://server/hub"
)
try await connection.start()

Typed proxies

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

// Client: get typed proxy
var chat = connection.GetTypedMethods<IChatHub>();
await chat.SendMessage("Alice", "Hello!");
csharp
// Define interface (no attribute needed)
public interface IChatHub {
    Task SendMessage(string user, string message);
    Task<List<string>> GetHistory();
}

// Client: get typed proxy (runtime-generated via DispatchProxy)
var chat = connection.GetTypedMethods<IChatHub>();
await chat.SendMessage("Alice", "Hello!");
swift
// Client: mark with @HubProxy
@HubProxy
protocol IChatHub {
    func sendMessage(user: String, message: String) async throws
    func getHistory() async throws -> [String]
}

// Client: get typed proxy
let chat = connection.getTypedMethods(IChatHubProxy.self)
try await chat.sendMessage(user: "Alice", message: "Hello!")

TypeScript has no typed proxy generation — method names are passed as strings.

Invoke / Send / Stream

csharp
// Invoke (await result)
var result = await connection.InvokeCoreAsync<string>(message, ct);

// Send (fire-and-forget)
await connection.SendCoreAsync(message, ct);

// Stream
await foreach (var item in connection.StreamAsyncCore<int>(message, ct))
    Console.WriteLine(item);
csharp
// Invoke (await result)
var result = await connection.InvokeCoreAsync<string>(message, ct);

// Send (fire-and-forget)
await connection.SendCoreAsync(message, ct);

// Stream (via polyfill packages)
await foreach (var item in connection.StreamAsyncCore<int>(message, ct))
    Console.WriteLine(item);
ts
// Invoke
const result = await connection.invoke<string>('Method.Name');

// Send
await connection.send('Method.Name', arg1, arg2);

// Stream
connection.stream<number>('Method.Name').subscribe({
    next: item => console.log(item),
});
swift
// Invoke
let result: String = try await connection.invoke("Method.Name")

// Send
try await connection.send("Method.Name", arguments: arg1, arg2)

// Stream
for try await item in try await connection.stream("Method.Name") as AsyncThrowingStream<Int, Error> {
    print(item)
}

Server-to-client handlers

csharp
connection.RegisterInterface<IChatClient, ChatClientImpl>(new ChatClientImpl());
csharp
connection.RegisterInterface<IChatClient, ChatClientImpl>(new ChatClientImpl());
ts
connection.onServerMethod('ReceiveMessage', (user, message) => {
    console.log(`${user}: ${message}`);
});
swift
await connection.onServerMethod("ReceiveMessage") { args in
    print("\(args[0]): \(args[1])")
    return AnyCodable.nil
}

CancellationToken handling

ClientMechanismType
.NETStandard CancellationTokenNative
.NET FrameworkStandard CancellationTokenNative
TypeScriptAbortSignal via CancellationManager (Map-based)Web API
SwiftActor-based CancellationManager with continuationsSwift Concurrency

Packages

ClientPackageInstall
.NETCocoar.SignalARRR.Clientdotnet add package
.NET FrameworkCocoar.SignalARRR.Client.FullFrameworkdotnet add package
TypeScript@cocoar/signalarrrnpm install
SwiftCocoarSignalARRR + CocoarSignalARRRMacrosSwift Package Manager

Released under the Apache-2.0 License.