Ship the code once. Turn capabilities on and off with config.
A discovery-and-DI orchestration engine: capabilities register themselves as toggleable modules, resolved through one composite flag system, with startup diagnostics built in.
$ dotnet add package PowerCSharp.FeaturesNothing is scanned unless you say so
Discovery is opt-in per assembly via options.ScanAssemblies(...) — a deliberate anti-surprise-registration design. A feature author can support auto-discovery via IFeatureModule reflection, explicit services.Add<Name>Feature() calls, or both at once.
builder.Services.AddPowerFeatures(builder.Configuration, options =>
{
options.AddBuiltInFeatures(); // opt-in the built-in bundle (CORS, etc.)
options.ScanAssemblies( // opt-in pluggable feature assemblies
typeof(CacheFeatureModule).Assembly);
options.Override("Cache", true); // optional code-level override
options.EnableDiagnosticsEndpoint(); // GET /power-features — off by default
});
var app = builder.Build();
app.UsePowerFeatures();One precedence chain, every feature obeys it
Code override beats a custom provider, which beats environment variables, which beats appsettings, which beats the feature's own default. Flags aren't boolean-only either — GetValue(key) returns a typed value with AsBoolean(), AsString(), AsEnum<T>(), and AsInt32() accessors.
Resolution order, highest precedence first
Code override
options.Override(key, value)
Custom provider
IFeatureFlagProvider
Environment variable
POWERFEATURES__KEY__ENABLED
appsettings.json
PowerFeatures:Key:Enabled
Feature default
FeatureDescriptor.DefaultEnabled
Every module looks the same to the engine
A FeatureRegistry (singleton in DI) records each module's key, tier, order, resolved enabled state, source, package ID, and version. Diagnostics are opt-in-safe: a structured startup log plus an HTTP endpoint at GET /power-features, off by default.
public interface IFeatureModule
{
string FeatureKey { get; } // stable identifier, e.g. "Cache"
int Order { get; } // registration + middleware ordering
void ConfigureServices(IFeatureRegistrationContext context);
void ConfigurePipeline(IFeaturePipelineContext context); // optional
}Two packages built on the engine
PowerCSharp.Features.Abstractions has zero third-party dependencies and targets netstandard2.0 + net8.0, so any feature — even a .NET Framework one — can reference it cheaply.
Naming that encodes the architecture
Plural Features is the framework. BuiltInFeatures is the one bundled tier. Singular Feature.<Name> is a pluggable module, and Feature.<Name>.<Provider> is a swappable backend — matching .NET convention.