NekoLib.Diagnostics.Windows
1.1.0
dotnet add package NekoLib.Diagnostics.Windows --version 1.1.0
NuGet\Install-Package NekoLib.Diagnostics.Windows -Version 1.1.0
<PackageReference Include="NekoLib.Diagnostics.Windows" Version="1.1.0" />
<PackageVersion Include="NekoLib.Diagnostics.Windows" Version="1.1.0" />
<PackageReference Include="NekoLib.Diagnostics.Windows" />
paket add NekoLib.Diagnostics.Windows --version 1.1.0
#r "nuget: NekoLib.Diagnostics.Windows, 1.1.0"
#:package NekoLib.Diagnostics.Windows@1.1.0
#addin nuget:?package=NekoLib.Diagnostics.Windows&version=1.1.0
#tool nuget:?package=NekoLib.Diagnostics.Windows&version=1.1.0
NekoLib
A family of focused, dual-target C# libraries for desktop and embedded applications — built for PDV/DM-class software: kiosk and point-of-sale shells that run unattended for days, on hardware that ranges from current machines to boxes still pinned to .NET Framework.
Every shipped module supports .NET Framework 4.8.1 and a .NET 9.0 target
side by side; UI and Win32 modules use net9.0-windows. The dependency graph is
shallow rather than dependency-free: reference the feature package you need and
NuGet brings its documented foundations transitively.
Who this is for
The design assumptions come from unattended retail/dispensing terminals:
- The app never closes. Page lifecycle is deterministic and leaks are treated as bugs, not as something the next restart will clean up.
- Nobody is watching it. An idle timeout signs the session out and returns to a known screen; crashes produce a bundle you can read after the fact.
- The hardware is mixed. net481 and net9.0 are peers — neither is a second-class target, and nothing is allowed to compile on only one of them by accident.
- Touch-first, single-window. Navigation swaps pages inside one host panel rather than opening windows.
If you are building a normal multi-window desktop app most of this still works, but the tradeoffs were not made with you in mind.
Navigation is the core
NekoLib.Navigation is the module everything else orbits. It is a page
lifecycle runtime for a single-window shell: page registration, a deterministic
navigation order, history, guards, session, idle behavior, and four overlay
primitives — with WinForms and WPF adapters keeping application pages
framework-native.
PageNavBootstrap
.Use<WinFormsPlatformAdapter>(mainPanel)
.RegisterPagesFromAssembly(typeof(IdlePage).Assembly)
.ConfigurePages(cfg =>
{
cfg.Page<IdlePage>().AsIdle().StrongSingleton();
cfg.Page<AdminPage>().StrongSingleton();
})
.UseIdleTimeout(10_000)
.Start();
Start() mounts the static facade, so view-models navigate directly:
await NavigationService.SwitchPage<DashboardPage>();
await NavigationService.GoBackAsync();
NavigationService.Session.SignIn(roles: new[] { "admin" });
Guards are declared on the page and evaluated before navigation:
[RequireRole("admin")]
public sealed class AdminPage : PageView { }
→ Full technical reference:
docs/modules/Navigation/REFERENCE.md
— lifecycle order, guards, reuse policies, load modes, overlays, platform
adapters, logging, telemetry, Inspection, and the stability-sensitive components.
Optional modules
Pick what you need. Navigation requires NekoLib.Core; the other modules are
optional unless one of their documented dependents brings them transitively.
| Module | What it gives you |
|---|---|
NekoLib.Core |
Small contracts for independent Logging, Telemetry, and Inspection capabilities, plus their null implementations. Zero dependencies. |
NekoLib.Logging |
Synchronous ordered severity logging, bounded recent entries, debugger output, and bounded rolling-file persistence. |
NekoLib.Telemetry |
Bounded in-process operation timings with correlation IDs, checkpoints, outcomes, dimensions, and read-only snapshots. |
NekoLib.Diagnostics |
Incident orchestration: records a fatal event, requests a bounded log flush, captures supplied recent evidence, and writes a partial crash bundle. Dump writing remains pluggable. |
NekoLib.Diagnostics.Windows |
The Windows half of the above: minidumps via dbghelp, WER suppression, and the WinForms ThreadException hook. |
NekoLib.Http |
Typed, instance-scoped endpoint catalogs and bounded request execution through a consumer-owned HttpClient. |
NekoLib.Data |
Provider-neutral SQL gateway with a fluent QueryBuilder, typed and dynamic reads, target-specific streaming, and transactions. |
NekoLib.Mvvm |
ViewModelBase and RelayCommand/RelayCommand<T>. Deliberately tiny; works with WinForms and WPF binding alike. |
NekoLib.Pipes |
Named-pipe IPC: request/response RPC plus bounded pub/sub events over framed JSON. |
NekoLib.Watchdog |
Process supervision — application-side Host bootstrap/attach, restart on crash, crash bundling, an RPC control channel, and a companion host executable. |
NekoLib.Watchdog.Host |
Direct-reference deployment package for the versioned local Watchdog sidecar; no compile-time API. |
NekoLib.Devices |
Hardware protocol abstraction over serial ports, TCP streams, named pipes, and test doubles. |
NekoLib.Inspection |
Opt-in passive in-process inspection: a bounded operation buffer, ordered pull-based state providers, budgeted snapshots, and owner diagnostics. Actions remain explicitly experimental and are not authorization. Broad module instrumentation remains frozen. |
Ordinary logging does not require Diagnostics or Inspection:
var fileSink = new RollingFileLogSink(new RollingFileLogSinkOptions
{
FilePath = Path.Combine(AppContext.BaseDirectory, "logs", "app.log"),
MaximumFileBytes = 2 * 1024 * 1024,
RetainedFileCount = 4
});
using var logger = new Logger(LogLevel.Info, fileSink);
logger.Info("Application started", category: "Startup");
Telemetry and Inspection are separate opt-in capabilities. Navigation accepts each Core contract independently:
var telemetry = new TelemetryPipeline();
using var inspection = InspectionRuntime.EnableGlobal();
PageNavBootstrap
.Use<WinFormsPlatformAdapter>(mainPanel)
.UseLogging(logger)
.UseTelemetry(telemetry)
.UseInspection()
// page registration/configuration
.Start();
InspectionProvider.Current lives in Core and defaults to
NullInspection.Instance. Only one global runtime may be active. Disposing it
restores the NO-OP and clears operations and state providers. The experimental
action registry is also cleared. The overload
UseInspection(IInspectionRecorder) accepts an explicit non-global recorder.
Diagnostics sees only IInspectionSnapshotSource, so it cannot invoke
registered actions. See the
Inspection reference for identity,
ordering, budget, lifecycle, and experimental-boundary contracts.
Navigation telemetry creates one correlated Navigation/page_switch operation.
It owns the page-switch start and synchronous lifecycle-completed page_ready
boundaries; an application guard may report the intermediate authentication
checkpoint through NavigationArgs.WithTiming(...). This yields total,
time-to-authenticated, and post-auth-to-ready measurements without claiming pure
HTTP or first-paint timings.
At the composition root, the same independent implementations can be supplied to incident capture without creating feature-module dependencies:
var crashes = new CrashHandler(new CrashHandlerOptions
{
CrashRootDirectory = Path.Combine(AppContext.BaseDirectory, "crash"),
Logger = logger,
TelemetrySnapshotSource = telemetry,
InspectionSnapshotSource = inspection,
EvidenceCollectionTimeout = TimeSpan.FromMilliseconds(250)
});
crashes.Install();
ExternalNotifier is a generic composition callback: when supplied, Diagnostics
invokes it after the artifact stage completes or fails and isolates callback
failures. The application decides whether that callback notifies Watchdog or
another local
integration; Diagnostics does not inspect Watchdog environment state. Leave it
null when no notification is required. Subscribe to CrashBundleFailed to learn
that incident evidence was lost, because CrashDetected and the notifier fire
either way. Option values are captured when the handler is constructed. WinForms
applications call WindowsCrash.HookWinForms() explicitly before creating any
window; repeated calls are safe and retain one process-lifetime hook.
→ Full technical reference:
docs/modules/Diagnostics/REFERENCE.md
— handler lifecycle, evidence budgets and bounds, redaction boundary, bundle
layout, and the Windows crash adapter.
Module entry points and limits
The root module map below owns targets and project dependencies. This table is the compact operational reference for modules that do not need a dedicated technical manual.
| Module | Main public entry points | Important boundary | Focused validation |
|---|---|---|---|
| Core | ILogger, ITelemetry, IInspectionRecorder, snapshot contracts, null objects |
Contracts only; no concrete pipeline or feature-module knowledge | NekoLib.Core.Tests.Unit |
| Logging | Logger, LoggerOptions, DebugLogSink, RollingFileLogSink |
Synchronous ordered writes; callers own sink composition, and DisposeSinks defaults to transferring sink disposal to the logger |
NekoLib.Logging.Tests.Unit |
| Telemetry | TelemetryPipeline, TelemetryPipelineOptions |
Bounded in-memory completed operations; no persistence in v1; the caller owns one explicit terminal and sink dispatch is synchronous | NekoLib.Telemetry.Tests.Unit |
| Inspection | InspectionRuntime, InspectionOptions, InspectionProvider |
Explicit opt-in; passive bounded evidence; at most one global runtime; actions experimental; broad module rollout frozen | NekoLib.Inspection.Tests.Unit |
| Diagnostics | CrashHandler, CrashHandlerOptions, CrashDumpWriter |
Incident evidence consumer; options are captured at construction, disposal is terminal and releases the process hooks, bundles may be partial, and a failed bundle raises CrashBundleFailed |
NekoLib.Diagnostics.Tests.Unit |
| Diagnostics.Windows | WindowsCrash, CrashSuppressor |
Windows-only adapter; WinForms exception hooking is explicit and process-idempotent | build directly plus NekoLib.Diagnostics.Tests.Unit |
| HTTP | HttpEndpoint, HttpApiCatalog, RelativeUriBuilder, HttpApiClient |
Consumer owns HttpClient, authentication and policy; non-success protocol evidence is preserved and response buffering is bounded |
NekoLib.Http.Tests.Unit |
| Data | QueryBuilder, DatabaseGateway, QueryExecutionContext, DbSession |
Raw identifiers/clauses remain a caller trust boundary; OleDb binding is positional | NekoLib.Data.Tests.Unit |
| Mvvm | ViewModelBase, RelayCommand, RelayCommand<T> |
Binding helpers only; no application host or navigation dependency; coercion needs an exact runtime type match and Execute does not consult CanExecute |
NekoLib.Mvvm.Tests.Unit |
| Pipes | PipeServer, PipeClient, PipeEventHub, PipeEventClient, IPipeMetrics |
Local cooperative-process transport, not an authorization boundary; current-user access is opt-in; event delivery is bounded/best-effort; stateful shutdown is terminal and awaitable | NekoLib.Pipes.Tests.Unit |
| Watchdog | WatchdogBootstrap, WatchdogController, WatchdogRuntime, WatchdogOptions |
Default application bootstrap plus a deliberate advanced supervisor runtime; configuration is captured, shutdown is terminal, evidence is bounded/best-effort, and current-user RPC/events do not protect against a hostile same-user process | NekoLib.Watchdog.Tests.Unit |
| Devices | HardwareEngine, ICommTransport, serial/TCP/named-pipe transports, ProtocolRaw |
Transport-neutral byte streams; a timed-out operation leaves an indeterminate receive state unless CloseTransportOnNoResponse is enabled; real COM-port behavior still needs explicit runtime validation |
NekoLib.Devices.Tests.Unit |
Navigation and its adapters use their dedicated technical reference. Pipes returns stable protocol errors to clients and reports handler exception details only to the configured local metrics/diagnostics surface. Run a focused suite with:
dotnet test tests/NekoLib.<Module>.Tests/Unit/NekoLib.<Module>.Tests.Unit.csproj
Adapters and projects without a dedicated test assembly are built directly and
covered through their owning module's tests. The complete validation taxonomy
and package/runtime exceptions are documented in
tests/README.md.
Compatibility
| Targets | net481 and net9.0 (net9.0-windows for the UI and Win32 modules) |
| Language | C# latest; no record in types shared across targets — net481 lacks IsExternalInit |
| Nullable | Configured per module; preserve the existing setting documented in AGENTS.md |
| Tooling | Visual Studio 2022 or the dotnet CLI. Builds and validation are manual; GitHub Actions is used only for manually dispatched NuGet.org trusted publication |
| Platform | net481 and every -windows target build on Windows only |
Public API stability, coordinated SemVer, deprecation, compatibility baselines,
and migration follow the current
public API and release policy.
Consumer-visible changes are recorded in CHANGELOG.md.
dotnet build NekoLib.sln
dotnet test NekoLib.sln
.\eng\verify-public-api.ps1
NuGet packages
Package production is opt-in: the 15 library projects and the Watchdog Host
deployment package are packaged together; tests, runtime scenarios,
BundlerTool, and the constants-only
src/Hosting/NekoLib project are not.
NekoLib 1.0.0 is the first stable coordinated family support baseline. Its
qualifying immutable local candidate, 1.0.0-local.22, passed the clean
canonical package flow from source commit
7090e40eed7c6b888ce8da732f21cbe10f1a936c. The coordinated 1.0.0 package
set was then materialized locally from clean source commit
db63529cafce11690a18a595e4abc6c0610b9b8e and published to NuGet.org through
the v1.0.0 GitHub Release and the manual trusted-publication workflow. See the
1.0.0 stable release record for provenance,
hashes, validation results, and evidence boundaries.
Use the packaging entry point instead of packing individual projects:
$packageVersion = Read-Host "Enter a new immutable package version"
.\eng\pack-local.ps1 -PackageVersion $packageVersion
The command requires a clean Git worktree, builds and tests the solution,
publishes the Watchdog Host payloads, packs the whole family, validates package
structure, matching XML API documentation for every managed target assembly,
and cross-TFM compatibility, restores clean PackageReference-only consumers,
and finally copies the verified artifacts to
artifacts/local-feed/. Main packages and .snupkg symbol packages are
retained. Package versions are immutable: after publishing any version, choose
a different version for changed bits.
Use -AllowDirty only for a disposable validation version; a package produced
from uncommitted sources cannot carry exact Git/Source Link provenance.
Install the public stable packages directly from NuGet.org:
dotnet add package NekoLib.Navigation.WinForms --version 1.0.0
For unpublished validation versions, register the generated local folder as a source on a consumer machine:
dotnet nuget add source C:\path\to\NekoLib\artifacts\local-feed --name NekoLibLocal
dotnet add package NekoLib.Navigation.WinForms --version 1.0.0
The same verified package family can also be pushed under a distinct version to an authenticated private NuGet v3 feed; no package or consumer project changes are required.
Project references become NuGet dependencies, so an application normally
references only its top-level modules. For example,
NekoLib.Navigation.WinForms brings Navigation and Core transitively.
NekoLib.Watchdog.Host is a deployment package rather than a compile-time
library. Reference it directly from the executable project; deployment does not
flow through wrapper packages. On build and
publish it copies an isolated sidecar to:
<application output>/NekoLib.Watchdog.Host/NekoLib.Watchdog.Host.exe
That subdirectory is owned by the package and replaced on each build/publish so obsolete files from an older Host payload cannot survive an upgrade.
The package carries an AnyCPU net481 payload plus framework-dependent
win-x86 and win-x64 .NET 9 payloads. Selection follows
NekoLibWatchdogHostRid, RuntimeIdentifier, then PlatformTarget, defaulting
to win-x64. Set NekoLibWatchdogHostDeploy=false to disable deployment. A
.NET 9 Host still requires the corresponding x86 or x64 .NET 9 Runtime on the
target machine.
Call the application-side bootstrap near the beginning of Main, passing the
original arguments:
static void Main(string[] args)
{
WatchdogBootstrap.EnsureStarted(args);
// normal application startup
}
The first call starts the deployed sidecar, attaches it to the current PID, and
waits for a bounded PID/token handshake over the target-specific pipe. The first
application process keeps its existing parent; after it exits, the Host uses the
normal restart path and becomes the parent of subsequent instances. Restarted
instances receive NEKO_UNDER_WATCHDOG=1, so the bootstrap returns immediately
instead of recursively starting another Host. If a Watchdog already answers on
the same target pipe and confirms the current PID, no second Host is started. A
conflicting supervised PID fails clearly instead of being mistaken for a valid
handoff. Lock wait, preflight, pipe I/O and readiness confirmation share the one
bounded timeout supplied to EnsureStarted.
The coordinated library and Host use internal protocol v1 and must be updated
together. Bootstrap checks the version before accepting the versioned
attached:v1:<pid>:<token> identity. A stale or independently copied Host fails
with an incompatible-protocol diagnostic. Explicit working directories must
already exist. Fatal Host startup evidence is bounded under
%LOCALAPPDATA%\NekoLib\Watchdog\watchdog-host-fatal.log; see the
Host technical reference.
The package-consumer probes live under tests/NekoLib.PackageConsumers/ and
cover single- and multi-target WinForms plus WPF without any ProjectReference.
They are not part of NekoLib.sln, because a normal source build must not
require packages to have been produced first.
Module map
| Module | Path | Targets | References |
|---|---|---|---|
NekoLib.Core |
src/Core/NekoLib.Core/ |
net481, net9.0 | — |
NekoLib.Logging |
src/Logging/NekoLib.Logging/ |
net481, net9.0 | Core |
NekoLib.Telemetry |
src/Telemetry/NekoLib.Telemetry/ |
net481, net9.0 | Core |
NekoLib.Inspection |
src/Inspection/NekoLib.Inspection/ |
net481, net9.0 | Core |
NekoLib.Diagnostics |
src/Diagnostics/NekoLib.Diagnostics/ |
net481, net9.0 | Core |
NekoLib.Diagnostics.Windows |
src/Diagnostics/NekoLib.Diagnostics.Windows/ |
net481, net9.0-windows | Diagnostics |
NekoLib.Http |
src/Http/NekoLib.Http/ |
net481, net9.0 | — |
NekoLib.Navigation |
src/Navigation/NekoLib.Navigation/ |
net481, net9.0 | Core |
NekoLib.Navigation.WinForms |
src/Navigation/NekoLib.Navigation.WinForms/ |
net481, net9.0-windows | Navigation |
NekoLib.Navigation.Wpf |
src/Navigation/NekoLib.Navigation.Wpf/ |
net481, net9.0-windows | Navigation |
NekoLib.Data |
src/Data/NekoLib.Data/ |
net481, net9.0 | — |
NekoLib.Mvvm |
src/Mvvm/NekoLib.Mvvm/ |
net481, net9.0 | — |
NekoLib.Devices |
src/Devices/NekoLib.Devices/ |
net481, net9.0 | — |
NekoLib.Pipes |
src/Pipes/NekoLib.Pipes/ |
net481, net9.0 | — |
NekoLib.Watchdog |
src/Watchdog/NekoLib.Watchdog/ |
net481, net9.0-windows | Core, Pipes |
NekoLib.Watchdog.Host |
src/Watchdog/NekoLib.Watchdog.Host/ |
net481, net9.0-windows | Watchdog |
NekoLib |
src/Hosting/NekoLib/ |
net481, net9.0 | — |
Inside Navigation, dependencies flow one way:
Adapters → Runtime → Contracts. Across packages, dependencies follow the
References column above: platform adapters depend on Navigation,
Diagnostics.Windows depends on Diagnostics; Logging, Telemetry, Inspection, and
Diagnostics depend only on Core; HTTP, Data, Mvvm, Devices, and Pipes have no
NekoLib project dependency; Watchdog depends on Core and Pipes. The graph has no
cycles.
src/Tools/BundlerTool/ is a standalone dev utility and is not part of
NekoLib.sln. Build it reproducibly through
eng/build-bundler.ps1; generated output belongs under
artifacts/.
Where things are
| Core technical reference | docs/modules/Core/REFERENCE.md |
| Navigation technical reference | docs/modules/Navigation/REFERENCE.md |
| Inspection technical reference | docs/modules/Inspection/REFERENCE.md |
| Pipes technical reference | docs/modules/Pipes/REFERENCE.md |
| Watchdog technical reference | docs/modules/Watchdog/REFERENCE.md |
| Product direction, intentions, and the Inspection instrumentation freeze | ROADMAP.md |
| Formally promoted work and execution gates | TODO.md |
| Unpromoted ideas | docs/proposals/ |
| Documentation authority and lifecycle | docs/README.md |
| Automated verification taxonomy | tests/README.md |
| Shared manual runtime scenarios | runtime_tests/README.md |
| Documentation infrastructure, agent adapters, tools, artifacts, and local data | docs/repository-layout.md |
| Historical audits and the active-review index | docs/audit/README.md |
| Completed roadmap history | docs/history/README.md |
| Working agreements for coding agents | AGENTS.md |
Automated suites and package probes are classified in
tests/README.md. Manual runtime scenarios are separate and
are versioned under runtime_tests/; build and launch
them explicitly, never through dotnet test.
License
See LICENSE.txt.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0-windows7.0 is compatible. net10.0-windows was computed. |
| .NET Framework | net481 is compatible. |
-
.NETFramework 4.8.1
- NekoLib.Diagnostics (>= 1.1.0)
-
net9.0-windows7.0
- NekoLib.Diagnostics (>= 1.1.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.