---
title: .NET feature flag management
titleSuffix: Azure App Configuration
description: Learn to implement feature flags in your .NET and ASP.NET Core applications using feature management and Azure App Configuration. Dynamically manage feature rollouts, conduct A/B testing, and control feature visibility without redeploying the app.
services: azure-app-configuration
author: rossgrambo
ms.author: rossgrambo
ms.service: azure-app-configuration
ms.devlang: csharp
ms.custom: devx-track-dotnet
ms.topic: tutorial
ms.date: 01/07/2024
#Customer intent: I want to control feature availability in my app by using the Feature Management library.
---
# .NET Feature Management
[](https://www.nuget.org/packages/Microsoft.FeatureManagement)
[](https://www.nuget.org/packages/Microsoft.FeatureManagement.AspNetCore)
[](https://www.nuget.org/packages/Microsoft.FeatureManagement.Telemetry.ApplicationInsights)
.NET feature management library provides a way to develop and expose application functionality based on feature flags. Once a new feature is developed, many applications have special requirements, such as when the feature should be enabled and under what conditions. This library provides a way to define these relationships, and also integrates into common .NET code patterns to make exposing these features possible.
Feature flags provide a way for .NET and ASP.NET Core applications to turn features on or off dynamically. Developers can use feature flags in simple use cases like conditional statements to more advanced scenarios like conditionally adding routes or MVC filters. Feature flags are built on top of the .NET Core configuration system. Any .NET Core configuration provider is capable of acting as the backbone for feature flags.
Here are some of the benefits of using .NET feature management library:
* A common convention for feature management
* Low barrier-to-entry
* Built on `IConfiguration`
* Supports JSON file feature flag setup
* Feature Flag lifetime management
* Configuration values can change in real-time; feature flags can be consistent across the entire request
* Simple to Complex Scenarios Covered
* Toggle on/off features through declarative configuration file
* Surface different variants of a feature to different users
* Dynamically evaluate state of feature based on call to server
* API extensions for ASP.NET Core and MVC framework
* Routing
* Filters
* Action Attributes
The .NET feature management library is open source. For more information, visit the [GitHub repo](https://github.com/microsoft/FeatureManagement-Dotnet).
## Feature Flags
Feature flags can be either enabled or disabled. The state of a flag can be made conditional through the use of feature filters.
### Feature Filters
Feature filters define a scenario for when a feature should be enabled. When a feature is evaluated as on or off, its list of feature filters are traversed until one of the filters determines the feature is enabled. At this point, traversal through the feature filters stops. If no feature filter indicates that the feature should be enabled, it is considered disabled.
As an example, a Microsoft Edge browser feature filter could be designed. This feature filter would activate any features it is attached to as long as an HTTP request is coming from Microsoft Edge.
### Feature Flag Configuration
The .NET Core configuration system is used to determine the state of feature flags. The foundation of this system is `IConfiguration`. Any provider for `IConfiguration` can be used as the feature state provider for the feature flag library. This system enables scenarios ranging from appsettings.json to Azure App Configuration and more.
### Feature Flag Declaration
The feature management library supports appsettings.json as a feature flag source since it's a provider for .NET Core's `IConfiguration` system. Feature flags are declared using the [`Microsoft Feature Management schema`](https://github.com/microsoft/FeatureManagement/blob/main/Schema/FeatureManagement.v2.0.0.schema.json). This schema is language agnostic in origin and is supported across all Microsoft feature management libraries.
The following example declares feature flags in a json file.
``` JavaScript
{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
// Define feature flags in a json file
"feature_management": {
"feature_flags": [
{
"id": "FeatureT",
"enabled": false
},
{
"id": "FeatureU",
"enabled": true,
"conditions": {}
},
{
"id": "FeatureV",
"enabled": true,
"conditions": {
"client_filters": [
{
"name": "Microsoft.TimeWindow",
"parameters": {
"Start": "Mon, 01 May 2023 13:59:59 GMT",
"End": "Sat, 01 July 2023 00:00:00 GMT"
}
}
]
}
}
]
}
}
```
The `feature_management` section of the json document is used by convention to load feature flag settings. Feature flag objects must be listed in the `feature_flags` array under the `feature_management` section. In the previous section, we see that we have provided three different features. A feature flag has `id` and `enabled` properties. The `id` is the name used to identify and reference the feature flag. The `enabled` property specifies the enabled state of the feature flag. A feature is *OFF* if `enabled` is false. If `enabled` is true, then the state of the feature depends on the `conditions`. If there are no `conditions`, then the feature is *ON*. If there are `conditions`, and they're met, then the feature is *ON*. If there are `conditions` and they aren't met then the feature is *OFF*. The `conditions` property declares the conditions used to dynamically enable the feature. Features define their feature filters in the `client_filters` array. `FeatureV` specifies a feature filter named `Microsoft.TimeWindow`. This filter is an example of a configurable feature filter. We can see in the example that the filter has a `Parameters` property. This property is used to configure the filter. In this case, the start and end times for the feature to be active are configured.
**Advanced:** The usage of colon ':' is forbidden in feature flag names.
#### Requirement type
The `requirement_type` property of `conditions` is used to determine if the filters should use `Any` or `All` logic when evaluating the state of a feature. If `requirement_type` isn't specified, the default value is `Any`.
* `Any` means only one filter needs to evaluate to true for the feature to be enabled.
* `All` means every filter needs to evaluate to true for the feature to be enabled.
A `requirement_type` of `All` changes the traversal. First, if there is no filter, the feature is disabled. If there are filters, then the feature filters are traversed until one of the filters decides that the feature should be disabled. If no filter indicates that the feature should be disabled, then it is considered enabled.
``` JavaScript
{
"id": "FeatureW",
"enabled": true,
"conditions": {
"requirement_type": "All",
"client_filters": [
{
"name": "Microsoft.TimeWindow",
"parameters": {
"Start": "Mon, 01 May 2023 13:59:59 GMT",
"End": "Sat, 01 Jul 2023 00:00:00 GMT"
}
},
{
"name": "Microsoft.Percentage",
"parameters": {
"Value": "50"
}
}
]
}
}
```
In this example, `FeatureW` specifies a `requirement_type` of `All`, meaning all of its filters must evaluate to true for the feature to be enabled. In this case, the feature is enabled for 50% of users during the specified time window.
### .NET Feature Management schema
In previous versions, the primary schema for the feature management library was the [`.NET feature management schema`](https://github.com/microsoft/FeatureManagement-Dotnet/blob/main/schemas/FeatureManagement.Dotnet.v1.0.0.schema.json). Starting from v4.0.0, new features including variants and telemetry are not supported for the .NET feature management schema.
> [!NOTE]
> If there is a feature flag declaration that can be found in both the `feature_management` and `FeatureManagement` sections, the one from the `feature_management` section will be adopted.
## Consumption
The basic form of feature management is checking if a feature flag is enabled and then performing actions based on the result. This check is done through the `IVariantFeatureManager`'s `IsEnabledAsync` method.
``` C#
…
IVariantFeatureManager featureManager;
…
if (await featureManager.IsEnabledAsync("FeatureX"))
{
// Do something
}
```
### Service Registration
Feature management relies on .NET Core dependency injection. We can register the feature management services using standard conventions.
``` C#
using Microsoft.FeatureManagement;
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddFeatureManagement();
}
}
```
By default, the feature manager retrieves feature flag configuration from the "FeatureManagement" section of the .NET Core configuration data. If the "FeatureManagement" section doesn't exist, the configuration is considered empty.
> [!NOTE]
> You can also specify that feature flag configuration should be retrieved from a different configuration section by passing the section to `AddFeatureManagement`. The following example tells the feature manager to read from a different section called "MyFeatureFlags" instead:
>
> ``` C#
> services.AddFeatureManagement(configuration.GetSection("MyFeatureFlags"));
> ```
### Dependency Injection
When using the feature management library with MVC, the `IVariantFeatureManager` can be obtained through dependency injection.
``` C#
public class HomeController : Controller
{
private readonly IVariantFeatureManager _featureManager;
public HomeController(IVariantFeatureManager featureManager)
{
_featureManager = featureManager;
}
}
```
### Scoped Feature Management Services
The `AddFeatureManagement` method adds feature management services as singletons within the application, but there are scenarios where it may be necessary for feature management services to be added as scoped services instead. For example, users may want to use feature filters that consume scoped services for context information. In this case, the `AddScopedFeatureManagement` method should be used instead. This method ensures that feature management services, including feature filters, are added as scoped services.
``` C#
services.AddScopedFeatureManagement();
```
## ASP.NET Core Integration
The feature management library provides functionality in ASP.NET Core and MVC to enable common feature flag scenarios in web applications. These capabilities are available by referencing the [Microsoft.FeatureManagement.AspNetCore](https://www.nuget.org/packages/Microsoft.FeatureManagement.AspNetCore/) NuGet package.
### Controllers and Actions
MVC controller and actions can require that a given feature, or one of any list of features, be enabled in order to execute. This requirement can be done by using a `FeatureGateAttribute`, which can be found in the `Microsoft.FeatureManagement.Mvc` namespace.
``` C#
[FeatureGate("FeatureX")]
public class HomeController : Controller
{
…
}
```
In this example, the `HomeController` is gated by "FeatureX". "FeatureX" must be enabled before any action the `HomeController` contains can be executed.
``` C#
[FeatureGate("FeatureX")]
public IActionResult Index()
{
return View();
}
```
In this example, the `Index` MVC action requires "FeatureX" to be enabled before it can be executed.
### Disabled Action Handling
When an MVC controller or action is blocked because none of the features it specifies are enabled, a registered `IDisabledFeaturesHandler` is invoked. By default, a minimalistic handler is registered which returns HTTP 404. This handler can be overridden using the `IFeatureManagementBuilder` when registering feature flags.
``` C#
public interface IDisabledFeaturesHandler
{
Task HandleDisabledFeature(IEnumerable features, ActionExecutingContext context);
}
```
### View
In MVC views `` tags can be used to conditionally render content based on whether a feature is enabled or whether specific variant of a feature is assigned. For more information, see the [variants](#variants) section.
``` HTML+Razor
This can only be seen if 'FeatureX' is enabled.
```
``` HTML+Razor
This can only be seen if variant 'Alpha' of 'FeatureX' is assigned.
```
You can also negate the tag helper evaluation to display content when a feature or set of features are disabled. By setting `negate="true"` in the following example, the content is only rendered if `FeatureX` is disabled.
``` HTML+Razor
This can only be seen if 'FeatureX' is disabled.
```
``` HTML+Razor
This can only be seen if variant 'Alpha' of 'FeatureX' isn't assigned.
```
The `` tag can reference multiple features/variants by specifying a comma separated list of features/variants in the `name`/`variant` attribute.
``` HTML+Razor
This can only be seen if 'FeatureX' and 'FeatureY' are enabled.
```
``` HTML+Razor
This can only be seen if variant 'Alpha' or 'Beta' of 'FeatureX' is assigned.
```
> [!NOTE]
> If `variant` is specified, only *one* feature should be specified.
By default, all listed features must be enabled for the feature tag to be rendered. This behavior can be overridden by adding the `requirement` attribute as seen in the following example.
> [!NOTE]
> If a `requirement` of `And` is used in conjunction with `variant` an error will be thrown, as multiple variants can never be assigned.
``` HTML+Razor
This can only be seen if either 'FeatureX' or 'FeatureY' or both are enabled.
```
The `` tag requires a tag helper to work. To use the tag, add the feature management tag helper to the _ViewImports.cshtml_ file.
``` HTML+Razor
@addTagHelper *, Microsoft.FeatureManagement.AspNetCore
```
### MVC Filters
MVC action filters can be set up to conditionally execute based on the state of a feature. This is done by registering MVC filters in a feature aware manner.
The feature management pipeline supports async MVC Action filters, which implement `IAsyncActionFilter`.
``` C#
services.AddMvc(o =>
{
o.Filters.AddForFeature("FeatureX");
});
```
This code adds an MVC filter named `SomeMvcFilter`. This filter is only triggered within the MVC pipeline if "FeatureX" is enabled.
### Razor Pages
MVC Razor pages can require that a given feature, or one of any list of features, be enabled in order to execute. This requirement can be added by using a `FeatureGateAttribute`, which can be found in the `Microsoft.FeatureManagement.Mvc` namespace.
``` C#
[FeatureGate("FeatureX")]
public class IndexModel : PageModel
{
public void OnGet()
{
}
}
```
The code above sets up a Razor page to require the "FeatureX" to be enabled. If the feature is not enabled, the page generates an HTTP 404 (NotFound) result.
When used on Razor pages, the `FeatureGateAttribute` must be placed on the page handler type. It can't be placed on individual handler methods.
### Application building
The feature management library can be used to add application branches and middleware that execute conditionally based on feature state.
``` C#
app.UseMiddlewareForFeature("FeatureX");
```
With the above call, the application adds a middleware component that only appears in the request pipeline if the feature "FeatureX" is enabled. If the feature is enabled/disabled during runtime, the middleware pipeline can be changed dynamically.
This builds off the more generic capability to branch the entire application based on a feature.
``` C#
app.UseForFeature(featureName, appBuilder =>
{
appBuilder.UseMiddleware();
});
```
## Implementing a Feature Filter
Creating a feature filter provides a way to enable features based on criteria that you define. To implement a feature filter, the `IFeatureFilter` interface must be implemented. `IFeatureFilter` has a single method named `EvaluateAsync`. When a feature specifies that it can be enabled for a feature filter, the `EvaluateAsync` method is called. If `EvaluateAsync` returns `true`, it means the feature should be enabled.
The following snippet demonstrates how to add a customized feature filter `MyCriteriaFilter`.
``` C#
services.AddFeatureManagement()
.AddFeatureFilter();
```
Feature filters are registered by calling `AddFeatureFilter` on the `IFeatureManagementBuilder` returned from `AddFeatureManagement`. These feature filters have access to the services that exist within the service collection that was used to add feature flags. Dependency injection can be used to retrieve these services.
> [!NOTE]
> When filters are referenced in feature flag settings (for example, appsettings.json), the _Filter_ part of the type name should be omitted. For more information, see the [`Filter Alias Attribute`](#filter-alias-attribute) section.
### Parameterized Feature Filters
Some feature filters require parameters to decide whether a feature should be turned on or not. For example, a browser feature filter may turn on a feature for a certain set of browsers. It may be desired that Edge and Chrome browsers enable a feature, while Firefox does not. To do this filtering, a feature filter can be designed to expect parameters. These parameters would be specified in the feature configuration, and in code would be accessible via the `FeatureFilterEvaluationContext` parameter of `IFeatureFilter.EvaluateAsync`.
``` C#
public class FeatureFilterEvaluationContext
{
///
/// The name of the feature being evaluated.
///
public string FeatureName { get; set; }
///
/// The settings provided for the feature filter to use when evaluating whether the feature should be enabled.
///
public IConfiguration Parameters { get; set; }
}
```
`FeatureFilterEvaluationContext` has a property named `Parameters`. These parameters represent a raw configuration that the feature filter can use to decide how to evaluate whether the feature should be enabled or not. To use the browser feature filter as an example once again, the filter could use `Parameters` to extract a set of allowed browsers that would be specified for the feature and then check if the request is being sent from one of those browsers.
``` C#
[FilterAlias("Browser")]
public class BrowserFilter : IFeatureFilter
{
…
public Task EvaluateAsync(FeatureFilterEvaluationContext context)
{
BrowserFilterSettings settings = context.Parameters.Get() ?? new BrowserFilterSettings();
//
// Here we would use the settings and see if the request was sent from any of BrowserFilterSettings.AllowedBrowsers
}
}
```
### Filter Alias Attribute
When a feature filter is registered for a feature flag, the alias used in configuration is the name of the feature filter type with the _Filter_ suffix, if any, removed. For example, `MyCriteriaFilter` would be referred to as _MyCriteria_ in configuration.
``` JavaScript
"MyFeature": {
"EnabledFor": [
{
"Name": "MyCriteria"
}
]
}
```
This name can be overridden by using the `FilterAliasAttribute`. A feature filter can be decorated with this attribute to declare the name that should be used in configuration to reference this feature filter within a feature flag.
### Missing Feature Filters
If a feature is configured to be enabled for a specific feature filter and that feature filter isn't registered, an exception is thrown when the feature is evaluated. The exception can be disabled by using the feature management options.
``` C#
services.Configure(options =>
{
options.IgnoreMissingFeatureFilters = true;
});
```
### Using HttpContext
Feature filters can evaluate whether a feature should be enabled based on the properties of an HTTP Request. This is performed by inspecting the HTTP Context. A feature filter can get a reference to the HTTP Context by obtaining an `IHttpContextAccessor` through dependency injection.
``` C#
public class BrowserFilter : IFeatureFilter
{
private readonly IHttpContextAccessor _httpContextAccessor;
public BrowserFilter(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
}
}
```
The `IHttpContextAccessor` must be added to the dependency injection container on startup for it to be available. It can be registered in the `IServiceCollection` using the following method.
``` C#
public void ConfigureServices(IServiceCollection services)
{
…
services.AddHttpContextAccessor();
…
}
```
**Advanced:** `IHttpContextAccessor`/`HttpContext` should not be used in the Razor components of server-side Blazor apps. [The recommended approach](/aspnet/core/blazor/security/server/interactive-server-side-rendering#ihttpcontextaccessorhttpcontext-in-razor-components) for passing http context in Blazor apps is to copy the data into a scoped service. For Blazor apps, `AddScopedFeatureManagement` should be used to register the feature management services. For more information, see the [`Scoped Feature Management Services`](#scoped-feature-management-services) section.
## Provide a Context For Feature Evaluation
In console applications, there's no ambient context such as `HttpContext` that feature filters can acquire and utilize to check if a feature should be on or off. In this case, applications need to provide an object representing a context into the feature management system for use by feature filters. This context can be given using `IVariantFeatureManager.IsEnabledAsync(string featureName, TContext appContext)`. The appContext object that is provided to the feature manager can be used by feature filters to evaluate the state of a feature.
``` C#
MyAppContext context = new MyAppContext
{
AccountId = current.Id;
}
if (await featureManager.IsEnabledAsync(feature, context))
{
…
}
```
### Contextual Feature Filters
Contextual feature filters implement the `IContextualFeatureFilter` interface. These special feature filters can take advantage of the context that is passed in when `IVariantFeatureManager.IsEnabledAsync` is called. The `TContext` type parameter in `IContextualFeatureFilter` describes what context type the filter is capable of handling. This allows the developer of a contextual feature filter to describe what is required for those who wish to utilize it. Since every type is a descendant of object, a filter that implements `IContextualFeatureFilter