FluentAzure 0.3.0-rc.1

This is a prerelease version of FluentAzure.
dotnet add package FluentAzure --version 0.3.0-rc.1
                    
NuGet\Install-Package FluentAzure -Version 0.3.0-rc.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="FluentAzure" Version="0.3.0-rc.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="FluentAzure" Version="0.3.0-rc.1" />
                    
Directory.Packages.props
<PackageReference Include="FluentAzure" />
                    
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 FluentAzure --version 0.3.0-rc.1
                    
#r "nuget: FluentAzure, 0.3.0-rc.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 FluentAzure@0.3.0-rc.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=FluentAzure&version=0.3.0-rc.1&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=FluentAzure&version=0.3.0-rc.1&prerelease
                    
Install as a Cake Tool

FluentAzure

Guard rails for .NET configuration on Azure: fail-fast validation, secret redaction, health checks and compile-time analyzers. It works on top of Microsoft's App Configuration and Key Vault providers, or with FluentAzure's own configuration pipeline.

NuGet .NET Native AOT Azure Fluent License

What's new in 0.3.0-rc.1:

  • A configuration guard that validates, health-checks and redacts configuration from any provider, including Microsoft's AddAzureAppConfiguration() and AddAzureKeyVault().
  • Analyzers that check Microsoft's APIs and the Azure SDK clients as well as FluentAzure's.
  • An IConfiguration provider with IOptionsMonitor<T> reload, an App Configuration source, managed/workload identity, OpenTelemetry and .NET 10 / Native AOT support.
  • One binder for every typed API, and deprecation of the build-once AddFluentAzure<T>() registrations in favour of the options pattern.

See the changelog and the upgrade guide.

πŸ›‘οΈ Why FluentAzure?

Microsoft's packages load configuration. FluentAzure makes sure it's complete, stays secret, and stays healthy, without changing how you load it.

Microsoft's providers on their own With FluentAzure
A required setting is missing or invalid Found at first use, often as a null or an exception inside a request Startup stops, listing every missing or invalid key
Logging the configuration GetDebugView() prints secrets GetRedactedDebugView() masks Key Vault values and anything that looks like a credential
A refresh brings in a bad value Nothing notices The health check re-runs your rules
Code review Nothing flags insecure setup Analyzers flag http:// endpoints, hard-coded Secret= connection strings and GetDebugView() at compile time
Error messages Can echo the value Name the key and the rule, never the value

⚑ Quick Start

Keep loading configuration the way you do today, and add the guard:

using Azure.Identity;
using FluentAzure;

var builder = WebApplication.CreateBuilder(args);
var credential = new DefaultAzureCredential();

// Microsoft's providers, unchanged
builder.Configuration
    .AddAzureAppConfiguration(o => o.Connect(new Uri("https://myconfig.azconfig.io"), credential))
    .AddAzureKeyVault(new Uri("https://myvault.vault.azure.net/"), credential);

// FluentAzure: fail fast at startup, with every problem listed by key (never by value)
builder.Services.AddFluentAzureGuard(guard => guard
    .Required("Database:ConnectionString", "Jwt:SecretKey", "Jwt:Issuer")
    .Validate("Jwt:SecretKey", v => v.Length >= 32, "must be at least 32 characters")
    .Sensitive("Payments:*"));

// ...and keep checking after configuration refreshes
builder.Services.AddHealthChecks().AddFluentAzureGuard();

If Jwt:SecretKey is too short, the app doesn't start:

OptionsValidationException: Configuration key 'Jwt:SecretKey' must be at least 32 characters.

The analyzers ship in the same package and need no setup. See Configuration guard for the full guide and examples/WebApi.Example for a complete app.

Prefer a single fluent pipeline instead of Microsoft's providers? FluentAzure has its own sources for environment variables, JSON, Key Vault and App Configuration, with the same safety features. See Where to Start and the usage patterns below.

🧭 Where to Start

You are building… Use Docs
An app that already uses Microsoft's AddAzureAppConfiguration() / AddAzureKeyVault() The configuration guard: builder.Services.AddFluentAzureGuard(...) adds fail-fast startup validation, a health check and secret redaction on top of what you have Configuration guard
An ASP.NET Core app, Azure Functions (isolated) or a worker service The IConfiguration provider: builder.Configuration.AddFluentAzureAsync(...) + AddFluentAzureOptions<T>(). You get reload, IOptionsMonitor<T>, health checks and fail-fast startup Configuration integration
A console tool, script or test The standalone pipeline: FluentConfig.Create()...BuildAsync() returns a Result you can Match Examples below
A trimmed or Native AOT app The provider + the configuration binding source generator Native AOT

Whichever you choose:

πŸ“¦ Installation

dotnet add package FluentAzure --prerelease

The current version is shown on the NuGet badge above. The package includes the FluentAzure analyzers (see docs/analyzers.md).

πŸ”’ Version Information

You can access the current version programmatically:

using FluentAzure;

// Get the current version
string version = FluentConfig.CurrentVersion; // e.g. "1.2.0" or "1.3.0-rc.1"

// Or access version details directly
int major = FluentAzure.Version.Major;
int minor = FluentAzure.Version.Minor;
int patch = FluentAzure.Version.Patch;
bool isPreRelease = FluentAzure.Version.IsPreRelease;

πŸ“– Example Usage Patterns

Standalone Pipeline (console apps, scripts, tests)
using FluentAzure; // Single using statement!

var config = await FluentConfig
    .Create()  // Ultra clean - just FluentConfig.Create()!
    .FromEnvironment()
    .Required("DATABASE_URL")
    .Optional("CACHE_TTL", "300")
    .BuildAsync();
Complex Enterprise Setup
using FluentAzure; // Single using statement!

var configResult = await FluentConfig
    .Create()  // Ultra clean - just FluentConfig.Create()!
    .FromJsonFile("appsettings.json")
    .FromEnvironment()
    .FromKeyVault("https://company-prod-kv.vault.azure.net")
    .Transform("ConnectionString", DecryptConnectionString)
    .Validate(c => Uri.IsWellFormedUriString(c["ServiceUrl"], UriKind.Absolute) ? null : "ServiceUrl must be a valid URI")
    .BuildAsync();

var config = configResult.Bind<AppConfiguration>();
Dependency Injection

Register settings with the options pattern: bind from IConfiguration (fed by Microsoft's providers and guarded by AddFluentAzureGuard(), or by FluentAzure's provider below) with AddFluentAzureOptions<T>(), and inject IOptions<T> or IOptionsMonitor<T>.

Configuration keys are case-insensitive, and environment variables using the standard __ separator (e.g. ConnectionStrings__Default) are also available under their : form (ConnectionStrings:Default).

The older services.AddFluentAzure<T>(...) / AddFluentAzureAsync<T>(...) registrations are obsolete and will be removed in 1.0. They build once at startup and register T as a singleton, with no reload. See the upgrade guide for the replacement.

FluentAzure's sources in ASP.NET Core / Functions (IConfiguration + IOptionsMonitor)

Plug a FluentAzure pipeline into the standard configuration system. Required keys and validations still fail fast at startup, and values become available to IConfiguration, IOptions<T> and IOptionsMonitor<T>:

using FluentAzure;

var builder = WebApplication.CreateBuilder(args);

await builder.Configuration.AddFluentAzureAsync(
    fluent => fluent
        .FromKeyVault(builder.Configuration["KeyVault:Url"]!)
        .Required("Database:ConnectionString"),
    reloadInterval: TimeSpan.FromMinutes(5) // pick up rotated secrets without a restart
);

// Binds the "Database" section, validates [Required]/[Range] etc. and fails at startup if invalid
builder.Services.AddFluentAzureOptions<DatabaseOptions>(builder.Configuration, "Database");

// Consumers: inject IOptionsMonitor<DatabaseOptions> to see reloaded values
  • Keys using the __ separator (environment variables, FluentAzure JSON flattening) are exposed with the standard : separator.
  • A failed reload keeps the last good values; observe failures with options.OnReloadError via the AddFluentAzure(configure, configureSource) overload.
  • builder.Configuration.AddFluentAzure(...) is the synchronous equivalent.
Azure App Configuration

Load settings, feature flags and Key Vault references from App Configuration, with label layering, snapshots and sentinel-key refresh:

var config = await FluentConfig
    .Create()
    .FromAppConfiguration("https://myconfig.azconfig.io", options =>
    {
        options.Labels.Add("Production");     // overrides unlabelled defaults
        options.IncludeFeatureFlags = true;   // exposed under FeatureManagement:*
        options.SentinelKey = "Sentinel";     // cheap change detection when reloading
    })
    .Required("Database:ConnectionString")    // may be a Key Vault reference; resolved automatically
    .BuildAsync();

See docs/app-configuration-source.md for all options.

Identity & Secret Redaction

Choose one identity for every Azure source in the pipeline (in any order relative to the sources), and keep secrets out of logs:

builder.Configuration.AddFluentAzure(fluent => fluent
    .UseManagedIdentity()                  // or UseWorkloadIdentity() / UseCredential(...)
    .FromAppConfiguration("https://myconfig.azconfig.io")
    .FromKeyVault("https://myvault.vault.azure.net")
    .Sensitive("Jwt:SigningKey"));         // mark secrets that come from other sources

logger.LogDebug("{Config}", builder.Configuration.GetRedactedDebugView()); // Key Vault values appear as ***

A per-source credential (KeyVaultConfiguration.Credential, AppConfigurationOptions.Credential) still takes precedence. Binding and conversion errors never include configuration values.

Observability: OpenTelemetry & Health Checks

FluentAzure emits traces and metrics through System.Diagnostics (no extra dependency), ready for OpenTelemetry:

builder.Services.AddOpenTelemetry()
    .WithTracing(t => t.AddSource(FluentAzureDiagnostics.ActivitySourceName))
    .WithMetrics(m => m.AddMeter(FluentAzureDiagnostics.MeterName));

builder.Services.AddHealthChecks().AddFluentAzure(tags: new[] { "ready" });
Signal Name Tags
Span FluentAzure.Build, with a child FluentAzure.LoadSource per source fluentazure.source, fluentazure.outcome, fluentazure.reload, key/error counts
Histogram (s) fluentazure.build.duration, fluentazure.source.load.duration fluentazure.source, fluentazure.outcome, fluentazure.reload
Counter fluentazure.provider.reloads fluentazure.outcome = changed / unchanged / failure

Telemetry and health data contain source names, outcomes, durations, counts and timestamps only β€” never configuration values or error messages.

The health check does not call Azure. It reports what the configuration providers last observed:

  • Healthy: every load succeeded.
  • Degraded: the last reload failed, so the last good values are still being served.
  • Unhealthy (or your failureStatus): no FluentAzure provider is registered, or values are older than staleAfter (by default, three reload intervals).
Trimming & Native AOT

FluentAzure targets .NET 8 and .NET 10 and is annotated for trimming and Native AOT. The pipeline, all sources (environment, JSON, Key Vault, App Configuration) and the IConfiguration provider are AOT-safe. The reflection-based binders (BuildAsync<T>(), Bind<T>(), AddFluentAzure<T>(), AddFluentAzureOptions<T>()) are marked [RequiresUnreferencedCode]/[RequiresDynamicCode], so the compiler warns if you use them in a trimmed or AOT app. In those apps, feed IConfiguration and bind with the configuration binding source generator:

<PublishAot>true</PublishAot>
<EnableConfigurationBindingGenerator>true</EnableConfigurationBindingGenerator>
IConfigurationRoot configuration = new ConfigurationBuilder()
    .AddFluentAzure(fluent => fluent.UseManagedIdentity().FromKeyVault(vaultUrl).Required("App:Name"))
    .Build();

services.AddOptions<AppOptions>().Bind(configuration.GetSection("App")).ValidateOnStart(); // source-generated

See examples/Aot.Example. CI publishes it with Native AOT and fails on any trimming or AOT warning.

Analyzers

The package includes compile-time analyzers (docs/analyzers.md):

  • FAZ0001: a Required("key") that the BuildAsync<T>() type never binds (usually a typo).
  • FAZ0002: a Key Vault or App Configuration endpoint that isn't HTTPS, including in Microsoft's AddAzureKeyVault / AddAzureAppConfiguration and the Azure SDK clients.
  • FAZ0003: a hard-coded App Configuration connection string containing a secret, in the same APIs.
  • FAZ0004: GetDebugView(), which prints secrets; use GetRedactedDebugView() instead.
Web API with FluentAzure's provider
// Program.cs
using FluentAzure;

var builder = WebApplication.CreateBuilder(args);

await builder.Configuration.AddFluentAzureAsync(fluent => fluent
    .UseManagedIdentity()
    .FromKeyVault(builder.Configuration["KeyVault:Url"]!)
    .Required("ConnectionStrings:DefaultConnection")
    .Required("Jwt:SecretKey"));

builder.Services.AddFluentAzureOptions<JwtOptions>(builder.Configuration, "Jwt");
builder.Services.AddHealthChecks().AddFluentAzure();

var app = builder.Build();
app.MapHealthChecks("/health");

A missing required key stops startup with a FluentAzureConfigurationException that lists every problem. Values are available through IConfiguration, IOptions<JwtOptions> and builder.Configuration.GetConnectionString("DefaultConnection").

πŸš€ Getting Started

Prerequisites

  • .NET 8 or .NET 10.
  • For Azure sources: an identity with access to your Key Vault and/or App Configuration store. No Azure subscription is needed for environment, JSON or in-memory sources. For local work, the App Configuration emulator runs in Docker.

Quick Start

  1. Install the package: dotnet add package FluentAzure --prerelease.
  2. Add using FluentAzure;.
  3. Choose your starting point from Where to Start.
  4. Handle results with Match, or let the provider fail fast at startup.

Features

  • Configuration guard: startup validation, a health check and secret redaction for configuration from any provider, including Microsoft's App Configuration and Key Vault providers.
  • Fluent pipeline: chain sources, Required, Optional, Transform and Validate, and get a Result with every error, not just the first.
  • Sources: environment variables, JSON files, in-memory values, Azure Key Vault, and Azure App Configuration (labels, snapshots, Key Vault references, feature flags).
  • IConfiguration provider: works with the options pattern, reloads into IOptionsMonitor<T>, and keeps the last good values when a reload fails.
  • Identity: one managed/workload identity for every Azure source.
  • Secret safety: secrets are tracked and redacted, and never appear in errors, telemetry or health data.
  • Observability: OpenTelemetry traces and metrics, and a health check.
  • Analyzers: compile-time checks for key typos, insecure endpoints, hard-coded secrets and unredacted debug output, in FluentAzure's APIs, Microsoft's providers and the Azure SDK clients.
  • Platforms: .NET 8 and .NET 10, trimming and Native AOT compatible.

πŸ“š Documentation

Topic Page
Configuration guard: startup validation, health check and redaction for any provider docs/configuration-guard.md
IConfiguration provider, reload, options, AOT docs/configuration-integration.md
Azure App Configuration docs/app-configuration-source.md
Azure Key Vault docs/key-vault-configuration-source.md
Identity & secret redaction docs/identity-and-redaction.md
OpenTelemetry & health checks docs/observability.md
Binding to typed objects docs/enhanced-configuration-binding.md
Analyzers FAZ0001–FAZ0004 docs/analyzers.md
Changelog & upgrading CHANGELOG.md, docs/upgrade-guide.md
Examples examples/
Security SECURITY.md

🀝 Contributing

We welcome contributions! Please see our Contributing Guide for details on:

  • Code style and standards
  • Testing requirements
  • Pull request process
  • Development setup

πŸ“š Resources


Ready to revolutionize Azure configuration management? Let's build something awesome! πŸš€

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  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 is compatible.  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 (1)

Showing the top 1 NuGet packages that depend on FluentAzure:

Package Downloads
AzureFunctions.Example

Package Description

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.3.0-rc.1 66 10/6/2026
0.2.0-rc.5 145 7/11/2025
0.2.0-rc.4 120 7/11/2025
0.2.0-rc.3 115 7/11/2025
0.2.0-rc.1 169 7/8/2025
0.1.0-alpha.10 168 7/8/2025
0.1.0-alpha.9 382 7/8/2025
0.1.0-alpha.8 168 7/8/2025
0.1.0-alpha.6 176 7/8/2025
0.1.0-alpha.5 379 7/8/2025
0.1.0-alpha.4 171 7/8/2025
0.1.0-alpha.3 367 7/8/2025
0.1.0-alpha.2 383 7/8/2025