azureasp.net-core.net-coreazure-app-configurationfeature-flags

Azure Feature Flag is not updating after cache expiration


We have FeatureFlag: IsServiceNeeded with no label set in Feature Manager of Azure App Configuration. We have used in built method AddAzureAppConfiguration by setting up the cache interval.

We are using .net core 3.1 web api and Feature Manager of Azure App Configuration.

We had IsServiceNeeded enabled during initialization of the app and after few hours, we disabled IsServiceNeed. We wait for entire day, but don't see the difference since the below returns true instead of false. We were expecting it to update every 3 minutes due to how we have it configured in program.cs file.

await _featureManager.IsEnabledAsync("IsServiceNeeded")

Let me know if you see anything odd with below. Thanks in advance,

Here is the code snippet we are using it.

Program.cs file

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((context, config) =>
            {
                var configurationRoot = config.Build();
                var appConfigConString = configurationRoot["AppConfigConnectionString"];

                config.AddAzureAppConfiguration(options => options.Connect(appConfigConString).UseFeatureFlags(featureFlagOptions => {
                    **featureFlagOptions.CacheExpirationInterval = TimeSpan.FromMinutes(3);**
                }));
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

Startup.cs file

public class Startup
{
    public IConfiguration Configuration { get; }
    public string ContentRootPath { get; set; }
    
    public Startup(IWebHostEnvironment env, IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddHsts(options =>
        {
            options.Preload = true;
            options.IncludeSubDomains = true;
            options.MaxAge = TimeSpan.FromDays(365);
        });

        var conf = Configuration.GetSection("AppSettings").Get<Config>();

        services.Configure<Config>(Configuration.GetSection("AppSettings"));

        services.AddSingleton<IAppSettings>(c => conf);**

        services.AddScoped<IProcessHandler, ProcessHandler>();
        **services.AddFeatureManagement();**
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        app.UseHsts();
        app.UseHttpsRedirection();
        app.UseHttpStatusCodeExceptionMiddleware();

        app.UseHttpsRedirection();

        app.UseRouting();

        app.UseAuthentication();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }

        private static void LoadMediatorHandlers(IServiceCollection services)
        {
            foreach (var assembly in Assembly
                                     .GetEntryAssembly()
                                     .GetReferencedAssemblies()
                                     .Select(Assembly.Load)
                                     .Where(name => (name.FullName.Contains("Queries") || name.FullName.Contains("Commands"))))
            {
                services.AddMediatR(assembly);
            }
            services.AddMediatR(typeof(Startup));
            services.AddScoped<IMediator, Mediator>();
        }   
    }

Application of Feature Flag:

public class ProcessHandler : IProcessHandler
{
    private readonly IFeatureManager _featureManager;

    public ProcessHandler(IFeatureManager featureManager)
    {
        _featureManager = featureManager;
    }

    public async Task<ClassA> ProcessXyz()
    {
        if (`await _featureManager.IsEnabledAsync("IsServiceNeeded")`)
        {
            return new ClassA();
        }
        
        return null;
    }   
}

Please Note: I have just added the required code and replaced actual names for security issues.

Thanks in advance


Solution

  • What is missing is the middleware that refreshes feature flags (and configuration) from Azure App Configuration.

    Open your startup.cs, add below

    public void ConfigureServices(IServiceCollection services)
    {
        // ...
        services.AddAzureAppConfiguration();
        services.AddFeatureManagement();
    }
    

    And then add below

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        // ...
        app.UseAzureAppConfiguration();
    }