InvergeDocs
.NET

.NET SDK

Inverge.Nexus — async, dependency-free, trim- and AOT-friendly, with ASP.NET Core, ILogger, Generic Host, realtime and Telescope packages.

  • NuGet Inverge.Nexus 1.0 (release candidate — use --prerelease) · source
  • Targets net8.0, net9.0, netstandard2.0 · CancellationToken everywhere
  • API reference

Packages

PackageAddsTargets
Inverge.NexusThe client and every product; no third-party dependenciesnet8.0, net9.0, netstandard2.0
Inverge.Nexus.Extensions.LoggingAddNexus() (DI, IConfiguration, IHttpClientFactory), the ILogger provider, flush on shutdownnet8.0, net9.0, netstandard2.0
Inverge.Nexus.AspNetCoreRequest middleware (UseNexus, UseNexusTelescope)net8.0, net9.0
Inverge.Nexus.RealtimeA Socket.IO connection for receiving room trafficnet8.0, net9.0, netstandard2.0
Inverge.Nexus.TelescopeRequest-journey tracingnet8.0, net9.0
dotnet add package Inverge.Nexus --prerelease

Console 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";
});
appsettings.json
{
  "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 session

NexusContext 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

ExceptionWhen
NexusConfigurationExceptionNo API key, malformed origin
NexusTransportExceptionDNS, refused connection, TLS, timeout
NexusValidationException400 / 422
NexusAuthenticationException401
NexusPermissionDeniedException403
NexusNotFoundException404
NexusBillingSuspendedException402 — unpaid invoices
NexusRateLimitException429 (RetryAfter)
NexusServerException5xx

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-forget

The 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/emit

Batch = false sends inline; builders expose Build() to assert payloads.

On this page