Preventing Inconsistent Feature Flag Values During a Single Request (Microsoft.FeatureManagement)

This is part six in a series of articles.

EDIT: my Feature Management Pluralsight training course is now available.

If you check a feature flag multiple times during a single HTTP request in ASP.NET Core, the feature can return a different results for each check.

For example, the Microsoft.Percentage feature filter which we looked at in part three enables a feature for a specified percentage of feature checks:

"FeatureManagement": {
  "Printing": {
    "EnabledFor": [
      {
        "Name": "Microsoft.Percentage",
        "Parameters": {
          "Value": 50
        }
      }
    ]
  }
}

If, within a single HTTP request, the printing feature is queried you will get different results. The following is a simple demo of this:

public async Task<IActionResult> Index()
{
    CheckPrintingFeature();
    CheckPrintingFeature();
    CheckPrintingFeature();

    return View();            

    async void CheckPrintingFeature()
    {
        if (await _featureManager.IsEnabledAsync(nameof(Features.Printing)))
        {
            ViewData["PrintMessage"] += "On, ";
        }
        else
        {
            ViewData["PrintMessage"] += "Off, ";
        }
    }
}

If we run the web app, the ViewData could be set to “Off, Off, On,” for example. This means if you are controlling which version of an algorithm gets used based on a feature flag and you are doing this in multiple places within a single HTTP request you may get different versions of the algorithm used, which is probably not what you want. This behaviour is not limited to the Percentage feature filter.

Using Feature Flag Snapshots During a Single Request

Luckily the FeatureManagement team has thought of this and provides an alternative in the form of the IFeatureManagerSnapshot interface. This interface represents a “a snapshot of feature state to ensure consistency across a given request” [Microsoft]. This means that within a single request, the first time a feature is checked, the result will be remembered for all subsequent checks within that HTTP request.

To use this, instead of injecting an IFeatureManager into a controller, you can instead inject an IFeatureManagerSnapshot:

private IFeatureManagerSnapshot _featureManager;

public HomeController(IFeatureManagerSnapshot featureManager)
{
    _featureManager = featureManager;
}

If you run the app now, you’ll get a message of either “Off, Off, Off,” or “On, On, On,”, you won’t get mixed results within a single request. You may still get different results across multiple requests, even for the same user/session. In a future post we’ll look at preserving values across requests.

Interestingly the <feature> tag helper internally uses IFeatureManagerSnapshot – this means that if you are controlling UI elements with the tag helper then you will get consistent results within a single request, for example:

<ul>
    <feature name="Printing">
        <li>Tag helper check 1</li>
    </feature>
    <feature name="Printing">
        <li>Tag helper check 2</li>
    </feature>
    <feature name="Printing">
        <li>Tag helper check 3</li>
    </feature>
    <feature name="Printing">
        <li>Tag helper check 4</li>
    </feature>
    <feature name="Printing">
        <li>Tag helper check 5</li>
    </feature>
    <feature name="Printing">
        <li>Tag helper check 6</li>
    </feature>
    <feature name="Printing">
        <li>Tag helper check 7</li>
    </feature>
</ul>

The above will either show all <li>s or none at all.

Be sure to check out my Microsoft Feature Management Pluralsight course get started watching with a free trial.

SHARE:

Pingbacks and trackbacks (1)+

Add comment

Loading