Muokkaa

Jaa


Tutorial: Use variant feature flags in an ASP.NET Core 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. Navigate to the QuoteOfTheDay directory and create a user secret for the application by running the following commands. 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>"
    
  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. Open Program.cs and add the following using statements.

    using Azure.Identity;
    using Microsoft.Extensions.Configuration.AzureAppConfiguration;
    using Microsoft.FeatureManagement;
    
  2. Add the following code to connect to your App Configuration store and call UseFeatureFlags to pull 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.

    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.");
    
    // Load configuration and feature flags from Azure App Configuration
    builder.Configuration
        .AddAzureAppConfiguration(options =>
        {
            options.Connect(new Uri(endpoint), new DefaultAzureCredential())
                   .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.