Aeroverra.SignalR.CodeGeneration.CSharp
0.1.3
See the version list below for details.
dotnet add package Aeroverra.SignalR.CodeGeneration.CSharp --version 0.1.3
NuGet\Install-Package Aeroverra.SignalR.CodeGeneration.CSharp -Version 0.1.3
<PackageReference Include="Aeroverra.SignalR.CodeGeneration.CSharp" Version="0.1.3" />
<PackageVersion Include="Aeroverra.SignalR.CodeGeneration.CSharp" Version="0.1.3" />
<PackageReference Include="Aeroverra.SignalR.CodeGeneration.CSharp" />
paket add Aeroverra.SignalR.CodeGeneration.CSharp --version 0.1.3
#r "nuget: Aeroverra.SignalR.CodeGeneration.CSharp, 0.1.3"
#:package Aeroverra.SignalR.CodeGeneration.CSharp@0.1.3
#addin nuget:?package=Aeroverra.SignalR.CodeGeneration.CSharp&version=0.1.3
#tool nuget:?package=Aeroverra.SignalR.CodeGeneration.CSharp&version=0.1.3
AeroSignalR
OpenAPI-style spec generation and strongly-typed client generation for ASP.NET Core SignalR.
Purpose
REST APIs have OpenAPI: the server publishes a spec, and anyone can generate a typed client
from it without ever seeing the server's source. SignalR has nothing like that, so hub
consumers hand-write connection.On("MagicString", ...) and hope the server never changes.
AeroSignalR closes that gap. The server describes its hubs in a spec document (a valid
OpenAPI 3.1 envelope with an x-signalr extension), served from an endpoint or exported at
build time without booting the server. From that document, a generator emits a complete C#
client: typed methods for everything the client can invoke, events for everything the server
pushes, and models for every type on the wire. The generated client rides on a runtime that
handles what SignalR's client deliberately does not: it retries the initial connect forever,
reconnects forever with capped exponential backoff, and re-sends your access token on every
reconnect.
- Spec generation from your mapped hubs via reflection: no attributes required,
Hub<T>callbacks included, lifecycle methods excluded - Headless export (
--signalr-spec-export) that never starts Kestrel, the database, or hosted services - Generated clients: typed invocations, events per callback, generated models and enums
- Nullability transfers end to end:
string?parameters,Task<Model?>returns, and nullable model properties survive the spec and come back as?annotations - Connection resilience by default: initial-connect retry forever, reconnect forever with capped jittered backoff, plus a supervisor that recovers from the graceful closes SignalR's own reconnect ignores; the connection only stays down when you stop it
- One-line DI registration (
AddAeroHubClient): singleton client, connects with the host, stops on shutdown, lifecycle logging built in; interface and keyed overloads plus a connection-state health check included - Streaming both directions (
IAsyncEnumerable<T>), generated client interfaces for mocking, XML doc summaries flowing spec-to-client, and per-invocation timeouts - Auth via
AccessTokenProvider(re-evaluated on reconnect) plus query string parameters - .NET 8, 9, and 10; System.Text.Json
The packages
All four version together and publish together.
| Package | NuGet | What it does | Who references it |
|---|---|---|---|
Aeroverra.SignalR.Spec |
The spec document model (read/write) | Pulled in by the two below | |
Aeroverra.SignalR.Spec.AspNetCore |
Generates, serves, and exports the spec from your mapped hubs | Your server | |
Aeroverra.SignalR.CodeGeneration.CSharp |
Generates the C# client from a spec document | Your generator console / build tooling only | |
Aeroverra.SignalR.Client |
The runtime the generated clients ride on | Anyone consuming a generated client |
Server: two lines
app.MapHub<NexusHub>("/Nexus/NexusHub"); // your existing hubs, unchanged
app.MapSignalRSpec(); // serves /openapi/signalr/v1.json
if (await app.TryExportSignalRSpecAsync(args)) return; // headless export, then exit
await app.RunAsync();
dotnet MyApi.dll --signalr-spec-export spec.json now writes the spec and exits before
Kestrel or any hosted service starts.
Generate a client
var document = SignalRSpecDocument.FromJson(await File.ReadAllTextAsync("spec.json"));
var settings = new CSharpClientGeneratorSettings { Namespace = "My.Company.SignalR" };
var code = new CSharpClientGenerator(document, settings).GenerateFile();
await File.WriteAllTextAsync("Generated/SignalRClients.cs", code);
Use it
Register once, like a REST API client; it connects with the host and stops on shutdown:
services.AddAeroHubClient<NexusHubClient>((provider, options) =>
{
options.BaseAddress = new Uri("https://api.example.com");
options.AccessTokenProvider = () => Task.FromResult<string?>(token);
options.QueryParameters["ServerName"] = "web-01";
});
Then inject it anywhere:
client.OnProxyServerUpdated += async proxyServerId =>
{
// the server called us
};
await client.Broadcast("hello", 30); // typed invocation
ProxyServerInfo proxyServer = await client.GetProxyServer(id);
Drop the connection and it reconnects on its own, backing off exponentially to a ceiling
and never giving up. Short-lived or per-user clients skip DI: new NexusHubClient(options)
plus StartAsync/DisposeAsync.
Documentation
Full documentation, including the spec format, server integration, generator settings, the client runtime, and limitations, lives in the wiki.
License
MIT. See LICENSE.md.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. 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. |
-
net8.0
- Aeroverra.SignalR.Spec (>= 0.1.3)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.