This post is a follow-up to a previous post that described what feature flags are and how they can be useful in a development workflow. In this post, we will explore integrating feature flags into an ASP.NET Core web application. We will use Azure App Configuration to store our feature flags. We will go over the setup of the ASP.NET Core project and Azure App Configuration, and then we will look at three different scenarios where feature flags can help to safely add new features to the project.
If you are unfamiliar with feature flags, you can learn more about them in the previous post. In short, a feature flag is a conditional statement in one or more places that allow a feature to be enabled or disabled. If the flag is set to true, then the feature protected by the flag is enabled; if it is set to false, then the feature is disabled.
Setup
ASP.NET Core Web Application
To provide a good starting point for this post, I am using the eShopOnWeb ASP.NET Core reference application from Microsoft. It’s a simple eCommerce website that by default uses an in-memory database, so it doesn’t have any external dependencies. Several projects are provided as part of the solution, but we will be focused primarily on making our changes in the “src/Web” and “src/Infrastructure” projects.

I created a separate GitHub repository containing the changes I made to add the feature flag management library and each individual feature to the project. You can use the history on the repository to see the full set of changes made for each feature.
Azure App Configuration
Like all Azure services, Azure App Configuration requires an Azure subscription. I used my existing subscription, but if you don’t have an Azure subscription, then you will need to sign up for a free trial. Azure App Configuration has both a free and paid tier, but all of the features we need for feature flags are a part of the free tier so we will be using that one. Alternatively, if you are unable or unwilling to sign up for an Azure subscription, the feature flag configuration can be put into the appsettings.json file (see documentation).
Once you have an Azure subscription, follow the steps in the documentation to create the App Configuration resource.
Initial Code Changes
The initial set of code changes that I made to include the necessary libraries (Microsoft.FeatureManagement.AspNetCore and Microsoft.Azure.AppConfiguration.AspNetCore) and hook up App Configuration into the application can be found in commit 2f176be. One thing that isn’t clear just from looking at the commit is where the App Configuration connection string comes in – for that, I used the .NET Core Secret Manager.
Alternate Service Integration
The first feature we will implement is to replace the default implementation of IEmailSender (which is actually just a stub) with an implementation that uses SendGrid. I want to wrap this new implementation with a feature flag so that we can switch over from the current email provider to SendGrid without having to do a deployment. Instead, we can simply toggle the feature flag, and the implementation will switch.
Azure App Configuration
This feature flag is simple to set up in Azure App Configuration. We just need to create a new feature flag with no additional configuration. In this case, we named it “enable-SendGrid”.

Application Changes
We need to make a couple of changes to the application code in order to implement the feature. The first change is to add a new implementation of the IEmailSender interface that uses SendGrid. The second is to update the dependency injection registration to use the new SendGridEmailSender instead of the old EmailSender. This is where we use the feature flag. If the feature flag is enabled, then we register SendGridEmailSender; if the flag is disabled, we register EmailSender.
Using feature flags to switch between two implementations of an interface is a great way to use feature flags because they only need to be put into one place. It also allows implementation classes to not be concerned about feature flags at all. The classes can be solely concerned with their specific implementations. The feature flag is just used to decide which implementation to use.
if (configuration[$"FeatureManagement:{FeatureFlags.EnableSendgrid}"] == "True")
{
services.AddTransient<IEmailSender, SendGridEmailSender>();
}
else {
services.AddTransient<IEmailSender, EmailSender>();
}
These changes can be found in commit 41a7b91.
Rollout
This feature flag is a Boolean setting, so it can either be on or off. To roll this feature out in production, we simply wait for the planned cutover date and then enable the feature flag. If we need to roll back the change, we would simply disable the feature flag. In a future release, the feature flag code is cleaned up, and only the new implementation would remain.
A/B Testing of a UI element
The second feature we will add is going to be a little different. Marketing wants a new banner under the header welcoming users to the website. They want to perform A/B testing on this banner to see if it has an effect on user purchases. For context, this is what the banner looks like:

Azure App Configuration
This feature flag will need a custom feature filter configured in Azure App Configuration. We will go into the details of the filter in the next section. In-App Configuration, we need to select “Use feature filter” and then select the “Custom” radio button. Then we enter the name of the filter, “IpAddressPercentage.”

The last step is to enter the parameters for the filter. To do that, we click on the button next to the name of the filter and select “Edit filter parameters”. This lets us enter in the parameters for the filter – in this case, a single parameter named “PercentageValue” with a value of 50.

Application Changes
We will be utilizing the filter functionality of the feature management library to allow for A/B testing. The library comes with a PercentageFilter which at first glance looks like what we want. The PercentageFilter allows us to specify a percentage of requests that the feature flag will be enabled for. The problem with this is that the PercentageFilter doesn’t take into account if a user has already seen the banner or not. This means that a user could see the banner on one page and have it gone on the next page load. This would present a jarring user experience.
Instead, we want to be able to ensure that a user either sees or doesn’t see the banner for all of their requests. There are a few ways we can do that, but for the example, we are going to tie it to the user’s IP address. This means that a user will always either see or not see the banner, assuming their IP doesn’t change. To do this, we use a custom feature filter that I named “IpAddressPercentageFeatureFilter”. The filter takes the user’s IP address, uses the last three segments as a seed for a random number generator, and then generates a new random number between 0 and 99. If that number is less than the percentage we configured, the feature is enabled. This custom filter isn’t specific to our feature, so we could use it for other features in the future.
[FilterAlias("IpAddressPercentage")]
public class IpAddressPercentageFeatureFilter : IFeatureFilter
{
private readonly IHttpContextAccessor _httpContextAccessor;
public IpAddressPercentageFeatureFilter(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public Task<bool> EvaluateAsync(FeatureFilterEvaluationContext context)
{
var settings = context.Parameters.Get<IpAddressPercentageFilterSettings>();
var ipAddress = _httpContextAccessor.HttpContext.Connection.RemoteIpAddress;
int randomSeed = 0;
if (ipAddress != null)
{
var ipBytes = ipAddress.GetAddressBytes();
if (ipBytes.Length >= 3)
{
int rawIp = 0;
rawIp ^= ipBytes[ipBytes.Length - 1];
rawIp ^= ipBytes[ipBytes.Length - 2] << 8;
rawIp ^= ipBytes[ipBytes.Length - 3] << 16;
randomSeed = rawIp;
}
}
var random = new Random(randomSeed);
bool isEnabled = random.Next(100) < settings.PercentageValue;
return Task.FromResult(isEnabled);
}
}
Once we have our customer filter defined, using the feature flag is as simple as adding a <feature> flag to the layout file. Everything else is handled by the library, filter, and configuration.
<feature name="welcome-banner">
<div class="container" style="background-color:yellow">
Welcome to the eShop!
</div>
</feature>
These changes can be found in commit 2f19090.
Rollout
This feature can be rolled out by gradually increasing the percentage of users who are shown the banner. This might take several weeks if marketing will be performing A/B testing. If they decide to go ahead and make the banner permanent, we can set the percentage to 100% and then remove the flag in a later release. If they decide they don’t want the banner, we can set the percentage to 0% and remove the flag and banner in a later release.
Staged rollout of a new page
Our final feature is to add a new page for clearance sales. We want to be able to slowly roll out access to this new page so that we can do some testing in production to make sure the right sales items show up. Once our testers are happy with the feature, we can roll it out to all users.
Azure App Configuration
This time we will use the Targeting filter in Azure App Configuration. This will let us enter in users (who will always see the feature), groups (who can have a percentage configured for each group), and everyone else (who can have a percentage configured). For testing, we added a single user.
Application Changes
In order to use the Targeting filter, we will need to provide a custom ITargetingContextAccessor. This will give the Targeting filter the information it needs (username and groups) to determine if a user can or cannot access a feature. In our UserTargetingContextAccessor, we use the values provided in the HttpContext to get the user’s email address, which we use as the user ID. The email’s domain name is used as the group.
public class UserTargetingContextAccessor : ITargetingContextAccessor
{
private const string TargetingContextLookup = "UserTargetingContextAccessor.TargetingContext";
private readonly IHttpContextAccessor _httpContextAccessor;
public UserTargetingContextAccessor(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
}
public ValueTask<TargetingContext> GetContextAsync()
{
HttpContext httpContext = _httpContextAccessor.HttpContext;
if (httpContext.Items.TryGetValue(TargetingContextLookup, out object value))
{
return new ValueTask<TargetingContext>((TargetingContext)value);
}
List<string> groups = new List<string>();
if (httpContext.User.Identity.Name != null)
{
groups.Add(httpContext.User.Identity.Name.Split("@", StringSplitOptions.None)[1]);
}
TargetingContext targetingContext = new TargetingContext
{
UserId = httpContext.User.Identity.Name,
Groups = groups
};
httpContext.Items[TargetingContextLookup] = targetingContext;
return new ValueTask<TargetingContext>(targetingContext);
}
}
We are going to protect this new page by using an attribute on the MVC controller. This will evaluate the feature flag for all requests to any of the controller’s actions. The attribute can also be applied to individual actions. This gives us an easy way to gate features that are all accessed from a controller or a set of actions inside a controller.
[FeatureGate(FeatureFlags.ClearancePage)]
public class ClearanceController : Controller
The final thing we need to do is add a link to the clearance page to the header. We will use the same <feature> tag as before to show it only to users who have access to the feature.
<feature name="clearance-page">
<div class="container">
<a asp-controller="clearance" asp-action="sales" >Clearance sale</a>
</div>
</feature>
These changes can be found in commit 37e9fc7.
Rollout
With these changes in place, we can safely deploy our new page to production and be assured that it won’t be seen by the general public until our testers are satisfied with it. We can allow individual users or groups of users to see the feature. This could also be used for something like opt-in beta testing.
Closing
In the first part of this two-part series, we explored use cases for feature flags. In this second part, we looked at how we can implement some of those use cases in an ASP.NET Core website using Azure App Configuration and the Microsoft.FeatureManagement library. Hopefully, after reading both posts, you are equipped to start integrating feature flags into your development workflow. If you need more assistance with feature flags or any other DevOps or Cloud transformations, contact Tallan to get in touch with our DevOps team.
Ready to get started with DevOps? Click here to view our latest Marketplace offering.