Skip to content

codingdroplets/dotnet-feature-flags-aspnetcore

Repository files navigation

dotnet-feature-flags-aspnetcore

Feature Flags in ASP.NET Core Web API using Microsoft.FeatureManagement v4 — simple on/off flags, percentage rollouts, targeting filters, and [FeatureGate] action guards, all wired up with zero custom infrastructure.

Visit CodingDroplets YouTube Patreon Buy Me a Coffee GitHub


🚀 Support the Channel — Join on Patreon

If this sample saved you time, consider joining our Patreon community. You'll get exclusive .NET tutorials, premium code samples, and early access to new content — all for the price of a coffee.

👉 Join CodingDroplets on Patreon

Prefer a one-time tip? Buy us a coffee ☕


🎯 What You'll Learn

  • How to install and register Microsoft.FeatureManagement.AspNetCore in an ASP.NET Core Web API
  • How to declare simple on/off feature flags in appsettings.json
  • How to configure a percentage-based rollout (Microsoft.Percentage filter) for gradual feature releases
  • How to configure a targeting filter (Microsoft.Targeting) to enable features for specific users or groups
  • How to use IFeatureManager.IsEnabledAsync() inside controller actions to branch logic
  • How to use the [FeatureGate] attribute to declaratively guard an entire endpoint
  • How to centralise all flag names as constants to eliminate magic strings
  • How to override flags per environment using appsettings.Development.json
  • How to unit-test feature-flag-driven controller logic using Moq

🗺️ Architecture Overview

┌───────────────────────────────────────────────────────────┐
│                   HTTP Request                            │
└────────────────────────────┬──────────────────────────────┘
                             │
                    ┌────────▼────────┐
                    │  ASP.NET Core   │
                    │  Middleware     │
                    └────────┬────────┘
                             │
          ┌──────────────────┼──────────────────┐
          │                  │                  │
  ┌───────▼──────┐  ┌────────▼───────┐  ┌──────▼──────────┐
  │ Products     │  │ Search         │  │ Dashboard       │
  │ Controller   │  │ Controller     │  │ Controller      │
  │              │  │                │  │ [FeatureGate]   │
  └──────┬───────┘  └───────┬────────┘  └──────┬──────────┘
         │                  │                  │
         └──────────────────┼──────────────────┘
                            │
                   ┌────────▼────────────┐
                   │   IFeatureManager   │
                   │ (IsEnabledAsync)    │
                   └────────┬────────────┘
                            │
               ┌────────────▼────────────────┐
               │   Feature Configuration     │
               │   appsettings.json          │
               │   "FeatureManagement": {    │
               │     "NewPricingEngine": true │
               │     "BetaSearch": {         │
               │       Percentage: 50%       │
               │     }                       │
               │     "VipDashboard": {       │
               │       Targeting filter      │
               │     }                       │
               │   }                         │
               └─────────────────────────────┘

📋 Feature Flag Types — Summary Table

Flag Name Type Default Behaviour
NewPricingEngine Simple on/off true Switches between 10% discount pricing and legacy pricing
DarkModeSupport Simple on/off false Enables a dark-mode preference feature
BetaSearch Percentage rollout (50%) 50% of requests Routes search requests to BetaEngine vs StableEngine
VipDashboard Targeting filter Specific users/groups Guards the VIP dashboard endpoint

📁 Project Structure

dotnet-feature-flags-aspnetcore/
├── dotnet-feature-flags-aspnetcore.sln
│
├── src/
│   └── FeatureFlagsDemo/
│       ├── Controllers/
│       │   ├── DashboardController.cs   # [FeatureGate] declarative guard example
│       │   ├── FeaturesController.cs    # Query flag states via HTTP
│       │   ├── ProductsController.cs    # Flag-driven pricing strategy switch
│       │   └── SearchController.cs      # Percentage-rollout routing example
│       │
│       ├── Models/
│       │   ├── FeatureFlagStatusDto.cs  # Response shape for flag queries
│       │   ├── ProductDto.cs            # Product response with pricing engine info
│       │   └── SearchResultDto.cs       # Search response with engine label
│       │
│       ├── Services/
│       │   ├── IPricingService.cs       # Interface: Calculate + EngineName
│       │   ├── LegacyPricingService.cs  # Strategy: no discount (flag OFF)
│       │   └── NewPricingService.cs     # Strategy: 10% discount (flag ON)
│       │
│       ├── FeatureFlags.cs              # Centralised flag name constants
│       ├── Program.cs                   # App bootstrap + FeatureManagement DI
│       ├── appsettings.json             # Production flag config
│       └── appsettings.Development.json # Dev override: all flags ON
│
└── tests/
    └── FeatureFlagsDemo.Tests/
        ├── FeaturesControllerTests.cs   # 4 tests
        ├── PricingServiceTests.cs       # 11 tests
        ├── ProductsControllerTests.cs   # 6 tests
        └── SearchControllerTests.cs     # 5 tests

🛠️ Prerequisites

Requirement Version
.NET SDK 10.0+
IDE Visual Studio 2022 / Rider / VS Code
NuGet Microsoft.FeatureManagement.AspNetCore 4.5.0

⚡ Quick Start

# 1. Clone the repository
git clone https://github.com/codingdroplets/dotnet-feature-flags-aspnetcore.git
cd dotnet-feature-flags-aspnetcore

# 2. Build
dotnet build -c Release

# 3. Run (Development — all flags ON)
dotnet run --project src/FeatureFlagsDemo

# 4. Open Swagger UI
# http://localhost:5289/swagger

🔧 How It Works

1. Register Feature Management

// Program.cs
builder.Services.AddFeatureManagement(
    builder.Configuration.GetSection("FeatureManagement"));

2. Define flag names as constants (no magic strings)

// FeatureFlags.cs
public static class FeatureFlags
{
    public const string NewPricingEngine = "NewPricingEngine";
    public const string BetaSearch       = "BetaSearch";
    public const string VipDashboard     = "VipDashboard";
    public const string DarkModeSupport  = "DarkModeSupport";
}

3. Configure flags in appsettings.json

"FeatureManagement": {
  // Simple on/off
  "NewPricingEngine": true,
  "DarkModeSupport": false,

  // Percentage-based rollout — 50% of requests see BetaSearch
  "BetaSearch": {
    "EnabledFor": [
      { "Name": "Microsoft.Percentage", "Parameters": { "Value": 50 } }
    ]
  },

  // Targeting — only specific users / groups
  "VipDashboard": {
    "EnabledFor": [
      {
        "Name": "Microsoft.Targeting",
        "Parameters": {
          "Audience": {
            "Users": [ "alice@example.com" ],
            "Groups": [ { "Name": "VipBeta", "RolloutPercentage": 100 } ],
            "DefaultRolloutPercentage": 0
          }
        }
      }
    ]
  }
}

4. Inject IFeatureManager and branch logic

// ProductsController.cs — switch pricing strategy at runtime
private async Task<IPricingService> GetPricingServiceAsync()
{
    bool useNewEngine = await _featureManager.IsEnabledAsync(FeatureFlags.NewPricingEngine);
    return useNewEngine
        ? new NewPricingService()   // 10% discount
        : new LegacyPricingService(); // no discount
}

5. Declaratively guard an endpoint with [FeatureGate]

// DashboardController.cs — returns 404 automatically when flag is disabled
[HttpGet("vip")]
[FeatureGate(FeatureFlags.VipDashboard)]
public IActionResult GetVipDashboard()
{
    return Ok(new { Message = "Welcome to the VIP Dashboard!" });
}

6. Override all flags in Development

// appsettings.Development.json — all flags ON so you can test every path
"FeatureManagement": {
  "NewPricingEngine": true,
  "DarkModeSupport": true,
  "BetaSearch": true,
  "VipDashboard": true
}

📡 API Endpoints

Method Endpoint Description Status Codes
GET /api/features List all feature flags and their current state 200
GET /api/features/{flagName} Get a single flag's state by name 200, 404
GET /api/products Get all products (pricing depends on NewPricingEngine flag) 200
GET /api/products/{id} Get a single product by ID 200, 404
GET /api/search?q={query} Search products (engine depends on BetaSearch flag) 200, 400
GET /api/dashboard/vip VIP dashboard — guarded by [FeatureGate(VipDashboard)] 200, 404
GET /api/dashboard/standard Standard dashboard — always available 200

🧪 Running Tests

dotnet test -c Release

Test Summary

Test Class Tests Covers
PricingServiceTests 11 Discount calculation, rounding, engine names
ProductsControllerTests 6 Flag-driven pricing, 404 handling
SearchControllerTests 5 Engine routing, query validation, response shape
FeaturesControllerTests 4 Flag status listing, single flag lookup
Total 26 26 passed, 0 failed

🤔 Key Concepts

Why Microsoft.FeatureManagement over a simple bool in config?

Approach Pros Cons
appsettings bool Simple, no dependency No rollout strategies, no targeting
Custom IFeatureFlag Full control Reinventing the wheel
Microsoft.FeatureManagement Built-in filters, Azure App Config compatible, attribute guards Slight learning curve

Feature flag strategies compared

Strategy Config key Use case
Simple on/off "Flag": true Kill switch, dev toggle
Percentage rollout Microsoft.Percentage Canary releases, A/B testing
Targeting filter Microsoft.Targeting Beta users, VIP groups
Time window filter Microsoft.TimeWindow Scheduled feature launches

IFeatureManager vs [FeatureGate]

Technique When to use
IsEnabledAsync(flag) Branch logic inside a method — switch implementations, return different data
[FeatureGate(flag)] Declaratively gate an entire action — automatic 404 when disabled

🏷️ Technologies Used

  • ASP.NET Core 10 — Web API framework
  • Microsoft.FeatureManagement.AspNetCore 4.5.0 — Feature flag engine
  • Swashbuckle.AspNetCore — Swagger / OpenAPI documentation
  • xUnit — Unit testing framework
  • Moq — Mocking framework for IFeatureManager in tests

📚 References


📄 License

This project is licensed under the MIT License.


🔗 Connect with CodingDroplets

Platform Link
🌐 Website https://codingdroplets.com/
📺 YouTube https://www.youtube.com/@CodingDroplets
🎁 Patreon https://www.patreon.com/CodingDroplets
☕ Buy Me a Coffee https://buymeacoffee.com/codingdroplets
💻 GitHub http://github.com/codingdroplets/

Want more samples like this? Support us on Patreon or buy us a coffee ☕ — every bit helps keep the content coming!

About

Feature Flags in ASP.NET Core Web API using Microsoft.FeatureManagement v4: on/off flags, percentage rollouts, targeting filters, and FeatureGate action guards.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages