Cirreum.Runtime.RemoteConnections.WebSockets 2.0.2

dotnet add package Cirreum.Runtime.RemoteConnections.WebSockets --version 2.0.2
                    
NuGet\Install-Package Cirreum.Runtime.RemoteConnections.WebSockets -Version 2.0.2
                    
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="Cirreum.Runtime.RemoteConnections.WebSockets" Version="2.0.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Cirreum.Runtime.RemoteConnections.WebSockets" Version="2.0.2" />
                    
Directory.Packages.props
<PackageReference Include="Cirreum.Runtime.RemoteConnections.WebSockets" />
                    
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 Cirreum.Runtime.RemoteConnections.WebSockets --version 2.0.2
                    
#r "nuget: Cirreum.Runtime.RemoteConnections.WebSockets, 2.0.2"
                    
#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 Cirreum.Runtime.RemoteConnections.WebSockets@2.0.2
                    
#: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=Cirreum.Runtime.RemoteConnections.WebSockets&version=2.0.2
                    
Install as a Cake Addin
#tool nuget:?package=Cirreum.Runtime.RemoteConnections.WebSockets&version=2.0.2
                    
Install as a Cake Tool

Cirreum.Runtime.RemoteConnections.WebSockets

NuGet Version NuGet Downloads GitHub Release License .NET

App-facing registration for Cirreum raw WebSocket remote connections

Overview

Cirreum.Runtime.RemoteConnections.WebSockets registers typed raw WebSocket client connections on a Cirreum application builder, replacing the hand-written factory an application would otherwise compose. Registration gives the connection framework-owned receive and reconnect loops, credential refresh, observable state, and disposal.

The transport implementation ships in Cirreum.RemoteConnections.WebSockets and flows in transitively.

Usage

Write the connection type. It derives from WebSocketRemoteConnection and takes the framework-supplied context as its first constructor parameter. A connection speaking a protocol it does not own overrides OnFrameReceivedAsync and decodes frames itself:

public sealed class RealtimeVoiceConnection(WebSocketRemoteConnectionContext context)
    : WebSocketRemoteConnection(context) {

    public event Func<ReadOnlyMemory<byte>, Task>? AudioReceived;

    public Task SendAudioAsync(ReadOnlyMemory<byte> audio, CancellationToken ct = default) =>
        this.SendBytesAsync(audio, WebSocketMessageType.Binary, ct);

    protected override async ValueTask OnFrameReceivedAsync(
        ReadOnlyMemory<byte> payload, WebSocketMessageType messageType, CancellationToken ct) {

        if (messageType == WebSocketMessageType.Binary) {
            await (this.AudioReceived?.Invoke(payload) ?? Task.CompletedTask);
            return;
        }

        await base.OnFrameReceivedAsync(payload, messageType, ct);

    }

}

Leaving the seam alone instead gets Cirreum's { "method", "payload" } envelope, dispatched to handlers registered with On<T> — what a Cirreum server writes for a method-addressed push.

Per-session connections

A telephony bridge holds one outbound connection per active call, so the lifetime belongs to the session rather than to the application:

builder.AddRemoteConnectionFactory<RealtimeVoiceConnection>(options => {
    options.EndpointUri = new Uri("wss://provider.example.com/realtime");
});

This registers IRemoteConnectionFactory<RealtimeVoiceConnection> and no connection instance. The caller creates, connects, and disposes what it receives:

await using var voice = this._voiceFactory.Create();
await voice.ConnectAsync(ct);

Create optionally adjusts the registered options for one session — a different deployment, a per-call subprotocol — leaving the registration untouched for every later one.

Application-lifetime connections

A single connection that lives as long as the process registers directly:

builder.AddRemoteConnection<MarketDataConnection>(options => {
    options.EndpointUri = new Uri("wss://feed.example.com/stream");
});

It resolves as MarketDataConnection and as IRemoteConnection, and the container disposes it with the host — never dispose an injected connection. Registration does not connect; call ConnectAsync when the caller is ready.

Notes

  • One registration per connection type, in either shape. Registering the same type twice with equal options is a no-op; with different options, or under both verbs, it throws. Subclass the connection to reach a second endpoint.

  • Credentials resolve from the options when set, and otherwise from the host's ambient IRemoteConnectionCredentialSource. Every connect and reconnect attempt builds a fresh socket and re-resolves the credential, because a ClientWebSocket cannot be reconnected once closed. Name the audience on the options and the host mints for it:

    builder.AddRemoteConnectionFactory<RealtimeVoiceConnection>(options => {
        options.EndpointUri = new Uri("wss://provider.example.com/realtime");
        options.Scopes = ["api://contoso/access_as_user"];
    });
    

    A source registered keyed to a connection type is preferred over the unkeyed one for that connection, so a bridge holding one socket to a provider and another to its own backend can give each its own mechanism:

    services.AddKeyedScoped<IRemoteConnectionCredentialSource, ProviderCredentialSource>(typeof(RealtimeVoiceConnection));
    

    For a factory registration the options are copied per instance, so Create's adjustment — a different audience for one call — does not reach the registration every later session is built from.

  • The native transport is reachable through the optional configureTransport delegate, which receives ClientWebSocketOptions for each socket after the framework has configured it — the place to offer subprotocols.

Documentation

Contribution Guidelines

  1. Be conservative with new abstractions
    The API surface must remain stable and meaningful.

  2. Limit dependency expansion
    Only add foundational, version-stable dependencies.

  3. Favor additive, non-breaking changes
    Breaking changes ripple through the entire ecosystem.

  4. Include thorough unit tests
    All primitives and patterns should be independently testable.

  5. Document architectural decisions
    Context and reasoning should be clear for future maintainers.

  6. Follow .NET conventions
    Use established patterns from Microsoft.Extensions.* libraries.

Versioning

Cirreum.Runtime.RemoteConnections.WebSockets follows Semantic Versioning:

  • Major - Breaking API changes
  • Minor - New features, backward compatible
  • Patch - Bug fixes, backward compatible

License

This project is licensed under the MIT License - see the LICENSE file for details.


Cirreum Foundation Framework
Layered simplicity for modern .NET

Product Compatible and additional computed target framework versions.
.NET 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
2.0.2 122 8/30/2026
2.0.1 107 8/26/2026
2.0.0 100 8/26/2026
1.0.0 106 8/25/2026