EnumCraft.FeatureFlags.Json 1.0.1

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

EnumCraft.FeatureFlags.Json

JSON file provider for EnumCraft.FeatureFlags.

NuGet License: MIT


Overview

EnumCraft.FeatureFlags.Json is the JSON file-based data provider for the EnumCraft feature flag system. It loads feature flag configuration from a JSON file, supports per-tenant overrides, and automatically reloads when the file changes — using a FileSystemWatcher with a polling fallback for reliability.

This package is part of the EnumCraft ecosystem:

Package Description
EnumCraft.Core Strongly-typed enums and flags (TypedEnum, TypedFlag)
EnumCraft.Json JSON serialization extensions for TypedEnum and TypedFlag
EnumCraft.FeatureFlags Feature flag abstraction and resolution engine
EnumCraft.FeatureFlags.Json JSON file provider (this package)

How It Works

JsonFeatureFlagProvider loads the JSON file once at startup and holds the result as an in-memory snapshot. All calls to IsActive and IsActive(tenantId) resolve against that snapshot — no file I/O occurs at query time.

When the file changes, the provider reloads it in the background and atomically swaps the snapshot. All subsequent reads see the new data. If the reload fails, the previous snapshot is retained — no partial reads, no dropped flags.

Querying is safe to call on every request. The per-call cost is a dictionary lookup.


Installation

dotnet add package EnumCraft.FeatureFlags.Json

Requirements

  • .NET Standard 2.0+ or .NET 8.0+
  • EnumCraft.FeatureFlags
  • EnumCraft.Core

Quick Start

using EnumCraft.FeatureFlags.Json;

// Best Practice: name the json file to match its associated derived type
var options = new JsonFeatureFlagProviderOptions { DirectoryPath = AppDomain.CurrentDomain.BaseDirectory,
                                                   FileName      = "AppFeatureFlag.json" };  

var provider = new JsonFeatureFlagProvider(options);

if(!AppFeatureFlag.TryConfigure(provider, out var error))
{
  Console.WriteLine($"Failed to configure flags: {error}");
  return;
}

Optional Logging

Pass an ILogger to the constructor for diagnostic output. Falls back to NullLogger if not provided.

var logger   = loggerFactory.CreateLogger<AppFeatureFlag>();
var provider = new JsonFeatureFlagProvider(options, logger);

You can also set a logger on the provider instance after construction:

provider.SetLogger(logger);

Configuration Options

Property Default Description
DirectoryPath (required) Directory where the JSON file is located
FileName "FeatureFlags.json" Name of the JSON file (best practice - name it to the associated derived type)
EnableAutoReload true Watch for file changes and reload automatically
DebounceMs 350 Minimum ms between reloads, prevents rapid re-reads
PollMs 2000 Polling interval ms - fallback safety net alongside the watcher
MaxRetryAttempts 10 Max attempts to read file - handles mid-write states
RetryDelayMs 100 Delay ms between retry attempts

FullPath is computed automatically from DirectoryPath + FileName.


JSON File Format

Name your JSON file to match your derived flag type (e.g., AppFeatureFlag.json).

{
  "global": {
    "DarkMode":        true,
    "NewDashboard":    true,
    "BetaReporting":   false,
    "MaintenanceMode": false
  },
  "tenants": {
    "1001": {
      "DarkMode":     false,
      "NewDashboard": false
    },
    "1002": {
      "BetaReporting": true
    }
  }
}

Resolution Order

  1. Tenant override — per-tenant value, if present
  2. Global override — global value from JSON, if present
  3. Default — constructor-defined fallback (isActiveDefault)

Key Casing

Flag keys in the JSON file must match the Code property of your flag definition exactly (case-sensitive). If you define your flags using nameof(), the key is the member name as written in C# — for example, "DarkMode", not "darkMode" or "dark_mode". A key mismatch silently falls through to the flag's constructor default with no warning.


Auto-Reload Behavior

When EnableAutoReload is true (the default):

  • A FileSystemWatcher monitors the JSON file for changes
  • A polling timer runs as a fallback safety net
  • A debounce window (default 350ms) prevents rapid successive reloads
  • On successful reload, the Changed event is raised and consumers can call GetSnapshot() for the latest data
  • On failed reload due to a transient IO error or mid-write corruption, the previous snapshot is retained — no partial reads
  • The watcher is automatically recreated if it encounters a buffer overflow error

Emergency Shutoff

Deleting the JSON file reverts all flags to their isActiveDefault constructor values immediately. The Changed event fires on deletion so consumers are notified.

This is the recommended emergency shutoff pattern - no application restart required. Delete the file to revert all flags to their constructor-defined defaults. Flags with isActiveDefault: false will become inactive; flags with isActiveDefault: true will become active.

When the file is recreated, the provider detects the change and reloads the new values automatically.


Production Deployment

Multiple App Servers

Each running instance of your application loads and watches the JSON file independently. There is no cross-process coordination — each process manages its own in-memory snapshot.

For deployments with multiple app servers, point all instances at the same shared file:

  • A shared network path (UNC path or mapped drive)
  • A mounted volume shared across containers
  • A managed file storage location (e.g., Azure Files, AWS EFS)

When the file is updated, each instance will detect the change and reload independently within its configured DebounceMs + PollMs window (worst-case: ~2.35 seconds at defaults).

⚠️ Write coordination is not provided. If multiple processes write to the same file simultaneously, last-write-wins. For v1.0.0, the JSON file is treated as read-only at runtime — updates are made out-of-band (deploy, copy, or manual edit).


Disposal

JsonFeatureFlagProvider implements IDisposable. At application shutdown, dispose the provider to stop the FileSystemWatcher and polling timer cleanly:

provider.Dispose();

After disposal, GetSnapshot() continues to return the last known snapshot — no exceptions thrown. The Changed event will not fire after disposal.


Framework Support

Framework Supported
.NET Framework 4.7.2+
.NET Standard 2.0+
.NET 8+

Dependencies

  • EnumCraft.Core (v1.0.0 or later)
  • EnumCraft.FeatureFlags (v1.0.0 or later)
  • System.Text.Json (v4.7.2 or later)

Known Limitations

  • Key matching is case-sensitive. A key mismatch silently falls through to the flag's constructor default with no warning. Configurable case sensitivity is planned for a future release.
  • No write coordination across processes. See Production Deployment.
  • Configure() may only be called once per flag type. Use TryConfigure() for a non-throwing alternative. Runtime provider swapping (Reconfigure()) is planned for a future release.


License

MIT — see LICENSE for details.


Author

Randel Bjorkquist — GitHub | NuGet

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  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 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. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos 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
1.0.1 94 4/26/2026
1.0.0 97 4/26/2026
0.3.1-preview 99 4/22/2026
0.3.0-preview 102 4/20/2026
0.2.2-preview 102 4/6/2026
0.2.1-preview 108 3/2/2026
0.2.0-preview 104 2/24/2026