Cirreum.Invocation.SignalR
1.2.1
dotnet add package Cirreum.Invocation.SignalR --version 1.2.1
NuGet\Install-Package Cirreum.Invocation.SignalR -Version 1.2.1
<PackageReference Include="Cirreum.Invocation.SignalR" Version="1.2.1" />
<PackageVersion Include="Cirreum.Invocation.SignalR" Version="1.2.1" />
<PackageReference Include="Cirreum.Invocation.SignalR" />
paket add Cirreum.Invocation.SignalR --version 1.2.1
#r "nuget: Cirreum.Invocation.SignalR, 1.2.1"
#:package Cirreum.Invocation.SignalR@1.2.1
#addin nuget:?package=Cirreum.Invocation.SignalR&version=1.2.1
#tool nuget:?package=Cirreum.Invocation.SignalR&version=1.2.1
Cirreum Invocation SignalR
SignalR invocation source for the Cirreum Invocation provider family.
Overview
Cirreum.Invocation.SignalR is the L3 Infrastructure package that makes SignalR a registered invocation source within the Cirreum framework. It supplies a concrete InvocationProviderRegistrar that:
- Maps SignalR Hubs from configuration (
Cirreum:Invocation:Providers:SignalR:Instances:{key}). - Registers a
HubFilterthat publishesIInvocationContextper Hub method invocation, putting SignalR on the same unified seam as HTTP. - Wires up the per-instance auth scheme via
RequireAuthorization()when one is configured.
Apps do not reference this package directly — they install the matching L5 Runtime Extensions package (Cirreum.Runtime.Invocation.SignalR) which exposes the AddSignalR<THub>(instanceKey) extension on IInvocationBuilder and the MapSignalRInvocation() endpoint-mapping method, and pulls this package in transitively.
Architectural position
L2 Core
Cirreum.InvocationProvider ← abstractions: IInvocationContext, registrar base, ...
L3 Infrastructure
Cirreum.Invocation.SignalR ← THIS PACKAGE — registrar, settings, HubFilter
Cirreum.Invocation.WebSockets ← peer for raw WebSockets
L4 Runtime
Cirreum.Runtime.InvocationProvider ← IInvocationBuilder seam, AddInvocation, RegisterInvocationProvider
L5 Runtime Extensions
Cirreum.Runtime.Invocation.SignalR ← AddSignalR<THub>(key) + MapSignalRInvocation()
What's in the box
| Type | Role |
|---|---|
SignalRInvocationRegistrar |
Concrete registrar — maps Hubs, wires the HubFilter, validates settings |
SignalRInvocationSettings / SignalRInvocationInstanceSettings (Cirreum.Invocation.Configuration) |
Typed settings bound from Cirreum:Invocation:Providers:SignalR |
SignalRHubMapping (Cirreum.Invocation.SignalR) |
DI-stashed (InstanceKey, HubType) record produced by the L5 AddSignalR<THub> extension and consumed by the registrar |
InvocationContextHubFilter (Cirreum.Invocation.SignalR, internal) |
IHubFilter covering all three lifecycle hooks — publishes IInvocationContext, materializes IInvocationConnection at upgrade, dispatches IConnectionLifecycle callbacks |
SignalRConnection (Cirreum.Invocation.SignalR, internal) |
IInvocationConnection adapter wrapping HubCallerContext; aliases Items and forwards SendAsync<T> overloads through the captured SignalR caller proxy |
SignalRInvocationContext (Cirreum.Invocation.SignalR, internal) |
IInvocationContext adapter for SignalR — used both for Hub method invocations and for synthetic scopes around lifecycle hooks |
How registration works
The L5 AddSignalR<THub>(instanceKey) extension does two things:
- Stashes a
SignalRHubMapping(instanceKey, typeof(THub))record in DI. - Calls
builder.HostBuilder.RegisterInvocationProvider<SignalRInvocationRegistrar, SignalRInvocationSettings, SignalRInvocationInstanceSettings>()from L4. The L4 helper:- Binds
Cirreum:Invocation:Providers:SignalRfromIConfigurationtoSignalRInvocationSettings. - Calls
registrar.Register(...)— services phase — which callsservices.AddSignalR()and registers theInvocationContextHubFilteragainst the globalHubOptions. - Stashes an
InvocationProviderMappingin DI capturing the deferredregistrar.Map(...)closure.
- Binds
The L5 MapSignalRInvocation() endpoint-mapping method resolves all InvocationProviderMapping entries with ProviderName == "SignalR" and invokes their closures against IEndpointRouteBuilder. The registrar's MapSource then:
- Resolves the
SignalRHubMappingfor each enabled instance. - Dispatches through reflection to
endpoints.MapHub<THub>(path)(the framework only ships a generic-only overload). - Wires
RequireAuthorizationwithAuthenticationSchemes = settings.SchemeifSchemeis set.
Configuration
{
"Cirreum": {
"Invocation": {
"Providers": {
"SignalR": {
"Instances": {
"chat": { "Enabled": true, "Path": "/chat", "Scheme": "oidc_primary" },
"notifications": { "Enabled": true, "Path": "/notifications", "Scheme": "oidc_primary" }
}
}
}
}
}
}
Scheme references a configured Authorization instance under Cirreum:Authorization:Providers:*:Instances:{Scheme}. Optional — leave unset for unauthenticated hubs (rare).
Server-initiated push
From cross-cutting code (Conductor command handlers, validators, services) running inside the SignalR invocation pipeline, push to the calling client through the ambient connection — no separate service to inject:
public sealed class NotifyHandler(IInvocationContextAccessor accessor)
: ICommandHandler<NotifyCommand> {
public async ValueTask<Result> Handle(NotifyCommand cmd, CancellationToken ct) {
var connection = accessor.Current?.Connection;
if (connection is not null) {
await connection.SendAsync("Notification", cmd.Payload, ct);
}
return Result.Success();
}
}
The no-method SendAsync<T>(payload) overload uses the runtime type name as the SignalR method-routing convention (e.g. SendAsync(new ChatMessage(...)) dispatches to client connection.on("ChatMessage", ...)); the keyed SendAsync<T>(method, payload) overload accepts an explicit method name. Serialization flows through SignalR's configured IHubProtocol (JSON or MessagePack — set via AddSignalR().AddJsonProtocol(...) / .AddMessagePackProtocol()).
Hub method bodies that already use Clients.Caller.SendAsync(...) directly are equivalent — both paths push to the same target through the same SignalR pipeline.
Connection lifecycle
Implement IConnectionLifecycle (from Cirreum.Invocation.Connections) and register it in DI to receive OnConnectedAsync / OnDisconnectedAsync callbacks. The HubFilter dispatches both under a synthetic invocation scope so consumers like IUserStateAccessor work normally inside the callbacks. The DisconnectInfo parameter on OnDisconnectedAsync carries the disconnect circumstances — graceful close vs. abort, the underlying exception (if any), and a human-readable reason — populated by this adapter from SignalR's optional Exception? parameter:
internal sealed class AuditConnectionLifecycle(ILogger<AuditConnectionLifecycle> logger)
: IConnectionLifecycle {
public ValueTask<bool> OnConnectedAsync(IInvocationConnection connection, CancellationToken ct) {
// Inspect connection.User, connection.ConnectionId, connection.Items, etc.
// Return false to reject the connection (the upgrade aborts; client sees normal rejection).
return ValueTask.FromResult(true);
}
public ValueTask OnDisconnectedAsync(
IInvocationConnection connection,
DisconnectInfo info,
CancellationToken ct) {
if (info.WasGraceful) {
logger.LogInformation("Connection {Id} closed cleanly", connection.ConnectionId);
} else if (info.Exception is not null) {
logger.LogWarning(info.Exception,
"Connection {Id} aborted: {Reason}", connection.ConnectionId, info.Reason);
}
return ValueTask.CompletedTask;
}
}
Per-transport mapping for DisconnectInfo: SignalR's Exception? parameter from OnDisconnectedAsync(HubLifetimeContext, Exception?) populates as WasGraceful = exception is null, Exception = exception, Reason = exception?.Message.
Dependencies
- Cirreum.InvocationProvider
1.3.0+— L2 abstractions (InvocationProviderRegistrar,IInvocationContext,IInvocationContextAccessor,IInvocationConnection(withSendAsync<T>andAbort()),IConnectionLifecycle,DisconnectInfo, etc.) - Microsoft.AspNetCore.App (framework reference) — SignalR (
Microsoft.AspNetCore.SignalR), endpoint routing
Versioning
Follows Semantic Versioning. Foundational library — major bumps are rare and coordinated with Cirreum.InvocationProvider releases.
License
MIT — see LICENSE.
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.InvocationProvider (>= 1.3.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Cirreum.Invocation.SignalR:
| Package | Downloads |
|---|---|
|
Cirreum.Runtime.Invocation.SignalR
Runtime Extensions package for the Cirreum SignalR invocation source — app-facing AddSignalRInvocation() / AddSignalR<THub>() / MapSignalRInvocation() extensions that wire SignalR Hubs into the unified IInvocationContext seam from configuration. |
GitHub repositories
This package is not used by any popular GitHub repositories.