Vincent Costel

Simple Feature Toggles for Asp.Net Core

Feature toggles are a technique allowing enabling or disabling features without changing or deploying code.

One of the use I'm interested in, is the ability to decouple code deployment from feature delivery.
Dormant features can be deployed to QA or production environments but they are not enabled until they are considered ready for prime time.

Here we have a fictitious application that let you post messages 280 characters at a time. We can take advantage of the fact that Dependency Injection (DI) is everywhere in Asp.Net Core, even in Razor views, to inject individual IFeatureToggle<TFeature> interfaces where we want to test for feature availability.

  public interface IFeatureToggle
{
bool FeatureEnabled { get; }
}

public interface IFeatureToggle<TFeature>: IFeatureToggle
where TFeature : class
{ }
  @* Example of a feature toggle injected in a Razor view *@
@inject IFeatureToggle<CharacterLimit280> CharacterLimit280

@if (CharacterLimit280.FeatureEnabled)
{
<p>You can write up to 280 characters!</p>
}
  /* Example of a feature toggle injected in a Controller  */
public class PostingController
{
readonly IFeatureToggle _posting
public PostingController(IFeatureToggle<Posting> posting)
{
_posting = posting;
}

[HttpGet]
public IActionResult Index()
{
if(!_posting.FeatureEnabled)
{
return Forbid();
}
return View();
}
}

Each "feature" is just an empty class.

  public class Posting { }
public class CharacterLimit280 { }

The DI container supports open generic registrations so we can leverage this with the IFeatureToggle<TFeature> interface and its implementation.

  // In Startup.cs
services.AddSingleton(typeof(IFeatureToggle<>), typeof(ConfigurationFeatureToggle<>));

The ConfigurationFeatureToggle<TFeature> implementation class simply reads a Configuration section to determine which features are enabled. By using appsettings.[env].json files we can have separate configurations for each environment.

  {  
"FeatureToggle": {
"Posting": true,
"CharacterLimit280": false
}
}
public class ConfigurationFeatureToggle<TFeature> : IFeatureToggle<TFeature>
where TFeature : class
{
readonly IConfiguration _configuration;

public ConfigurationFeatureToggle(IConfigurationRoot configuration)
{
_configuration = configuration.GetSection("FeatureToggle");
}

public bool FeatureEnabled => _configuration.GetValue<bool>(typeof(TFeature).Name);
}

That's it! It's pretty basic but good enough for my needs at the moment.
These toggles are usually short lived. They are not intended to be left in the code indefinitely and they can be removed shortly after the features are enabled in production.