Cocoar.Configuration.AspNetCore 3.4.0-secrets.1

This is a prerelease version of Cocoar.Configuration.AspNetCore.
There is a newer prerelease version of this package available.
See the version list below for details.
dotnet add package Cocoar.Configuration.AspNetCore --version 3.4.0-secrets.1
                    
NuGet\Install-Package Cocoar.Configuration.AspNetCore -Version 3.4.0-secrets.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Cocoar.Configuration.AspNetCore" Version="3.4.0-secrets.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Cocoar.Configuration.AspNetCore" Version="3.4.0-secrets.1" />
                    
Directory.Packages.props
<PackageReference Include="Cocoar.Configuration.AspNetCore" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Cocoar.Configuration.AspNetCore --version 3.4.0-secrets.1
                    
#r "nuget: Cocoar.Configuration.AspNetCore, 3.4.0-secrets.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Cocoar.Configuration.AspNetCore@3.4.0-secrets.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Cocoar.Configuration.AspNetCore&version=3.4.0-secrets.1&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Cocoar.Configuration.AspNetCore&version=3.4.0-secrets.1&prerelease
                    
Install as a Cake Tool

Reactive, strongly-typed configuration layering for .NET

Cocoar.Configuration

Elevates configuration from hidden infrastructure to an observable, safety‑enforced subsystem you can trust under change and failure.

License: Apache-2.0 NuGet Downloads

πŸ“– Articles & Deep Dives

β€’ Reactive, Strongly-Typed Configuration in .NET: Introducing Cocoar.Configuration v3.0 (Part 1)
Learn how v3.0 simplifies configuration management with zero-ceremony DI, atomic multi-config updates, and reactive patterns.

β€’ Config-Aware Rules in .NET β€” The Power Feature of Cocoar.Configuration (Part 2)
Dive deeper into atomic recompute, required vs optional rules, and config-aware conditional logic for dynamic, tenant-aware setups.


Shouldn't configuration be this easy?

builder.Services.AddCocoarConfiguration(rule => [
    rule.For<AppSettings>().FromFile("appsettings.json").Select("App"),
    rule.For<AppSettings>().FromEnvironment("APP_")
]);

It is. AppSettings is now injectable β€” and automatically updates when configs change.


Install

dotnet add package Cocoar.Configuration
dotnet add package Cocoar.Configuration.AspNetCore

# Optional features:
dotnet add package Cocoar.Configuration.Secrets
dotnet add package Cocoar.Configuration.HttpPolling
dotnet add package Cocoar.Configuration.MicrosoftAdapter

Links: Cocoar.Configuration Β· AspNetCore Β· Secrets Β· HttpPolling Β· MicrosoftAdapter


Why Cocoar.Configuration?

Microsoft's IConfiguration works, but configuration deserves better. Here's what you get:

  • Zero ceremony – Define a class, add a rule, inject it. No Configure<T>() calls, no IOptions<T> wrappers.
  • Atomic multi-config updates – IReactiveConfig<(T1, T2, T3)> means multiple configs stay in sync. Never see inconsistent state.
  • Config-aware rules – Rules can access earlier config to make decisions. Perfect for multi-tenant and dynamic scenarios.
  • Reactive by default – Subscribe to changes automatically. No manual IOptionsMonitor wiring.
  • Explicit layering – Rules execute in order, last write wins. No hidden merge logic.
  • Interface deserialization – Support for interface-typed properties in config classes with explicit mapping.
  • Built-in health monitoring – Track provider status and config changes with IConfigurationHealthService.
  • ✨ Compile-time validation – Roslyn analyzers catch configuration errors while you code with red squiggles, automatic quick fixes, and CI/CD integration. Zero runtime cost. See Analyzer Documentation for details on diagnostics (COCFG001-006).

DI Lifetimes: Concrete config types are registered as Scoped (stable snapshot per request), while IReactiveConfig<T> is Singleton (continuous live updates). These defaults can be customized via the setup parameter.

Migration from IOptions

Before (IConfiguration + IOptions):

// Startup configuration
builder.Services.Configure<AppSettings>(builder.Configuration.GetSection("App"));

// Injection - requires wrapper
public class MyService(IOptions<AppSettings> options)
{
    var settings = options.Value; // Unwrap every time
}

After (Cocoar.Configuration):

// Startup configuration
builder.Services.AddCocoarConfiguration(rule => [
    rule.For<AppSettings>().FromFile("appsettings.json").Select("App")
]);

// Direct injection - no wrapper
public class MyService(AppSettings settings)
{
    // Just use it
}

// Or reactive
public class MyService(IReactiveConfig<AppSettings> config)
{
    config.Subscribe(newSettings => /* handle changes */);
}

Quick Example

var builder = WebApplication.CreateBuilder(args);

// Define your configuration rules
builder.Services.AddCocoarConfiguration(rule => [
    rule.For<AppSettings>().FromFile("appsettings.json").Select("App"),
    rule.For<AppSettings>().FromEnvironment("APP_"),
    rule.For<DatabaseConfig>().FromFile("appsettings.json").Select("Database")
]);

var app = builder.Build();

// Direct injection - just use your POCO
app.MapGet("/api/status", (AppSettings settings) => 
    new { settings.Version, settings.FeatureFlags });

app.Run();

For reactive scenarios (long-lived services):

public class CacheWarmer : BackgroundService
{
    private readonly IReactiveConfig<AppSettings> _config;
    
    public CacheWarmer(IReactiveConfig<AppSettings> config)
    {
        _config = config;
        
        // Subscribe once - rebuild cache when settings change
        _config.Subscribe(newSettings =>
        {
            Console.WriteLine($"Config changed, rebuilding cache...");
            RebuildCache(newSettings);
        });
    }
    
    protected override Task ExecuteAsync(CancellationToken stoppingToken) => Task.CompletedTask;
}

SignalR hub that streams atomic multi-config updates

public class ConfigHub : Hub
{
    private readonly IReactiveConfig<(AppSettings App, DatabaseConfig Db)> _configs;
    
    public ConfigHub(IReactiveConfig<(AppSettings App, DatabaseConfig Db)> configs)
    {
        _configs = configs;
        
        // Stream config changes to connected clients - always atomic
        _configs.Subscribe(async tuple =>
        {
            var (app, db) = tuple;
            await Clients.All.SendAsync("ConfigUpdated", new { app.Version, db.ConnectionString });
        });
    }
}

What You Can Do

Layer Configuration Sources

builder.Services.AddCocoarConfiguration(rule => [
    rule.For<AppSettings>().FromFile("appsettings.json"),           // Base
    rule.For<AppSettings>().FromFile("appsettings.Production.json"), // Environment
    rule.For<AppSettings>().FromEnvironment("APP_"),                 // Overrides
    rule.For<AppSettings>().FromCommandLine()                        // Final overrides (highest priority)
]);
// Rules execute in order - last write wins

Environment variable mapping:
Hierarchical keys use __ (double underscore):

APP_Database__Host=localhost
APP_Database__Port=5432
# Maps to: AppSettings.Database.Host and AppSettings.Database.Port

Command-line argument mapping:
Hierarchical keys use : or __:

dotnet run --Database:Host=localhost --Database:Port=5432 --Verbose
# Maps to: AppSettings.Database.Host, AppSettings.Database.Port, and AppSettings.Verbose (true)

Flexible switch prefixes for command-line arguments:
Use any prefix style (--, -, /, @, #, %) - even multiple at once:

// Single custom prefix
rule.For<AppConfig>().FromCommandLine(["-"])     // Unix-style
rule.For<AppConfig>().FromCommandLine(["/"])     // Windows-style
rule.For<AppConfig>().FromCommandLine(["@"])     // Custom semantic style

// Multiple prefixes simultaneously
rule.For<AppConfig>().FromCommandLine(["--", "-", "/"])
# Mix different styles in the same command line
dotnet run --host=localhost -port=8080 /verbose

# Or use semantic prefixes for self-documenting CLIs
invoke.exe @target=server #issue=123 %env=prod

Prefix filtering for command-line arguments:
Map arguments to specific configuration types:

builder.Services.AddCocoarConfiguration(rule => [
    rule.For<AppConfig>().FromCommandLine("app_"),
    rule.For<DatabaseConfig>().FromCommandLine("db_")
]);
dotnet run --app_host=localhost --db_connectionstring="Server=localhost"
# --app_host β†’ AppConfig.Host (prefix stripped)
# --db_connectionstring β†’ DatabaseConfig.ConnectionString (prefix stripped)

Required vs Optional Rules

// Required - fails fast if missing
rule.For<CoreSettings>().FromFile("required.json").Required()

// Optional - graceful degradation at runtime (default)
rule.For<OptionalSettings>().FromFile("optional.json")

Conditional Rules

rule.For<TenantSettings>().FromFile("tenant.json"),

rule.For<PremiumFeatures>().FromFile("premium.json")
    .When(accessor => accessor.GetRequiredConfig<TenantSettings>().IsPremium)
// Rules can access earlier config to make decisions

Dynamic Configuration

rule.For<TenantSettings>().FromFile("tenant.json"),

rule.For<ApiSettings>().FromHttpPolling(accessor =>
{
    var tenant = accessor.GetRequiredConfig<TenantSettings>();
    return new HttpPollingRuleOptions(
        $"https://{tenant.Region}.api.example.com/config",
        pollInterval: TimeSpan.FromMinutes(5)
    );
})
// Rules can derive behavior from earlier rules

Interface Exposure

builder.Services.AddCocoarConfiguration(rule => [
    rule.For<AppSettings>().FromFile("appsettings.json")
], setup => [
    setup.ConcreteType<AppSettings>().ExposeAs<IAppSettings>()
]);

// Both AppSettings and IAppSettings are injectable
public class MyService(IAppSettings settings) { }

Interface Deserialization

When your configuration classes have interface-typed properties, you need to map them to concrete types for JSON deserialization:

// Configuration with interface properties
public class AppSettings
{
    public string AppName { get; set; }
    public ILoggingConfig Logging { get; set; }  // Interface property!
}

builder.Services.AddCocoarConfiguration(rule => [
    rule.For<AppSettings>().FromEnvironment()  // or FromFile, FromHttpPolling, etc.
], setup => [
    // Map interface to concrete type for deserialization
    setup.Interface<ILoggingConfig>().DeserializeTo<LoggingConfig>()
]);

Why is this needed? When loading configuration from JSON sources (files, environment variables, HTTP), properties typed as interfaces cannot be deserialized directly. This mapping tells the deserializer which concrete type to instantiate.

Common scenarios:

  • Environment variables: Logging__LogLevel__Default=Debug
  • Visual Studio hot reload injecting logging configuration
  • Modular configuration with abstracted dependencies

Supports nested interfaces: If your interface properties contain other interface properties, just register all the mappings and they'll work at any depth.


Providers

  • File – JSON files with automatic change detection and reload
  • Environment Variables – Prefix-based with hierarchical mapping (__ for nesting)
  • Command-Line Arguments – POSIX-style parsing with prefix support and nested configuration
  • HTTP Polling – Remote config with polling; providers emit bytes and central dedup avoids churn (Cocoar.Configuration.HttpPolling)
  • Microsoft Adapter – Bridge existing IConfiguration sources (Cocoar.Configuration.MicrosoftAdapter)
  • Static/Observable – In-memory for testing and development

Examples

Explore real-world scenarios in the examples directory:

Example Description
BasicUsage ASP.NET Core with file + environment layering
FileLayering Multi-file layering (base/env/local)
DynamicDependencies Rules derived from earlier config
ConditionalRulesExample Config-aware conditional rules
TupleReactiveExample Atomic multi-config snapshots
HttpPollingExample Remote HTTP config polling
MicrosoftAdapterExample Integrate existing IConfiguration sources
SecretsBasicExample Memory-safe secret handling with Secret<T>
SecretsCertificateExample Pre-encrypted secrets with X.509 certificates

View all examples β†’


Documentation

Topic Link
Reactive Configuration Reactive Config
Health Monitoring Health Monitoring
Secrets & Memory Safety Secrets API Reference
Secret Protectors Secret Protectors
Secrets Usage Examples Usage Examples
Secure Bytes Secure Bytes
Secure Data Transfer Secure Data Transfer
Certificate Caching Intelligent Certificate Caching
Provider Guidance Provider Guidance
Migration from v2.x Migration Guide v2β†’v3
Migration from v1.x Migration Guide v1β†’v2

Testing

Over 200 automated tests covering:

  • Configuration layering and rule execution
  • Reactive updates and atomic snapshots
  • Provider reliability and failover
  • Concurrent access and race conditions
  • Health monitoring and status tracking

See the Testing Guide for details.


Contributing

Contributions welcome! See CONTRIBUTING.md for guidelines.

  • Semantic Versioning – Breaking changes increment major version
  • Apache 2.0 License – See LICENSE and NOTICE
  • Trademarks – See TRADEMARKS.md

Security

Secrets Management

For sensitive configuration data, use Cocoar.Configuration.Secrets:

  • Memory-safe Secret<T> type with automatic zeroization
  • Pre-encrypted envelope support (secrets encrypted at rest)
  • X.509 certificate-based hybrid encryption (RSA-OAEP + AES-GCM-256)
  • On-demand decryption via Secret<T>.Open() with controlled exposure windows
  • See Secrets documentation for details

General Best Practices

  • Use pre-encrypted secrets in configuration files (via Secrets package)
  • Use environment variables for non-sensitive overrides
  • Enable TLS/HTTPS for remote config endpoints
  • Consider Azure Key Vault or similar via the Microsoft Adapter

Runtime Security Posture

  • Byte-only pipeline below the orchestrator: providers and RuleManager handle UTF-8 bytes, not strings
  • Single parse point in the Configuration Orchestrator; no user-data strings are created below this layer
  • Centralized dedup in RuleManager using SHA-256 over transformed bytes; avoids unnecessary recompute/IO
  • Secure in-memory handling: transformed bytes are owned and zeroized on replace/dispose
  • Behavior is unchanged for consumers in success paths; improved health signaling during sustained provider failures

Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
3.4.0-secrets.36 170 11/16/2025
3.4.0-secrets.34 171 11/16/2025
3.4.0-secrets.32 95 11/15/2025
3.4.0-secrets.30 102 11/15/2025
3.4.0-secrets.29 107 11/15/2025
3.4.0-secrets.28 110 11/15/2025
3.4.0-secrets.27 113 11/15/2025
3.4.0-secrets.26 102 11/15/2025
3.4.0-secrets.25 158 11/14/2025
3.4.0-secrets.1 165 11/14/2025
3.4.0-beta.6 220 11/16/2025
3.3.0 183 10/23/2025
3.2.0 171 10/23/2025
3.1.1 170 10/19/2025
3.1.0 161 10/19/2025
3.0.0 177 10/12/2025
2.0.0 107 10/11/2025
1.1.0 178 9/25/2025
1.0.0 207 9/21/2025
0.15.0 294 9/18/2025
0.14.0 312 9/17/2025
0.13.0 319 9/17/2025
0.12.0 311 9/17/2025
0.11.1 301 9/16/2025
0.11.0 301 9/16/2025
0.10.0 304 9/16/2025
0.9.2 249 9/15/2025
0.9.1 225 9/14/2025
0.9.0 148 9/14/2025
0.4.0 161 9/13/2025