1

I am using azure app configuration and azure function.

So i am pulling all the key value from azure app configuration. But if the azure function is running and if i make any changes in key value from azure app configuration, azure func will not show the updated value.

Below is the code that i have implemented

in startup.cs

public override void Configure(IFunctionsHostBuilder builder)
        {
            var environmentName = Environment.GetEnvironmentVariable("AZURE_FUNCTIONS_ENVIRONMENT");
            if (string.IsNullOrWhiteSpace(environmentName))
                throw new Exception("AZURE_FUNCTIONS_ENVIRONMENT could not be resolved.");

            var hostEnvironment = new HostEnvironment { EnvironmentName = environmentName };
            var config = SetUpConfiguration(builder.Services, hostEnvironment);

            var appSettings = config.Get<TSettings>();
            appSettings.AppName = _appName;

            builder.Services.AddSingleton<ICorrelationIdProvider>(new FunctionAppCorrelationIdProvider());
            builder.Services.AddSingleton<IIdentityProvider>(new FunctionAppIdentityProvider(appSettings.AppName));
            builder.Services.AddSingleton<IHostEnvironment>(hostEnvironment);
            builder.Services.AddSingleton(appSettings);

}

    private IConfiguration SetUpConfiguration(IServiceCollection services, IHostEnvironment environment)
            {
                var executionContextOptions = services.BuildServiceProvider().GetService<IOptions<ExecutionContextOptions>>().Value;
                var configBuilder = new ConfigurationBuilder().Initialize(environment, executionContextOptions.AppDirectory);
                var config = configBuilder.Build();
                services.AddSingleton<IConfiguration>(new ConfigurationRoot(config.Providers.ToArray()));
                return config;
            }

in a helper class i have written the below code

 builder.AddAzureAppConfiguration(appConfigurationOptions =>
            appConfigurationOptions
                .Connect(new Uri(config["AppConfig:Endpoint"]), tokenCredential)
                .Select(ConfigurationKeys.AZURE_FUNC_TEST)
                .Select(KeyFilter.Any, environment.EnvironmentName)
                .ConfigureRefresh(refreshOptions =>
                {                 
                    refreshOptions.Register(ConfigurationKeys.AZURE_FUNC_TEST, false);
                    refreshOptions.SetCacheExpiration(TimeSpan.FromMinutes(1));
                })
                
        );
        return builder;

in azure function i am using the below code to get the value

var test = _settings.AzureFuncTest;

but here i dont get the new value until i dont restart the azure functions.

Ekta
  • 261
  • 1
  • 2
  • 11
  • @JasonPan i agree but i want it for azure function. In azure function how do i refresh it – Ekta Nov 03 '20 at 09:08
  • @JasonPan I am getting configurationRefresher = options.GetRefresher(); as null – Ekta Nov 03 '20 at 11:23

1 Answers1

0

I have updated the SetUpConfiguration method in the question to include the code in the helper method that sets up App Configuration. Although the question doesn't include how the helper method is used, but the following code would ensure that configurationRefresher is initialized.

private IConfiguration SetUpConfiguration(IServiceCollection services, IHostEnvironment environment)
{
    var executionContextOptions = services.BuildServiceProvider().GetService<IOptions<ExecutionContextOptions>>().Value;
    var configBuilder = new ConfigurationBuilder().Initialize(environment, executionContextOptions.AppDirectory);
    IConfigurationRefresher configurationRefresher = null;
    TokenCredential tokenCredential = new DefaultAzureCredential();

    configBuilder.AddAzureAppConfiguration(appConfigurationOptions =>
    {
        var settings = configBuilder.Build();

        appConfigurationOptions
            .Connect(new Uri(settings["AppConfig:Endpoint"]), tokenCredential)
            .Select(ConfigurationKeys.AZURE_FUNC_TEST)
            .Select(KeyFilter.Any, environment.EnvironmentName)
            .ConfigureRefresh(refreshOptions =>
            {
                refreshOptions.Register(ConfigurationKeys.AZURE_FUNC_TEST, false);
                refreshOptions.SetCacheExpiration(TimeSpan.FromMinutes(1));
            });

        configurationRefresher = appConfigurationOptions.GetRefresher();
    });

    var configuration = configBuilder.Build();
    services.AddSingleton(configurationRefresher);
    services.AddSingleton<IConfiguration>(configuration);

    return configuration;
}

Also, the statement var appSettings = config.Get<TSettings>() will create a copy of the settings at that moment, and is not expected to reflect changes in IConfiguration instance. To be able to see the latest settings, please use IOptionsMonitor<T> as described here.

Abhilash Arora
  • 277
  • 2
  • 4
  • I tried this and yes i get the config refresher value and when i write this line in function app await _configurationRefresher.TryRefreshAsync(); and when i inspect i see the new value but the config still has the old value and it is not getting updated – Ekta Nov 04 '20 at 06:22
  • Which variable did you inspect that showed the new value? And where do you expect the old value to be updated? – Abhilash Arora Nov 04 '20 at 06:59
  • await _configurationRefresher.TryRefreshAsync(); when i inspect await _configurationRefresher in this line it gets updated with new value but var appSettings = _config.Get(); in this the _config still has the old value – Ekta Nov 04 '20 at 07:09
  • @Ekta If you try the official source code and still find the problem exists, it is recommended to raise a support ticket for official help. – Jason Pan Nov 04 '20 at 07:43
  • @Ekta Okay, looks like it fixed your issue with refresher being null. The `_config.Get()` will not reflect changes since it creates a copy of the configuration. You can use `IOptionsMonitor()` to create an instance that can be injected in DI and would reflect updates in `IConfiguration`. – Abhilash Arora Nov 04 '20 at 18:11