Repository navigation
Releases: cirreum/Cirreum.Runtime.RemoteConnections.WebSockets
Release list
Release v2.0.2
Full Changelog: v2.0.1...v2.0.2
Release v2.0.1
Release v2.0.0
Cirreum.Runtime.RemoteConnections.WebSockets 2.0.0 — the registration names the connection
Why this release exists
The credential seam beneath this package changed. A credential source used to take no parameters, so
one registration answered identically for every connection an application opened — and where the
host could not infer an audience it supplied its own defaults. For a bridge holding several sockets
to several places, that is not a near miss; it is one answer for questions that have different
answers.
The fix is that a source is told which connection it is supplying for. This package is where that
information exists: it holds TConnection, and the transport beneath it does not.
What's new
A connection names its audience:
builder.AddRemoteConnectionFactory<RealtimeVoiceConnection>(options => {
options.EndpointUri = new Uri("wss://provider.example.com/realtime");
options.Scopes = ["api://contoso/access_as_user"];
});The registration stamps the connection type, and a source registered keyed to that type is
preferred over the unkeyed one:
services.AddKeyedScoped<IRemoteConnectionCredentialSource, ProviderCredentialSource>(typeof(RealtimeVoiceConnection));That matters more here than on the SignalR side. The founding consumer for raw WebSockets is a
telephony bridge holding one socket to a realtime provider and another to its own backend — two
mechanisms, two identity providers, in one process. Before this, both got whatever the single
ambient source returned.
Fixed
A factory-created connection carries the registered scopes. The factory copies the registered
options per instance, and that copy is the only path a per-session connection's options travel. It
omitted Scopes, which would have left every per-session connection's credential source with no
audience to mint for — silently, since a forgotten property looks exactly like one that was never
set.
The per-session verb is this package's common shape, so the omission would have reached most of its
consumers. Caught by a test written for the copy rather than for the feature.
Compatibility
- The registration verbs are unchanged, including their overloads, the
one-registration-per-connection-type rule, registration-time validation, and options-equality
dedup. - One
usingchanges where an application writes a connection type: the connection types moved
toCirreum.RemoteServices.Connections. - Declare
Scopeson connections whose credential comes from the host's session. A connection
carrying a provider key inAuthorizationHeaderor aCredentialProvidernever consults the
ambient source and is unaffected. See MIGRATION-v2.md.
See also
Cirreum.RemoteConnections.WebSockets2.0.0 — the transport that resolves the source, and where
any authorization scheme may be resolved per attempt rather than only Bearer.Cirreum.Contracts5.0.0 — the credential contract and the reasoning behind its shape.
Release v1.0.0
Cirreum.Runtime.RemoteConnections.WebSockets 1.0.0
First release of the app-facing registration surface for Cirreum raw WebSocket remote connections.
What this is for
Cirreum.RemoteConnections.WebSockets supplies the connection; this package supplies the line that
registers it. Without it an application composes the wiring itself — build the context from the
provider, construct the connection, decide its lifetime — the same way in every application, which
makes it exactly the kind of thing that drifts.
What it provides
AddRemoteConnectionFactory<TConnection>() is the verb most raw-WebSocket consumers want. A
telephony bridge holds one outbound connection per active call: N concurrent calls, N connections,
each created when the media stream opens and disposed when the call ends.
builder.AddRemoteConnectionFactory<RealtimeVoiceConnection>(options => {
options.EndpointUri = new Uri("wss://provider.example.com/realtime");
});It registers IRemoteConnectionFactory<TConnection> and no connection instance, so a status surface
enumerating standing connections never sees per-session ones. Ownership inverts with the lifetime —
the caller creates, connects, and disposes what the factory returns:
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.
AddRemoteConnection<TConnection>() serves the other lifetime: one connection for as long as
the process runs, such as a standing market-data feed. It resolves as TConnection and as
IRemoteConnection, and the container disposes it with the host. Registration does not connect.
Registration rules
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.
The registry is keyed by service collection rather than held process-wide. A registry shared across
a process would make a second container — a test host, a second builder — silently skip registrations
the first container had already claimed.
Options are validated as they are registered. A missing or relative endpoint surfaces while the
application is composing, not when something first resolves the connection.
Host neutrality
Both verbs are extension members on IDomainApplicationBuilder, which a Blazor WebAssembly builder
and a server-side builder both implement. There is no per-host variant, and no .Wasm package.
Requirements
Cirreum.RemoteConnections.WebSockets1.0.0 or later, which carries the transport and
WebSocketRemoteConnection. It flows in transitively, along withCirreum.Domain,
Cirreum.ContractsandCirreum.Kernel.- A host registering
IRemoteConnectionTokenSourceif connections are to present the session
credential without configuring one —Cirreum.Runtime.Wasm3.0.0 does.