.NET SDK
Inverge.Nexus — async, dependency-free, trim- and AOT-friendly, with ASP.NET Core, ILogger, Generic Host, realtime and Telescope packages.
- NuGet
Inverge.Nexus1.0 (release candidate — use--prerelease) · source - Targets net8.0, net9.0, netstandard2.0 ·
CancellationTokeneverywhere - API reference
Packages
| Package | Adds | Targets |
|---|---|---|
Inverge.Nexus | The client and every product; no third-party dependencies | net8.0, net9.0, netstandard2.0 |
Inverge.Nexus.Extensions.Logging | AddNexus() (DI, IConfiguration, IHttpClientFactory), the ILogger provider, flush on shutdown | net8.0, net9.0, netstandard2.0 |
Inverge.Nexus.AspNetCore | Request middleware (UseNexus, UseNexusTelescope) | net8.0, net9.0 |
Inverge.Nexus.Realtime | A Socket.IO connection for receiving room traffic | net8.0, net9.0, netstandard2.0 |
Inverge.Nexus.Telescope | Request-journey tracing | net8.0, net9.0 |
dotnet add package Inverge.Nexus --prereleaseConsole app or worker
using Inverge.Nexus;
await using var nexus = new NexusClient("nxs_live_xxx"); // or NEXUS_API_KEY
using (NexusContext.Scope(distinctId: "user_123"))
{
await nexus.IdentifyAsync("user_123", email: "ada@example.com");
nexus.Track("order_placed", new { total = 42 });
nexus.Logs.Information("Order accepted", source: "checkout");
}await using flushes buffered telemetry on the way out.
ASP.NET Core
using Inverge.Nexus.AspNetCore;
using Inverge.Nexus.Extensions.Logging;
builder.Services.AddNexus(o => o.Release = "api@2026.10.4"); // "Nexus" config section + NEXUS_*
builder.Services.AddNexusAspNetCore(o =>
{
o.ResolveDistinctId = http => http.User.FindFirst("sub")?.Value;
o.IgnoredPathPrefixes.Add("/internal");
// o.TrackRequests = true; // off by default (events are metered)
// o.IncludeQueryString = true; // off by default (query strings carry tokens)
});
builder.Logging.AddNexus(o =>
{
o.MinimumLevel = LogLevel.Information;
o.CaptureExceptions = true; // LogError(ex, …) → grouped issue
o.IncludeScopes = true;
});
var app = builder.Build();
app.UseAuthentication();
app.UseNexus(); // after auth, so the signed-in user is bound
app.MapPost("/orders", (INexusClient nexus, Order order) =>
{
nexus.Track("order_placed", new { total = order.Total }); // already attributed
return Results.Accepted();
});UseNexus() binds the person, session, device, country, route and request id,
and reports unhandled exceptions before rethrowing them unchanged. Health,
readiness and metrics paths are ignored out of the box. For request-journey
tracing add Telescope for .NET.
Configuration
var nexus = new NexusClient("nxs_live_xxx", o =>
{
o.Release = "api@2026.10.4";
o.AppVersion = "2.1.0";
o.Batch = true;
o.FlushInterval = TimeSpan.FromSeconds(5);
o.MaxBatch = 50;
o.MaxQueue = 10_000;
o.Timeout = TimeSpan.FromSeconds(10);
o.MaxRetries = 2;
o.DefaultProperties["tier"] = "enterprise";
o.DefaultHeaders["X-Tenant"] = "acme";
});{
"Nexus": {
"ApiKey": "nxs_live_xxx",
"Timeout": 10,
"MaxBatch": 50,
"Services": { "LiveActivities": false }
}
}Precedence, lowest first: appsettings → NEXUS_* environment → code.
Durations accept seconds (2.5) or "00:00:10".
Ambient context
using (NexusContext.Scope(distinctId: "user_123", url: "/checkout", country: "IQ"))
{
nexus.Track("checkout_started");
}
nexus.Track("order_placed", new { total = 42 }, context: new NexusTelemetryContext { DistinctId = "user_999" });
nexus.Reset(); // sign-out: forget the person, keep the device, new sessionNexusContext is AsyncLocal<T>: it flows into awaited calls, but a value set
inside an async method does not flow back to its caller — bind it where the
context is owned (middleware, job handler).
Exceptions
| Exception | When |
|---|---|
NexusConfigurationException | No API key, malformed origin |
NexusTransportException | DNS, refused connection, TLS, timeout |
NexusValidationException | 400 / 422 |
NexusAuthenticationException | 401 |
NexusPermissionDeniedException | 403 |
NexusNotFoundException | 404 |
NexusBillingSuspendedException | 402 — unpaid invoices |
NexusRateLimitException | 429 (RetryAfter) |
NexusServerException | 5xx |
All derive from NexusException; match on Code, not the message.
o.Silent = true returns empty results instead of throwing.
Batching & shutdown
nexus.Pending; // waiting to be sent
nexus.Dropped; // lost to a full buffer — expose it as a metric
await nexus.FlushAsync(TimeSpan.FromSeconds(5));
o.DiagnosticSink = (level, message, ex) => Console.Error.WriteLine($"[nexus:{level}] {message}");Transports, background calls, AOT
var nexus = new NexusClient(options, httpClient); // your HttpClient (not disposed)
var nexus = new NexusClient(options, myTransport); // INexusTransport
var bg = nexus.Background(); // fire-and-forgetThe core, logging and ASP.NET Core packages are trimmable and AOT-compatible. In
a trimmed app pass properties as IDictionary<string, object?> or a JsonNode
instead of anonymous objects.
Testing
await using var nexus = new NexusClient(new NexusOptions { ApiKey = "nxs_test", Batch = false }, fakeTransport);
await nexus.EmitAsync("orders:42", "status");
// assert fakeTransport saw POST /partner/rooms/orders%3A42/emitBatch = false sends inline; builders expose Build() to assert payloads.
