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
<PackageReference Include="Cirreum.Runtime.RemoteConnections.WebSockets" Version="2.0.2" />
<PackageVersion Include="Cirreum.Runtime.RemoteConnections.WebSockets" Version="2.0.2" />
<PackageReference Include="Cirreum.Runtime.RemoteConnections.WebSockets" />
paket add Cirreum.Runtime.RemoteConnections.WebSockets --version 2.0.2
#r "nuget: Cirreum.Runtime.RemoteConnections.WebSockets, 2.0.2"
#:package Cirreum.Runtime.RemoteConnections.WebSockets@2.0.2
#addin nuget:?package=Cirreum.Runtime.RemoteConnections.WebSockets&version=2.0.2
#tool nuget:?package=Cirreum.Runtime.RemoteConnections.WebSockets&version=2.0.2
Cirreum.Runtime.RemoteConnections.WebSockets
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 aClientWebSocketcannot 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
configureTransportdelegate, which receivesClientWebSocketOptionsfor each socket after the framework has configured it — the place to offer subprotocols.
Documentation
Contribution Guidelines
Be conservative with new abstractions
The API surface must remain stable and meaningful.Limit dependency expansion
Only add foundational, version-stable dependencies.Favor additive, non-breaking changes
Breaking changes ripple through the entire ecosystem.Include thorough unit tests
All primitives and patterns should be independently testable.Document architectural decisions
Context and reasoning should be clear for future maintainers.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 | Versions 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. |
-
net10.0
- Cirreum.RemoteConnections.WebSockets (>= 2.0.2)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.