Introducing the Microsoft.FeatureManagement library

Use Microsoft.FeatureManagement to add native feature flags!

Dave Brock
Dave Brock

A couple of weeks ago, I needed to find a way to better manage new functionality for a feature that was not ready yet (it broke stuff). We didn’t know exactly when the feature would be shipped, but we also didn’t want to deal with branch and merging headaches when the moment came.

My first thought: this was a perfect candidate for feature flags (or feature toggles). This allows you to merge code into a production branch, but only enable when ready. Instead of waiting for developers to be ready, you’re waiting for the end user to be ready.

Instead of writing this logic and having to deal with the corner case headaches, I knew Microsoft shipped a Microsoft.FeatureManagement library.

Unfortunately, that was all I knew and took this as a great opportunity to dig deeper. I learned a ton and will be dividing my new-found knowledge into four blog posts over the next several weeks.

I’ll be writing a few posts on this topic:

Create sample application and add NuGet packages

For this post, I’ll be using an ASP.NET Core Web Application with the traditional Model-View-Controller scaffolding. If you want to code along with me, make sure to create a new project. You can do this from the Visual Studio UI, or if VS Code is your style, the dotnet CLI by executing dotnet new mvc. Once you create your project, you’ll need to install Microsoft.FeatureManagement. You can do this in one of two ways:

  • From the NuGet Package Manager (easiest way is to right-click your solution in Visual Studio, then clicking Manage NuGet Packages)
  • From the dotnet CLI, you can execute the dotnet add package Microsoft.FeatureManagement command

(While we are using an ASP.NET Core application, the library depends on .NET Standard 2.0—so even non-.NET Core applications can benefit.)

Once the package is installed, update the dependency injection in Startup.cs to the following:

using Microsoft.FeatureManagement;
public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
    services.AddFeatureManagement();
}

You’re now ready to get this party started!

A simple example

To get the gist of feature flags, we can just update the default message for the app that ships with the default ASP.NET Core scaffolding. Out of the box, the message says, Welcome. Let’s change it so that the message says Welcome to Feature Flags when the functionality is enabled. The Microsoft.FeatureManagement library will check your appsettings.json file for its configuration. By default, it will look for a FeatureManagement section. Let’s add an entry now.

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "FeatureManagement": {
    "WelcomeText": false
  },
  "AllowedHosts": "*"
}

In your Models folder, create an IndexViewModel.cs file and include the Message property.

public class IndexViewModel
{
    public string Message { get; set; }
}

Then, in Views/Home/Index.cshtml, update the file to this:

@model IndexViewModel
@{
    ViewData["Title"] = "Home Page";
}
<div class="text-center">
    <h1 class="display-4">@Model.Message</h1>
    <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>

Here, we are including the model we created, and rendering its Message property. We will soon introduce logic to populate the message with a certain value, whether feature flags are enabled in our application. Next, let’s open up HomeController.cs and implement the IFeatureManager service by injecting it into the constructor.

public class HomeController : Controller
{
    private readonly IFeatureManager _featureManager;
    public HomeController(IFeatureManager featureManager)
    {
        _featureManager = featureManager;
    }
    // stuff we'll include soon
}

The IFeatureManager interface looks like this:

public interface IFeatureManager
{
    IAsyncEnumerable<string> GetFeatureNamesAsync();
    Task<bool> IsEnabledAsync(string feature);
    Task<bool> IsEnabledAsync<TContext>(string feature, TContext context);
}

We’ll use IsEnabledAsync to check for the feature we specified in appsettings.json. We could pass the string directly, but a better way would be to add a class to store these strings. To do that, create a file in the root of the project called FeatureFlags.cs.

public static class FeatureFlags
{
    public const string WelcomeMessage = "Welcome Message";
}

There, I feel better. Back to HomeController.cs, change the Index action method to the following:

public async Task<IActionResult> Index()
{
    var indexViewModel = new IndexViewModel()
    {
        Message = await _featureManager.IsEnabledAsync("WelcomeMessage")
                  ? "Welcome to the feature flag"
                  : "Welcome"
    };
    return View(indexViewModel);
}

In the Index view action, we are calling IsEnabledAsync and passing in our flag’s name from the appsettings.json file. If that value is true the Message will display Welcome to the feature flag and if not, Welcome. The complexity you deal with every day, right? If you run your app, you just see the standard welcome message, because your feature flag is set to false in your configuration.

Before turning on flag

Now, if you go to your appsettings.json file and set WelcomeText to true and restart the page, you’ll see the feature flag in action! (You only have to restart the page, and not the app, as the configuration provider handles the change without an app restart!)

After turning on flag

When thinking in terms of deployment, you can set release variables and whatnot to better manage when to turn these on. We will discuss these when we talk about integrating with Azure.

CSharpFeature FlagsASP.NET Core