Desktop and other non-ASP.NET Core apps

Nafas.Observability.Server runs a standalone HTTP listener for WinForms, WPF, and console apps with no ASP.NET Core pipeline.

UseNafasDashboard needs an IApplicationBuilder to mount onto — a plain WinForms, WPF, or console/worker app has no ASP.NET Core pipeline of its own to provide one. Nafas.Observability.Server is a separate, optional package for exactly that case: it runs a second, independent HTTP listener (on its own port) that serves the same dashboard against the same running app's real data — no Kestrel, no OWIN, just a minimal HTTP/1.1 server directly on TcpListener.

Why not Kestrel or HttpListener? The last version of Kestrel ever published as a plain NuGet package is 2.3.13 from 2019, with no HTTP/2 and no security patches since. System.Net.HttpListener — the BCL's own listener — turned out not to be usable for the LAN case either: on Windows it's backed by HTTP.sys, which refuses to bind any prefix other than "localhost" unless the process runs elevated or a URL ACL was reserved beforehand (verified empirically).

Being plain netstandard2.0 like the core package itself, this also works from classic .NET Framework 4.6.1+ apps, not just modern .NET — confirmed against a real net48 console host, not just the TFM compatibility rules (see Requirements for the one net48-specific gotcha it also caught, around SQLite and PlatformTarget).

bash
dotnet add package Nafas.Observability.Server
csharp
services.AddNafasServer();               // same as always -- storage + ingestion
services.AddNafasHttpServer(o =>
{
    o.Enabled = true;                    // opt-in; does nothing while false
    o.Port = 5099;
    o.AccessMode = NafasHttpServerAccessMode.LocalhostOnly; // or .Lan
});

Then open http://localhost:5099/nafas.

Starting and stopping at runtime

NafasHttpServerOptions.Enabled is only read once at startup — to start/stop/reconfigure it later (e.g. a settings screen's "enable dashboard" checkbox), resolve NafasHttpServer from DI and call its StartAsync/StopAsync directly.

Access modes

AccessMode only controls which network interface is bound — LocalhostOnly (the default) binds loopback only, Lan binds every interface so other devices on the network can reach the port via this machine's own IP, with no administrator rights required either way (unlike System.Net.HttpListener, verified empirically on both). It does not by itself relax NafasServerOptions.Authorize (still local-requests-only by default, see Security): set Authorize explicitly too if Lan should actually let those requests through, otherwise they still get a 403.

One request per connection

Not HTTP/1.1 keep-alive — this listener is a local/LAN admin tool, not a public high-throughput API, so giving up connection reuse (an extra TCP handshake per dashboard API call, imperceptible on localhost/LAN) removes an entire dimension of correctness surface instead.