Feature Flags in C# with Microsoft Feature Management

Feature flagging is a software development technique that allows teams to enable or disable application features at runtime without deploying new code. This article explains the fundamentals of feature flagging and demonstrates how to implement dynamic feature toggles in C# using Microsoft's official Microsoft.FeatureManagement library, covering configuration, dependency injection, endpoint gating, and dynamic filters.

What Is Feature Flagging?

Feature flagging (also known as feature toggling) separates code deployment from feature release. By wrapping new or experimental code paths in conditional statements evaluated by a flag, developers can continuously integrate and deploy code to production while keeping incomplete features hidden from end users.

Key use cases include:

  • Trunk-Based Development: Merging unfinished features into the main branch safely.
  • Canary Releases and Gradual Rollouts: Exposing features to a small percentage of users before a full release.
  • Kill Switches: Instantly turning off a degraded feature without rolling back the entire application.
  • A/B Testing: Providing different experiences to different user segments to measure engagement.

Setting Up Microsoft Feature Management in .NET

Microsoft provides first-class support for feature flags in .NET via the Microsoft.FeatureManagement.AspNetCore NuGet package.

1. Install the Package

Run the following command in the .NET CLI:

dotnet add package Microsoft.FeatureManagement.AspNetCore

2. Define Flags in Configuration

By default, the library reads from the standard .NET configuration system under the FeatureManagement section. Add your flags to appsettings.json:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information"
    }
  },
  "FeatureManagement": {
    "BetaDashboard": true,
    "NewPaymentGateway": false
  }
}

Because .NET automatically reloads appsettings.json on change, updating a boolean value in this file dynamically toggles the feature in real time without restarting the application.

3. Register the Service

Register the feature management services in Program.cs:

using Microsoft.FeatureManagement;

var builder = WebApplication.CreateBuilder(args);

// Register Feature Management
builder.Services.AddFeatureManagement();

builder.Services.AddControllers();

var app = builder.Build();

app.UseRouting();
app.MapControllers();

app.Run();

Consuming Feature Flags in C

You can evaluate feature flags programmatically or declaratively using routing attributes.

Programmatic Check Using IFeatureManager

Inject the IFeatureManager interface into your controllers or services to check feature status asynchronously:

using Microsoft.AspNetCore.Mvc;
using Microsoft.FeatureManagement;

[ApiController]
[Route("api/[controller]")]
public class OrdersController : ControllerBase
{
    private readonly IFeatureManager _featureManager;

    public OrdersController(IFeatureManager featureManager)
    {
        _featureManager = featureManager;
    }

    [HttpPost("checkout")]
    public async Task<IActionResult> Checkout()
    {
        if (await _featureManager.IsEnabledAsync("NewPaymentGateway"))
        {
            // Code path for the new payment provider
            return Ok("Processed via New Payment Gateway");
        }

        // Fallback to legacy payment provider
        return Ok("Processed via Legacy Gateway");
    }
}

Declarative Checks Using [FeatureGate]

To restrict entire controllers or specific action methods based on a flag, use the [FeatureGate] attribute. If the flag is disabled, the framework automatically returns a 404 Not Found.

using Microsoft.AspNetCore.Mvc;
using Microsoft.FeatureManagement.Mvc;

[ApiController]
[Route("api/[controller]")]
public class BetaController : ControllerBase
{
    [FeatureGate("BetaDashboard")]
    [HttpGet("dashboard")]
    public IActionResult GetDashboard()
    {
        return Ok(new { Data = "Beta metrics and analytics" });
    }
}

Implementing Dynamic Feature Filters

Beyond static boolean switches, Microsoft.FeatureManagement supports dynamic evaluation using Feature Filters, allowing you to toggle features based on context, time windows, or percentages.

Built-in Percentage Filter

To roll out a feature gradually to a random percentage of requests, register the built-in filter:

builder.Services.AddFeatureManagement()
    .AddFeatureFilter<PercentageFilter>();

Then configure the filter in appsettings.json:

{
  "FeatureManagement": {
    "BetaDashboard": {
      "RequirementType": "Any",
      "EnabledFor": [
        {
          "Name": "Percentage",
          "Parameters": {
            "Value": 25
          }
        }
      ]
    }
  }
}

With this configuration, await _featureManager.IsEnabledAsync("BetaDashboard") will dynamically evaluate to true roughly 25% of the time.

Centralizing Flags for Distributed Systems

While appsettings.json works for single-instance applications, microservices and scaled web apps require centralized flag management. Microsoft.FeatureManagement integrates natively with Azure App Configuration. By chaining .AddAzureAppConfiguration() into the .NET configuration pipeline, flags can be toggled via the Azure portal or CLI and pushed across all running instances dynamically without service downtime.