Feature flags also referred to as Feature Toggles are a powerful way to modify applications behavior without making any changes in the code. It allows features to be turned on and off dynamically.
In this tutorial, we are going to look at the below,
- Feature Management Library in .NET
- How can we use Feature Management Library in ASP.NET Core applications
- How to add a simple Boolean feature flag.
- Advanced Feature Flag filters.
- Custom Feature Flag Filter.
Feature Management Library
The .NET Core Feature Management Library extends the framework with comprehensive feature flag support. These libraries are built on top of the .NET Core Configuration system. Any .NET Core configuration provider can act as a backbone for feature flags.
The definition which I copied from GitHub.
“The Microsoft.FeatureManagement library enables developers to use feature flags and dynamic features inside of their applications. Feature flags can be used to turn features on or off dynamically. Developers can use feature flags in simple use cases like conditional statements to more advanced scenarios like conditionally adding routes or MVC filters. Dynamic features can be used to select different variants of a feature's configuration. This enables the possibility of using one version of a feature for one set of users, and another version of the feature for the remaining users”
Use Feature Management Library in ASP.NET Core
The tools which I have used for this tutorial are below
- VS 2022 Community Edition Preview Version 17.4 - Preview 2.0
- .NET 6.0
- Web API
- Swagger
The source code can be downloaded from this GitHub
Without any further delay, let us create an ASP.NET Core API project. Then add the below package from the NuGet.
Microsoft.FeatureManagement.AspNetCore
Add a simple Boolean Feature Flag
As we have successfully installed the NuGet package, let us go ahead and Feature flag into the Controller “WeatherForecastController”
To add the Feature flag, we need to inject an interface called “IFeatureManager”. This interface belongs to the NuGet package “Microsoft.FeatureManagement.AspNetCore”
The WeatherForecastController constructor would be looks like below
private readonly IFeatureManager _featureManager;
public WeatherForecastController(ILogger < WeatherForecastController > logger, IFeatureManager featureManager) {
_logger = logger;
this._featureManager = featureManager;
}
Now, we are going to add the Feature flag in the endpoint method –“GetWeatherForecast”
By default, this method returns list of WeatherForecast with properties Date, TemperatureC, and Summary. The GetWeatherForecast method given below
[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable < WeatherForecast > Get() {
return Enumerable.Range(1, 5).Select(index => new WeatherForecast {
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
}).ToArray();
}
Let us go ahead and add a new feature called “TemperatureF” into the Model – “WeatherForecast”
public class WeatherForecast {
public DateTime Date {
get;
set;
}
public int TemperatureC {
get;
set;
}
public string ? Summary {
get;
set;
}
//New Feature
public int TemperatureF {
get;
set;
}
}
While building this feature, we need to feature flag this new property as we are not sure when this is going to be deployed into production. So, we need to provide an ability to on and off this feature as we develop it. Let us start using the Feature Manager to determine this.
The updated GetWeatherForecast endpoint method is given below
[HttpGet(Name = "GetWeatherForecast")]
public async Task < IEnumerable < WeatherForecast >> Get() {
//Feature Flag - this needs to be configure in AppSettings.json
var isTemperatureFEnabled = await _featureManager.IsEnabledAsync("TemperatureF");
return Enumerable.Range(1, 5).Select(index => new WeatherForecast {
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
//check whether the Feature Flag is enabled
TemperatureF = isTemperatureFEnabled ? (int)(Random.Shared.Next(-20, 55) * 1.8) + 32 : null,
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
}).ToArray();
}
Now we need to configure this Feature flag in any of the configuration source. In this tutorial, we are going to configure in AppSettings.json
"FeatureManagement": {
"TemperatureF": true
}
The next step – we need to register the IFeatureManagement interface into dependency container. Now let us go to Program.cs and add the below line of code
builder.Services.AddFeatureManagement();
We have completed the configuration. Let us go ahead and execute the Endpoint GetWeatherForecast, we will get the below response
[{
"date": "2022-09-17T23:08:43.4688307-04:00",
"temperatureC": 25,
"summary": "Balmy",
"temperatureF": 37
}, {
"date": "2022-09-18T23:08:43.4693542-04:00",
"temperatureC": 44,
"summary": "Warm",
"temperatureF": 44
}, {
"date": "2022-09-19T23:08:43.4693578-04:00",
"temperatureC": -14,
"summary": "Mild",
"temperatureF": 91
}
We can see that the new Feature “TemparatureF” has been returned.
Now let us go to disable this feature in AppSettings.json and execute the endpoint
"FeatureManagement": {
"TemperatureF": false
}
Now execute the endpoint and look at the response.
[{
"date": "2022-09-17T23:11:51.823846-04:00",
"temperatureC": -17,
"summary": "Hot",
"temperatureF": null
}, {
"date": "2022-09-18T23:11:51.8238573-04:00",
"temperatureC": 28,
"summary": "Chilly",
"temperatureF": null
}, {
"date": "2022-09-19T23:11:51.8238577-04:00",
"temperatureC": 29,
"summary": "Freezing",
"temperatureF": null
}
The TemperatureF has been displayed with “null” value. This property can be turned off altogether when it is null. To do that, go to Startup.cs and add the below lines of code.
//Ignore Null Values
builder.Services.AddControllers().AddJsonOptions(option => {
option.JsonSerializerOptions.DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull;
});
Now, let us go ahead and execute the code and see what the response would be.
[{
"date": "2022-09-17T23:21:36.5978036-04:00",
"temperatureC": 20,
"summary": "Chilly"
}, {
"date": "2022-09-18T23:21:36.5981674-04:00",
"temperatureC": 19,
"summary": "Freezing"
}, {
"date": "2022-09-19T23:21:36.5981699-04:00",
"temperatureC": -19,
"summary": "Bracing"
}
TemperatureF property is not visible
Feature Flag Filters
Let us go ahead and add a new endpoint as below
[HttpGet("newfeature")]
public async Task < IEnumerable < WeatherForecast >> GetNewEndPoint() {
//Feature Flag - this needs to be configure in AppSettings.json
var isTemperatureFEnabled = await _featureManager.IsEnabledAsync("TemperatureF");
return Enumerable.Range(1, 5).Select(index => new WeatherForecast {
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
//check whether the Feature Flag is enabled
TemperatureF = isTemperatureFEnabled ? (int)(Random.Shared.Next(-20, 55) * 1.8) + 32 : null,
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
}).ToArray();
}
We are going to add feature flag to this method. Let us see how this can be achieved. Rather than we do an event check insider the method, we can simply add the below attribute at the method level to flag this method as a feature.
[FeatureGate("NewFeature")] – here “NewFeature” is the value of the feature flag
This attribute belongs to the namespace – “Microsoft.FeatureManagement.Mvc”
The updated method looks like below,
[HttpGet("newfeature")]
[FeatureGate("NewFeature")]
public async Task < IEnumerable < WeatherForecast >> GetNewFeature() {
//Feature Flag - this needs to be configure in AppSettings.json
var isTemperatureFEnabled = await _featureManager.IsEnabledAsync("TemperatureF");
return Enumerable.Range(1, 5).Select(index => new WeatherForecast {
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
//check whether the Feature Flag is enabled
TemperatureF = isTemperatureFEnabled ? (int)(Random.Shared.Next(-20, 55) * 1.8) + 32 : null,
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
}).ToArray();
}
Now, let us go ahead and add this feature flag in AppSettings.json
"FeatureManagement": {
"TemperatureF": false,
"NewFeature": true
}
Let us go ahead and execute the endpoint
WeatherForecast/newfeature
[{
"date": "2022-09-19T00:19:43.2623594-04:00",
"temperatureC": 1,
"summary": "Freezing"
}, {
"date": "2022-09-20T00:19:43.2651919-04:00",
"temperatureC": 7,
"summary": "Cool"
}, {
"date": "2022-09-21T00:19:43.2652001-04:00",
"temperatureC": 26,
"summary": "Scorching"
}
Now update the “NewFeature” flag in AppSettings.json as below,
"FeatureManagement": {
"TemperatureF": false,
"NewFeature": false
} {
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.4",
"title": "Not Found",
"status": 404,
"traceId": "00-4a24d9885877e1d886949c330cd2dd16-35b5ed50d738cba3-00"
}
We got the 404 error.
In the upcoming tutorial, I will be explaining Advanced Feature Flag and Custom Feature flag.
Thank you for reading my article. Please leave your comments in the comment box below