Feature Flags in .NET: A Minimal API with Toggle Power (Using Microsoft.FeatureManagement)
Feature flags give you fine-grained control over your application’s behavior—turn features on or off, run experiments, and roll back instantly without redeploying. In this tutorial, you’ll integrate the first‑party Microsoft.FeatureManagement package into a .NET Minimal API, source flags from configuration and a custom provider, and explore both attribute- and code-based gating.
Why Use Microsoft.FeatureManagement?
- First‑party support: Official Microsoft package, integrates with .NET configuration and dependency injection.
- Flexible filters: Time windows, percentages, custom logic.
- Clean architecture alignment: Business logic stays decoupled from flag storage.
Table of Contents
- Project Setup
- Define Feature Flags in Configuration
- Wire Up Microsoft.FeatureManagement
- Use Flags in Endpoints
- FeatureGate Attributes
- Custom Feature Provider
- Testing
- References
Project Setup
dotnet new webapi -n FlagsWithMicrosoft
cd FlagsWithMicrosoft
Edit your .csproj to target .NET 6+ and remove the default Weather sample. Then install the feature management package:
dotnet add package Microsoft.FeatureManagement
Define Feature Flags in Configuration
Using appsettings.json, declare flags under a FeatureManagement section. This keeps flags in config, supporting environment-based overrides.
// appsettings.json
{
  "FeatureManagement": {
    "NewUI": true,
    "BetaEndpoint": false,
    "TimeLimitedFeature": {
      "EnabledFor": [
        { "Name": "TimeWindow", "Parameters": { "Start": "2025-05-01", "End": "2025-06-01" } }
      ]
    }
  }
}
- NewUI: simple on/off.
- BetaEndpoint: off by default.
- TimeLimitedFeature: auto‑enabled during a date range.
Wire Up Microsoft.FeatureManagement
In Program.cs, register feature management services:
using Microsoft.FeatureManagement;
var builder = WebApplication.CreateBuilder(args);
// Add feature management and built-in filters
builder.Services.AddFeatureManagement()
    .AddFeatureFilter<Microsoft.FeatureManagement.FeatureFilters.TimeWindowFilter>();
var app = builder.Build();
This reads FeatureManagement from configuration and enables the built‑in TimeWindowFilter.
Use Flags in Endpoints
You can check flags manually using IFeatureManagerSnapshot:
using Microsoft.FeatureManagement;
app.MapGet("/new-ui-data", async ([FromServices] IFeatureManagerSnapshot fm) =>
{
    if (!await fm.IsEnabledAsync("NewUI"))
        return Results.NotFound("New UI not available.");
    return Results.Ok(new { message = "Welcome to the new UI!" });
});
Above: manual check with IsEnabledAsync().
FeatureGate Attributes
For attribute-based gating, add [FeatureGate] on endpoints or controllers. This automatically returns 404 if the feature is disabled.
using Microsoft.FeatureManagement;
// Attribute on Minimal API endpoint
app.MapGet("/beta-attr", () => "Beta data via attribute")
   .RequireFeature("BetaEndpoint");
// In MVC controller
[ApiController]
[Route("api/[controller]")]
public class ReportsController : ControllerBase
{
    [HttpGet("special")]
    [FeatureGate("TimeLimitedFeature")]
    public IActionResult GetTimeLimitedReport()
    {
        return Ok("Time-limited report data");
    }
}
- 
.RequireFeature("BetaEndpoint")for Minimal APIs
- 
[FeatureGate("TimeLimitedFeature")]for controllers
Custom Feature Provider
Implement IFeatureDefinitionProvider to fetch flags from an external service.
// Infrastructure/ExternalFeatureProvider.cs
using Microsoft.FeatureManagement;
using Microsoft.FeatureManagement.FeatureDefinitions;
public class ExternalFeatureProvider : IFeatureDefinitionProvider
{
    private readonly IExternalFlagRepository _repo;
    public ExternalFeatureProvider(IExternalFlagRepository repo) => _repo = repo;
    public async Task<FeatureDefinition> GetFeatureDefinitionAsync(string featureName)
    {
        var flag = await _repo.FetchFlagAsync(featureName);
        return new FeatureDefinition(
            name: featureName,
            enabledFor: flag.Enabled 
                ? new[] { new FeatureFilterConfiguration("AlwaysOn") } 
                : Array.Empty<FeatureFilterConfiguration>());
    }
    public async Task<IEnumerable<FeatureDefinition>> GetAllFeatureDefinitionsAsync()
    {
        var flags = await _repo.FetchAllFlagsAsync();
        return flags.Select(f => new FeatureDefinition(
            f.Name,
            f.Enabled ? new[] { new FeatureFilterConfiguration("AlwaysOn") } : Array.Empty<FeatureFilterConfiguration>()));
    }
}
// Infrastructure/ExternalFlagRepository.cs
public interface IExternalFlagRepository
{
    Task<FlagDto> FetchFlagAsync(string name);
    Task<IEnumerable<FlagDto>> FetchAllFlagsAsync();
}
public class InMemoryExternalFlagRepo : IExternalFlagRepository
{
    private readonly Dictionary<string,bool> _store = new() { ["NewUI"] = true, ["BetaEndpoint"] = false };
    public Task<FlagDto> FetchFlagAsync(string name) =>
        Task.FromResult(new FlagDto { Name = name, Enabled = _store.GetValueOrDefault(name) });
    public Task<IEnumerable<FlagDto>> FetchAllFlagsAsync() =>
        Task.FromResult(_store.Select(kv => new FlagDto { Name = kv.Key, Enabled = kv.Value }));
}
public record FlagDto { public string Name { get; init; } public bool Enabled { get; init; } }
Register in Program.cs:
builder.Services.AddSingleton<IExternalFlagRepository, InMemoryExternalFlagRepo>();
builder.Services.AddSingleton<IFeatureDefinitionProvider, ExternalFeatureProvider>();
Testing
- 
Unit test attribute endpoints by mocking IFeatureManagerSnapshot.
- 
Integration test custom provider by seeding InMemoryExternalFlagRepo.
Example xUnit test for manual check:
[Fact]
public async Task NewUI_ReturnsNotFound_WhenFlagOff()
{
    var fm = new Mock<IFeatureManagerSnapshot>();
    fm.Setup(x => x.IsEnabledAsync("NewUI", It.IsAny<CancellationToken>())).ReturnsAsync(false);
    var result = await new UIEndpoint(fm.Object).Get();
    Assert.IsType<NotFoundObjectResult>(result);
}
Feature flags give you the serenity to release often and safely. Stay Zen.
References
- Official docs: https://learn.microsoft.com/en-gb/azure/azure-app-configuration/feature-management-dotnet-reference
- GitHub repo: https://github.com/microsoft/FeatureManagement-Dotnet
🧘♂️ Like this kind of content?
Follow my dev blog → ZenOfCode
Or drop me a follow here on Dev.to 💬
 
 
              
 
    
Top comments (0)