| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [View Raw Code] [Original HTTPS Page] |
Why the Operational package family is shaped the way it is, what was deliberately excluded from v1, and the decision trail behind each structural choice. Companion to PowerCSharp.Operational.md (the API reference).
Operational is a cross-cutting package family: a shared mechanism for issue/error capture, in-app diagnostics, structured logging, disk-based event logging, and HTTP resilience — usable across any application architecture (Clean, Onion, Hexagonal, monolith), safe to enable/disable at any time without destabilizing the host application, and performance-friendly (background processing for anything that touches disk).
Decision: Operational is a standalone package family that sits beside PowerCSharp.Features, not as a leaf feature inside it.
The Features Framework (PowerCSharp.Features + Feature.Cache + Feature.Sanitization) is built for optional, leaf capabilities an application explicitly opts into (a cache backend, a sanitization engine) via AddPowerFeatures() + PowerFeatures:<Key>:Enabled. Its Feature.Sanitization.Abstractions package is the closer precedent for Operational's shape: it is explicitly documented as "usable standalone — no DI or feature registration required."
Operational is different in kind from Cache or Sanitization: it's cross-cutting plumbing (error capture, structured logging) that other code — potentially even Features Framework internals — may want to call. Forcing every consumer of IIssueManager/ILogger integration to first stand up the Features discovery engine would invert the dependency direction cross-cutting concerns are supposed to have: diagnostics should be available to log a Features Framework startup failure, not depend on the Features Framework having started successfully first.
So Operational follows the Sanitization-Abstractions shape, not the Cache shape:
PowerCSharp.Operational.Abstractions contracts + NoOp defaults, zero third-party deps
(netstandard2.0 + net8.0)
└─ PowerCSharp.Operational real implementation, ASP.NET Core-coupled (net8.0 only)
├─ PowerCSharp.Operational.Sentry [future — not in this build]
└─ PowerCSharp.Operational.WinEventLog [future — not in this build]
PowerCSharp.Operational.<Provider> (not Feature.Operational.*) is the naming convention for any future provider package that isolates a third-party or platform-specific dependency — exactly like Feature.Cache.BitFaster isolates BitFaster.Caching. Provider packages are named at the same nesting level as Operational, mirroring how PowerCSharp.Compatibility sits beside Core rather than under it.
Versioning: own family, PowerCSharpOperationalVersion, covering Operational.Abstractions + Operational together — the same pattern as PowerCSharpFeatureCacheVersion covering the whole Cache family. Future provider packages (Sentry/WinEventLog) get their own version property when that phase starts, mirroring the Cache/BitFaster precedent.
IRetryPolicyProvider is defined in PowerCSharp.Operational.Policies.Retry (the core package), not .Abstractions. Its members return Polly types directly (ResiliencePipeline<T>, IAsyncPolicy, AsyncRetryPolicy, RetryPolicy) — an interface shaped around a third-party library's types cannot live in a zero-dependency package without leaking that dependency into every consumer of .Abstractions, including ones that never touch retry logic. This is a direct application of the dependency-isolation rule in §4, applied to the contract itself rather than only to implementations.
Following the PowerCSharp invariant already enforced for Cache and Sanitization: no third-party or platform-specific dependency may leak into a consumer that didn't ask for it.
Windows Event Viewer forwarding is Windows-only by nature. Rather than guard it with OperatingSystem.IsWindows() conditionals inside the core package, PowerCSharp.Operational ships an IEventViewerService-shaped NoOp/pluggable hook only — no Windows Event Log code lives in the core package at all. A real Windows implementation would become PowerCSharp.Operational.WinEventLog, a separate provider package, following the same isolation pattern as Feature.Cache.BitFaster. This keeps Operational.Abstractions genuinely cross-platform with no conditional-compilation Windows code inside it — mirroring how PowerCSharp.Compatibility is kept as its own isolated layer rather than #if blocks scattered through Core.
Applied as a complete strip, not a rename-only pass: no references of any kind — in code, XML doc comments, default string literals, config keys, file/namespace names, or this documentation — to the original client, product, or internal ticket system the reference implementation came from. All #if DEBUG / debug-console scaffolding was removed and replaced with proper ILogger usage (e.g. RetryPolicyProvider's unit-test-host detection uses assembly inspection, not a debug-only branch). Sentry SDK and third-party issue-tracking framework calls were removed entirely — not renamed and kept — per the explicit exclusion in §10.
IssueManager, DiagnosticsService, DiagnosticHeaders, DiagnosticsLogger + DiagnosticsLoggerProvider + NullScope, EventLogWriter, EventLogRetentionCleaner, RetryPolicyProvider (+ a newly-authored IRetryPolicyProvider, since the original had no interface split appropriate for this dependency-isolation boundary — see §3).
| # | Decision |
|---|---|
| 1 | Operational is a standalone family beside the Features Framework (§2), not a full Features Framework member. |
| 2 | Full debranding: code, docs, comments — no mentions of any kind (§9). |
| 3 | v1 targets ASP.NET Core/Web API only; a platform-agnostic version is deferred (§5). |
| 4 | Same NoOp/enablement pattern as Cache/Sanitization (§7). |
| 5 | Reuse PowerCSharp.Feature.Sanitization.Abstractions for masking/sensitive-data filtering; leave // TODO for correlation id (§8). |
| 6 | Target netstandard2.0;net8.0 for Abstractions; Windows Event Log isolated into its own future provider package, following the .Compatibility isolation precedent (§6). |
| 7 | Remove all debug-only scaffolding (#if DEBUG, ad-hoc console output). |
| 8 | Own version family (PowerCSharpOperationalVersion), same pattern as Cache/Sanitization. |
| 9 | EventLogRetentionCleaner and RetryPolicyProvider included in v1 scope alongside the core diagnostics/logging/event-log path. |
| 10 | IRetryPolicyProvider placed in the core PowerCSharp.Operational package, not .Abstractions, because its shape depends on Polly types (§3). |
| 11 | Static service-locator resolution converted to constructor DI throughout, except the one narrowly-scoped DiagnosticsLogger → HttpContext.RequestServices bridge (§8). |
| 12 | EventLogWriter registered as a DI singleton rather than a hand-rolled static Instance (§8). |
| 13 | New unit tests written from scratch — no pre-existing tests were available to port. |
| Back | FazBrowse Home | New Git URL |