# Feature Flags in .NET and How I Use Them for A/B Testing

> Feature flags let you wrap a feature in a conditional statement and toggle it on or off at runtime, without redeploying the code. I'll cover the Microsoft.FeatureManagement library, feature filters and phased rollouts, trunk-based development, and how I use flags for A/B testing.

Published: 2023-09-16. Author: Milan Jovanović.

Canonical: https://milanjovanovic.tech/blog/feature-flags-in-dotnet-and-how-i-use-them-for-ab-testing

Feature flags let you turn application features on or off at runtime without redeploying the code.
In .NET you get them from the `Microsoft.FeatureManagement` library, which builds on the configuration system and exposes flag state through `IFeatureManager`.
Percentage and targeting filters turn that switch into phased rollouts and A/B tests.

The ability to conditionally turn features on or off in your application without redeploying the code is a powerful tool.

It lets you quickly iterate on new features and frequently integrate your changes with the main branch.

You can use **feature flags** to achieve this.

**Feature flags** are a software development technique that allows you to wrap application features in a conditional statement.
You can then toggle the feature on or off in runtime to control which features are enabled.

We have a lot to cover in this week's newsletter:

- Feature flag fundamentals in .NET
- Feature filters and phased rollouts
- Trunk-based development
- A/B testing

Let's dive in!

## Feature Flags In .NET

[Feature flags](https://github.com/microsoft/FeatureManagement-Dotnet) provide a way for .NET and ASP.NET Core applications to turn features on or off dynamically.

To get started, you need to install the `Microsoft.FeatureManagement` library in your project:

```powershell
Install-Package Microsoft.FeatureManagement
```

This library will allow you to develop and expose application functionality based on features.
It's useful when you have special requirements when a new feature should be enabled and under what conditions.

The next step is to register the required services with dependency injection by calling `AddFeatureManagement`:

```csharp
builder.Services.AddFeatureManagement();
```

And you are ready to create your first feature flag.
Feature flags are built on top of the .NET configuration system.
Any .NET configuration provider can act as the backbone for exposing feature flags.

Let's create a feature flag called `ClipArticleContent` in our `appsettings.json` file:

```json
"FeatureManagement": {
  "ClipArticleContent": false
}
```

By convention, feature flags have to be defined in the `FeatureManagement` configuration section.
But you can change this by providing a different configuration section when calling `AddFeatureManagement`.

Microsoft recommends exposing feature flags using enums and then consuming them with the `nameof` operator.
For example, you would write `nameof(FeatureFlags.ClipArticleContent)`.

However, I prefer defining feature flags as constants in a static class because it simplifies the usage.

```csharp
// Using enums
public enum FeatureFlags
{
    ClipArticleContent = 1
}

// Using constants
public static class FeatureFlags
{
    public const string ClipArticleContent = "ClipArticleContent";
}
```

To check the feature flag state, you can use the `IFeatureManager` service.
In this example, if the `ClipArticleContent` feature flag is turned on, we will return only the first thirty characters of the article's content.

```csharp {8}
app.MapGet("articles/{id}", async (
    Guid id,
    IGetArticle query,
    IFeatureManager featureManager) =>
{
    var article = query.Execute(id);

    if (await featureManager.IsEnabledAsync(FeatureFlags.ClipArticleContent))
    {
        article.Content = article.Content.Substring(0, 50);
    }

    return Results.Ok(article);
});
```

You can also apply feature flags on a controller or endpoint level using the `FeatureGate` attribute:

```csharp
[FeatureGate(FeatureFlags.EnableArticlesApi)]
public class ArticlesController : Controller
{
   // ...
}
```

This covers the fundamentals of using feature flags, and now, let's tackle more advanced topics.

## Feature Filters And Phased Rollouts

The feature flags I showed you in the previous section were like a simple on-off switch.
Although practical, you might want more flexibility from your feature flags.

The `Microsoft.FeatureManagement` package comes with a few built-in feature filters that allow you to create dynamic rules for enabling feature flags.

The available feature filters are
[`Microsoft.Percentage`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.featuremanagement.featurefilters.percentagefilter?view=azure-dotnet),
[`Microsoft.TimeWindow`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.featuremanagement.featurefilters.timewindowfilter?view=azure-dotnet)
and [`Microsoft.Targeting`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.featuremanagement.featurefilters.targetingfilter?view=azure-dotnet).

Here's an example of defining a `ShowArticlePreview` feature flag that uses a percentage filter:

```json {3,6}
"FeatureFlags": {
  "ClipArticleContent": false,
  "ShowArticlePreview": {
    "EnabledFor": [
      {
        "Name": "Percentage",
        "Parameters": {
          "Value": 50
        }
      }
    ]
  }
}
```

This means the feature flag will be randomly turned on 50% of the time.
The downside is the same user might see different behavior on subsequent requests.
A more realistic scenario is to have the feature flag state be cached for the duration of the user's session.

To use the `PercentageFilter`, you need to enable it by calling `AddFeatureFilter`:

```csharp
builder.Services.AddFeatureManagement().AddFeatureFilter<PercentageFilter>();
```

Another interesting feature filter is the `TargetingFilter`, which allows you to target specific users.
Targeting is used in phased rollouts, where you want to introduce a new feature to your users gradually.
You start by enabling the feature for a small percentage of users and slowly increase the rollout percentage while monitoring how the system responds.

## Trunk-based Development and Feature Flags

[Trunk-based development](https://trunkbaseddevelopment.com/) is a Git branching strategy where all developers work in short-lived branches or directly in the trunk, the main codebase.
The _"trunk"_ is the main branch of your repository.
If you're using Git, it will be either the `main` or `master` branch.
Trunk-based development avoids the "merge hell" problem caused by long-lived branches.

So, how do feature flags fit into trunk-based development?

The only way to ensure the trunk is always releasable is to hide incomplete features behind feature flags.
You continue pushing changes to the trunk as you work on the feature while the feature flag remains turned off on the main branch.
When the feature is complete, you turn on the feature flag and release it to production.

![Trunk based development.](https://milanjovanovic.tech/blogs/mnw_055/trunk_based_development.png)

## How I Used Feature Flags for A/B Testing On My Website

A/B testing (split testing) is an experiment where two or more variants of a page (or feature) are shown randomly to users.
Statistical analysis is performed in the background to determine which variation performs better for a given conversion goal.

Here's an example A/B test I performed on my website:

![Split test with two variants.](https://milanjovanovic.tech/blogs/mnw_055/split_test.png)

The hypothesis was that removing the image and focusing on the benefits would make more people want to subscribe.
I measure this using the conversion rate, which is the number of people visiting the page divided by the number of people subscribing.

I'm using a platform called [Posthog](https://posthog.com) to run experiments, which automatically calculates the results.

You can see that the _test_ variant has a significantly higher conversion rate, so it becomes the winner of the A/B test.

![Split test with two variants experiment results.](https://milanjovanovic.tech/blogs/mnw_055/experiment_results.png)

## Takeaway

The ability to dynamically turn features on or off without deploying the code is like a superpower.
Feature flags give you this ability with very little work.

You can work with feature flags in .NET by installing the `Microsoft.FeatureManagement` library.
Feature flags build on top of the .NET configuration system, and you can check the feature flag state using the `IFeatureManager` service.

Another use case for feature flags is A/B testing.
I run weekly experiments on my website, testing changes that will improve my conversion rate.
Feature flags help me decide which version of the website to show to the user.
And then, I can measure results based on the user's actions.

I also made a video about [**feature flagging in .NET,**](https://youtu.be/QVEUgIC7Wpo) and you can watch it [**here**](https://youtu.be/QVEUgIC7Wpo) if you want to learn more.

Hope this was valuable.

Stay awesome!

---

## Frequently asked questions

### What are feature flags in .NET?

Feature flags let you wrap application features in a conditional statement and toggle them on or off at runtime without redeploying code. In .NET you use the Microsoft.FeatureManagement library, which builds on top of the .NET configuration system.

### How do I create a feature flag in ASP.NET Core?

Install Microsoft.FeatureManagement, call AddFeatureManagement to register the services, and define the flag in the FeatureManagement section of appsettings.json. Check its state with IFeatureManager.IsEnabledAsync, or gate a whole controller or endpoint with the FeatureGate attribute.

### What are feature filters in Microsoft.FeatureManagement?

Feature filters add dynamic rules for enabling flags instead of a simple on-off switch. The built-in filters are Percentage, TimeWindow, and Targeting. The TargetingFilter supports phased rollouts, where you enable a feature for a small percentage of users and gradually increase it.

### How do feature flags support trunk-based development?

Trunk-based development keeps everyone working in short-lived branches or directly on the main branch. Hiding incomplete features behind feature flags is the only way to keep the trunk always releasable: you push changes with the flag off and turn it on when the feature is complete.

### Can I use feature flags for A/B testing?

Yes. Feature flags decide which variant of a page or feature each user sees, and you measure results based on user actions. Statistical analysis of a conversion goal, such as subscription rate, determines the winning variant. Platforms like Posthog calculate the results automatically.
