Tutorial: Use variant feature flags from Azure App Configuration in an ASP.NET application

In this tutorial, you use a variant feature flag to manage experiences for different user segments in an example application, Quote of the Day. You utilize the variant feature flag created in Use variant feature flags. Before proceeding, ensure you create the variant feature flag named Greeting in your App Configuration store.

Prerequisites

Create an ASP.NET Core web app

  1. Run the following code in a command prompt. This command creates a new Razor Pages application in ASP.NET Core, using Individual account auth, and places it in an output folder named QuoteOfTheDay.

    dotnet new razor --auth Individual -o QuoteOfTheDay
    
  2. Create a user secret for the application by navigating into the QuoteOfTheDay folder and run the following command. This secret holds the endpoint for your App Configuration.

    dotnet user-secrets set Endpoints:AppConfiguration "<App Configuration Endpoint>"
    
  3. Add the latest versions of the required packages.

    dotnet add package Azure.Identity
    dotnet add package Microsoft.Extensions.Configuration.AzureAppConfiguration
    dotnet add package Microsoft.FeatureManagement.AspNetCore
    

Connect to App Configuration for feature management

  1. In Program.cs, add the following using statements.

    using Azure.Identity;
    using Microsoft.Extensions.Configuration.AzureAppConfiguration;
    using Microsoft.FeatureManagement;
    
  2. In Program.cs, under the line var builder = WebApplication.CreateBuilder(args);, add the App Configuration provider, which pulls down the configuration from Azure App Configuration when the application starts. By default, the UseFeatureFlags method pulls down all feature flags with no label.

    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.

    builder.Configuration
        .AddAzureAppConfiguration(options =>
        {
            string endpoint = builder.Configuration.Get("Endpoints:AppConfiguration");
            options.Connect(new Uri(endpoint), new DefaultAzureCredential());
    
            options.UseFeatureFlags();
        });
    
  3. Add Azure App Configuration and feature management services and enable targeting for feature management.

    // Add Azure App Configuration and feature management services to the container.
    builder.Services.AddAzureAppConfiguration()
        .AddFeatureManagement()
        .WithTargeting();
    
  4. Under the line var app = builder.Build();, add Azure App Configuration middleware for dynamic configuration refresh.

    // Use Azure App Configuration middleware for dynamic configuration refresh.
    app.UseAzureAppConfiguration();
    

Use the variant feature flag

  1. Open QuoteOfTheDay > Pages > Index.cshtml.cs and replace the content with the following code.

    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Mvc.RazorPages;
    using Microsoft.FeatureManagement;
    
    namespace QuoteOfTheDay.Pages;
    
    public class Quote
    {
        public string Message { get; set; }
    
        public string Author { get; set; }
    }
    
    public class IndexModel(IVariantFeatureManagerSnapshot featureManager) : PageModel
    {
        private readonly IVariantFeatureManagerSnapshot _featureManager = featureManager;
    
        private Quote[] _quotes = [
            new Quote()
            {
                Message = "You cannot change what you are, only what you do.",
                Author = "Philip Pullman"
            }];
    
        public Quote? Quote { get; set; }
    
        public string GreetingMessage { get; set; }
    
        public async void OnGet()
        {
            Quote = _quotes[new Random().Next(_quotes.Length)];
    
            Variant variant = await _featureManager.GetVariantAsync("Greeting", HttpContext.RequestAborted);
    
            if (variant != null)
            {
                GreetingMessage = variant.Configuration?.Get<string>() ?? "";
            }
            else
            {
                _logger.LogWarning("No variant given. Either the feature flag named 'Greeting' is not defined or the variants are not defined properly.");
            }
        }
    }
    

    You call GetVariantAsync to retrieve the variant of the Greeting feature flag for the current user and assign its value to the GreetingMessage property of the page model.

  2. In QuoteOfTheDay > Pages > Shared > _Layout.cshtml, under where QuoteOfTheDay.styles.css is added, add the following reference to the font-awesome CSS library.

    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css">
    
  3. Open index.cshtml and replace its content with the following code.

    @page
    @model IndexModel
    @{
        ViewData["Title"] = "Home page";
        ViewData["Username"] = User.Identity?.Name ?? string.Empty;
    }
    
    <style>
        body {
            font-family: Arial, sans-serif;
            background-color: #f4f4f4;
            color: #333;
        }
    
        .quote-container {
            background-color: #fff;
            margin: 2em auto;
            padding: 2em;
            border-radius: 8px;
            max-width: 750px;
            box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.2);
            display: flex;
            justify-content: space-between;
            align-items: start;
            position: relative;
        }
    
        .vote-container {
            position: absolute;
            top: 10px;
            right: 10px;
            display: flex;
            gap: 0em;
        }
    
        .vote-container .btn {
            background-color: #ffffff; /* White background */
            border-color: #ffffff; /* Light blue border */
            color: #333
        }
    
        .vote-container .btn:focus {
            outline: none;
            box-shadow: none;
        }
    
        .vote-container .btn:hover {
            background-color: #F0F0F0; /* Light gray background */
        }
    
        .greeting-content {
            font-family: 'Georgia', serif; /* More artistic font */
        }
    
        .quote-content p.quote {
            font-size: 2em; /* Bigger font size */
            font-family: 'Georgia', serif; /* More artistic font */
            font-style: italic; /* Italic font */
            color: #4EC2F7; /* Medium-light blue color */
        }
    </style>
    
    <div class="quote-container">
        <div class="quote-content">
            <h3 class="greeting-content">@(Model.GreetingMessage)</h3>
            <br />
            <p class="quote">“@(Model.Quote?.Message ?? "< Quote not found >")”</p>
            <p>- <b>@(Model.Quote?.Author ?? "Unknown")</b></p>
        </div>
    
        <div class="vote-container">
            <button class="btn btn-primary" onclick="heartClicked(this)">
                <i class="far fa-heart"></i> <!-- Heart icon -->
            </button>
        </div>
    </div>
    
    <script>
        function heartClicked(button) {
            var icon = button.querySelector('i');
            icon.classList.toggle('far');
            icon.classList.toggle('fas');
        }
    </script>
    

    This code displays the UI of the Quote of the Day application and shows the GreetingMessage from the page model. The JavaScript handler heartClicked is triggered when the heart button is clicked.

Build and run the app

  1. Build and run the application.

    dotnet build
    dotnet run
    
  2. Once the application is loaded, select Register at the top right to register a new user.

    Screenshot of the Quote of the day app, showing Register.

  3. Register a new user named usera@contoso.com.

  4. Select the link Click here to validate email after entering user information.

    Screenshot of the Quote of the day app, showing click to confirm.

  5. Repeat the same steps to register a second user named userb@contoso.com.

    Note

    It's important for the purpose of this tutorial to use these names exactly. As long as the feature has been configured as expected, the two users should see different variants.

  6. Select Login at the top right to sign in as usera@contoso.com.

    Screenshot of the Quote of the day app, showing **Login**.

  7. Once logged in, you see a long greeting message for usera@contoso.com

    Screenshot of the Quote of the day app, showing a long message for the user.

  8. Click Logout and login as userb@contoso.com, you see the simple greeting message.

    Screenshot of the Quote of the day app, showing a simple message for the user.

Next steps

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