Use ASP.NET Core feature management to toggle flags on & off

Published: Monday 5 August 2024

ASP.NET Core gives you the ability to toggle features and off with feature management.

This means that you can show certain features to certain users. This could be based on their location, the current date and time, or it could be totally random. The possibilities are endless!

C# coding challenges

C# coding challenges

Our online code editor allows you to compile the answer.

It's supported in ASP.NET Core applications and be used in controllers as well as MVC views.

The first step is to ensure that you install the Microsoft.FeatureManagement.AspNetCore NuGet package into your application. Afterwards, you can start to add features to the configuration through appsettings.json.

Add feature flags to ASP.NET Core

By default, the FeatureManagement key is used in appsettings.json to add features.

Each feature is a key/value pair where the key is the name of the feature and the value is either true or false, depending on whether the feature is enabled.

There is an exception to this rule if you use a filter. You can specify the EnabledFor key and specify the name of the filter. One of the built-in feature flag filters is Percentage where you can enable a feature for a particular percentage of users.

Here's an example of how it can look in appsettings.json. We have enabled the NewDesign feature, disabled the ShowOffer feature, and enabled the DiscountBanner feature to 20% of the users.

"FeatureManagement": {
  "NewDesign": true, 
  "ShowOffer": false, 
  "DiscountBanner": {
    "EnabledFor": [
      {
        "Name": "Percentage",
        "Parameters": {
          "Value": 20
        }
      }
    ]
  }  
}

To ensure that ASP.NET Core can read your feature flags, you need to add the AddFeatureManagement extension method in the IServiceCollection instance in Program.cs.

// Program.cs
builder.Services.AddFeatureManagement();

To change the name of the config key used in appsettings.json, you can specify the configuration section as a parameter in the AddFeatureManagement extension method.

In this example, we've changed it from FeatureManagement to Features.

"Features": {
  "NewDesign": true, 
  "ShowOffer": false, 
  "DiscountBanner": {
    "EnabledFor": [
      {
        "Name": "Percentage",
        "Parameters": {
          "Value": 20
        }
      }
    ]
  }  
}
// Program.cs
builder.Services.AddFeatureManagement(builder.Configuration.GetSection("Features"));

Use the feature manager in controllers

To use the feature manager in controllers, you need to inject the IFeatureManager instance into it.

From there, you can use the IsEnabledAsync method, passing in the feature flag name as the parameter.

For example, if you want to know if the NewDesign feature is enabled, you would add that into the parameter.

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

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

	[HttpGet]
	public async Task<IActionResult> Features()
	{
		return Ok(new
		{
			NewDesign = await _featureManager.IsEnabledAsync("NewDesign"),
			ShowOffer = await _featureManager.IsEnabledAsync("ShowOffer"),
			DiscountBanner = await _featureManager.IsEnabledAsync("DiscountBanner")
		});
	}
}

It can also be used in a controller as an attribute. By using the FeatureGateAttribute, the controller's endpoint will only be run if that particular feature is enabled.

If it's not, it will return a 404 not found error.

In this example, the ShowDiscountBanner is only invoked if the DiscountBanner feature is enabled.

// FeatureController.cs
public class FeatureController : ControllerBase
{
	[HttpGet("show-discount-banner"), FeatureGate("DiscountBanner")]
	public IActionResult ShowDiscountBanner()
	{
		return NoContent();
	}
}

Creating custom filters

You can write your own custom filter for feature management. To do that, you need to implement the IFeatureFilter interface and add a FilterAlias attribute to the class specifying the name.

The IFeatureFilter includes an EvaluateAsync method where you can return whether a feature is enabled or not. This method passes in a FeatureFilterEvaluationContext instance which gets parameters that can be set in appsettings.json.

In this instance, we've created a TimeOfDay filter where it's enabled if the time of day is greater than the value specified in the parameter.

// TimeOfDayFilter.cs
[FilterAlias("TimeOfDay")]
public class TimeOfDayFilter : IFeatureFilter
{
    public Task<bool> EvaluateAsync(FeatureFilterEvaluationContext context)
    {
        return Task.FromResult(DateTime.UtcNow.TimeOfDay >= context.Parameters.GetValue<TimeSpan>("Value"));
    }
}

The filter needs to be added to Program.cs to use it. This can be done by adding the AddFeatureFilter extension method, with the filter type as its generic type.

// Program.cs
builder.Services.AddFeatureManagement()
	.AddFeatureFilter<TimeOfDayFilter>();

We can set the parameter for a feature in appsettings.json. For this instance, the feature flag is called TimedBanner and it's enabled using the TimeOfDay filter when the Value parameter is 12:00 (UTC) or later.

{
  "FeatureManagement": {
    ...,
    "TimedBanner": {
      "EnabledFor": [
        {
          "Name": "TimeOfDay",
          "Parameters": {
            "Value": "12:00:00"
          }
        }
      ]
    }
  }
}

Use feature flags in MVC views

As well as controllers, feature flags can be used in MVC views.

To enable it, the @addTagHelper needs to be added to the view where you are using it. It can also be added to _ViewImports so it's used throughout the application.

@addTagHelper *, Microsoft.FeatureManagement.AspNetCore

From there, you can use the feature tag helper alongside the name of the feature flag as a parameter. Depending on whether the feature flag is enabled depends on whether the content inside the feature tag helper is shown.

You can also use the negate parameter to show content if the feature flag is disabled.

<!-- Index.cshtml -->
<feature name="DiscountBanner">
    <p>Show the banner.</p>
</feature>
<feature name="DiscountBanner" negate="true">
    <p>Don't show the banner.</p>
</feature>

There is also the option to specify multiple feature flags in the name parameter. For this, the requirement parameter can be set with either All or Any.

If set to Any, any of the feature flags can be enabled to show the content. If it's set to All, all feature flags have to be enabled for the content to display.

<!-- Index.cshtml -->
<feature name="NewDesign, DiscountBanner" requirement="All">
    <p>Show the new design and discount banner.</p>
</feature>
<feature name="NewDesign, DiscountBanner" requirement="Any">
    <p>Show any of the new design or discount banner.</p>
</feature>

Watch the video

Watch our video where we add feature management to an ASP.NET Core application, and show you how to add it to controllers and views.

We'll also demonstrate feature flags working by running the application and showing what happens when the features are enabled and disabled.