Search code examples
azureazure-web-app-service.net-5serilogazure-app-configuration

How to retrieve Azure App Configuration Service settings while in Program.cs


I am using Asp.NET Core 5 (v5.0.6) web API deployed as an Azure App Service and I am migrating from using appsettings.json in the API to integrating with Azure App Configuration service. I have the Azure App Configuration Service set up but the issue I am having is how to access values in my Azure App Configuration service for retrieving a connection string for database access while I am still in Program.cs.

Note that in the CreateHostBuilder() method I am examining the context.HostingEnvironment.IsDevelopment() environment variable and if it is "IsDevelopment", implying a local DEV, I am reading an Azure App Configuration Service connection string via User Secrets but if it is not a local DEV, than I rely on the Managed Identity and just pass in the endpoint value from appsettings.json.

The only values I want to get that are not in Azure App Configuration Service is the local DEV Azure App Configuration Service Connection string (from User Secrets) and the Azure App Configuration Service endpoint from Appsettings.json. All other settings should come from Azure App Configuration Service.

The problem I am trying to solve is how to access the values in Azure App Configuration Service, while still in Program.cs, to retrieve the connection string for access to the Azure SQL database I am using for logging.

In the code below, when I link the Azure App Configuration in the CreateHostBuilderMethod and call build, I expected the values in Azure App Configuration Service to then be available via the static Configuration property. However when I try to retrieve the connection string value, it is always null.

How can I correctly retrieve the values for properties in Azure App Configuration Service to use them in Program.cs?

Here is my Program.cs file;

public class Program
{
    public static IConfiguration Configuration { get; } = new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
        .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true)
        .AddUserSecrets<Startup>()
        .Build();

    public static void Main(string[] args)
    {
        var host = CreateHostBuilder(args)
            .Build();
        
        var connectionString = Configuration["CoreApi:Settings:LoggingDb"]; //<-- This returns null
        const string tableName = "ApiLogs";

        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Information()
            .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
            .Filter.ByExcluding(Matching.FromSource("Microsoft.EntityFrameworkCore.Query"))
            .WriteTo.MSSqlServer(
                connectionString: connectionString,
                sinkOptions: new MSSqlServerSinkOptions { TableName = tableName })
            .CreateLogger();

        // TODO Enable to debug any startup Serilog issues. Make sure to comment out for PROD
        // Serilog.Debugging.SelfLog.Enable(msg =>
        // {
        //    Debug.Print(msg);
        //    Debugger.Break();
        // });
        //var host = CreateHostBuilder(args)
        //    .Build();

        try
        {
            Log.Information("Starting ConfirmDelivery API");
            host.Run();
        }
        catch (Exception ex)
        {
            Log.Fatal(ex, "ConfirmDelivery API Host terminated unexpectedly");
        }
        finally
        {
            Log.CloseAndFlush();
        }
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((context, config) =>
            {
                var settings = config.Build();
                if (context.HostingEnvironment.IsDevelopment())
                {
                    var connectionString = settings.GetConnectionString("AzureAppConfiguration");
                    config.AddAzureAppConfiguration(connectionString);
                }
                else
                {
                    var endpoint = settings["AppConfigEndpoint"];
                    var credentials = new ManagedIdentityCredential();
                    config.AddAzureAppConfiguration(options =>
                    {
                        options.Connect(new Uri(endpoint), credentials);
                    });
                }
            }).ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });

}

Solution

  • Try the code below to get a config value:

    using System;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.Configuration.AzureAppConfiguration;
    
    
    namespace myapp
    {
        class Program
        {
            static void Main(string[] args)
            {
                var configItemName = "";
                var appConfigConnectionString = "";
                var builder = new ConfigurationBuilder();
                builder.AddAzureAppConfiguration(appConfigConnectionString);
    
                var config = builder.Build();
                Console.WriteLine(config[configItemName]);
            }
        }
    }
    

    Result :

    enter image description here enter image description here