Roll out features to targeted audiences in an ASP.NET Core application

In this guide, you'll use the targeting filter to roll out a feature to targeted audiences for your ASP.NET Core application. For more information about the targeting filter, see Roll out features to targeted audiences.

Prerequisites

Create a web application with a feature flag

In this section, you create a web application that allows users to sign in and use the Beta feature flag you created before.

  1. Create a web application that authenticates against a local database using the following command.

    dotnet new webapp --auth Individual -o TestFeatureFlags
    
  2. Navigate to the newly created TestFeatureFlags directory and add references to the following NuGet packages.

    dotnet add package Microsoft.Azure.AppConfiguration.AspNetCore
    dotnet add package Microsoft.FeatureManagement.AspNetCore
    dotnet add package Azure.Identity
    
  3. Create a user secret for the application by running the following commands.

    The command uses Secret Manager to store a secret named Endpoints:AppConfiguration, which stores the endpoint for your App Configuration store. Replace the <your-App-Configuration-endpoint> placeholder with your App Configuration store's endpoint. You can find the endpoint in your App Configuration store's Overview blade in the Azure portal.

    dotnet user-secrets init
    dotnet user-secrets set Endpoints:AppConfiguration "<your-App-Configuration-endpoint>"
    
  4. Add Azure App Configuration and feature management to your application.

    1. You use the DefaultAzureCredential to authenticate to your App Configuration store. Follow the instructions to assign your credential the App Configuration Data Reader role. Be sure to allow sufficient time for the permission to propagate before running your application.

    2. Update the Program.cs file with the following code.

      // Existing code in Program.cs
      // ... ...
      
      using Azure.Identity;
      
      var builder = WebApplication.CreateBuilder(args);
      
      // Retrieve the endpoint
      string endpoint = builder.Configuration.GetValue<string>("Endpoints:AppConfiguration") 
          ?? throw new InvalidOperationException("The setting `Endpoints:AppConfiguration` was not found.");
      
      // Connect to Azure App Configuration and load all feature flags with no label
      builder.Configuration.AddAzureAppConfiguration(options =>
      {
          options.Connect(new Uri(endpoint), new DefaultAzureCredential())
                 .UseFeatureFlags();
      });
      
      // Add Azure App Configuration middleware to the container of services
      builder.Services.AddAzureAppConfiguration();
      
      // Add feature management to the container of services
      builder.Services.AddFeatureManagement();
      
      // The rest of existing code in Program.cs
      // ... ...
      
  5. Enable configuration and feature flag refresh from Azure App Configuration with the App Configuration middleware.

    Update Program.cs withe the following code.

    // Existing code in Program.cs
    // ... ...
    
    var app = builder.Build();
    
    // Use Azure App Configuration middleware for dynamic configuration refresh
    app.UseAzureAppConfiguration();
    
    // The rest of existing code in Program.cs
    // ... ...
    
  6. Add a new empty Razor page named Beta under the Pages directory. It includes two files Beta.cshtml and Beta.cshtml.cs.

    @page
    @model TestFeatureFlags.Pages.BetaModel
    @{
        ViewData["Title"] = "Beta Page";
    }
    
    <h1>This is the beta website.</h1>
    
  7. Open Beta.cshtml.cs, and add the FeatureGate attribute to the BetaModel class.

    using Microsoft.AspNetCore.Mvc.RazorPages;
    using Microsoft.FeatureManagement.Mvc;
    
    namespace TestFeatureFlags.Pages
    {
        [FeatureGate("Beta")]
        public class BetaModel : PageModel
        {
            public void OnGet()
            {
            }
        }
    }
    
  8. Open Pages/_ViewImports.cshtml, and register the feature manager Tag Helper using an @addTagHelper directive.

    @addTagHelper *, Microsoft.FeatureManagement.AspNetCore
    
  9. Open _Layout.cshtml in the Pages/Shared directory. Insert a new <feature> tag in between the Home and Privacy navbar items, as shown in the highlighted lines below.

    <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
        <div class="container">
            <a class="navbar-brand" asp-area="" asp-page="/Index">TestAppConfigNet3</a>
            <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                    aria-expanded="false" aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>
            <div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
                <ul class="navbar-nav flex-grow-1">
                    <li class="nav-item">
                        <a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
                    </li>
                    <feature name="Beta">
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Beta">Beta</a>
                        </li>
                    </feature>
                    <li class="nav-item">
                        <a class="nav-link text-dark" asp-area="" asp-page="/Privacy">Privacy</a>
                    </li>
                </ul>
            </div>
        </div>
    </nav>
    

Enable targeting for the web application

The targeting filter evaluates a user's feature state based on the user's targeting context, which comprises the user ID and the groups the user belongs to. In this example, you use the signed-in user's email address as the user ID and the domain name of the email address as the group.

  1. Add an ExampleTargetingContextAccessor.cs file with the following code. You implement the ITargetingContextAccessor interface to provide the targeting context for the signed-in user of the current request.

    using Microsoft.FeatureManagement.FeatureFilters;
    
    namespace TestFeatureFlags
    {
        public class ExampleTargetingContextAccessor : ITargetingContextAccessor
        {
            private const string TargetingContextLookup = "ExampleTargetingContextAccessor.TargetingContext";
            private readonly IHttpContextAccessor _httpContextAccessor;
    
            public ExampleTargetingContextAccessor(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);
            }
        }
    }
    
  2. Open the Program.cs file and enable the targeting filter by calling the WithTargeting method. You pass in the type ExampleTargetingContextAccessor that the targeting filter will use to get the targeting context during feature flag evaluation. Add HttpContextAccessor to the service collection to allow ExampleTargetingContextAccessor to access the signed-in user information from the HttpContext.

    // Existing code in Program.cs
    // ... ...
    
    // Add feature management to the container of services
    builder.Services.AddFeatureManagement()
                    .WithTargeting<ExampleTargetingContextAccessor>();
    
    // Add HttpContextAccessor to the container of services.
    builder.Services.AddHttpContextAccessor();
    
    // The rest of existing code in Program.cs
    // ... ...
    

    Note

    For Blazor applications, see instructions for enabling feature management as scoped services.

Targeting filter in action

  1. Build and run the application. Initially, the Beta item doesn't appear on the toolbar, because the Default percentage option is set to 0.

    User not logged in and Beta item not displayed

  2. Select the Register link in the upper right corner to create a new user account. Use an email address of test@contoso.com. On the Register Confirmation screen, select Click here to confirm your account.

  3. Sign in as test@contoso.com, using the password you set when registering the account.

    The Beta item now appears on the toolbar, because test@contoso.com is specified as a targeted user.

    User logged in and Beta item displayed

    Now sign in as testuser@contoso.com, using the password you set when registering the account. The Beta item doesn't appear on the toolbar, because testuser@contoso.com is specified as an excluded user.

    You can create more users with @contoso.com and @contoso-xyz.com email addresses to see the behavior of the group settings.

    Users with contoso-xyz.com email addresses won't see the Beta item. While 50% of users with @contoso.com email addresses will see the Beta item, the other 50% won't see the Beta item.

Next steps

To learn more about the feature filters, continue to the following documents.

For the full feature rundown of the .NET feature management library, continue to the following document.