Skip to content

New Azure SDK developments may warrant an updated API surface for adding the configuration provider into the configuration system #730

@jimmyca15

Description

@jimmyca15

The latest release of the App Configuration SDK (Azure.Data.AppConfiguration) added a new type: ConfigurationClientSettings.

This type can be used to instantiate a ConfigurationClient directly. E.g.

var settings = new ConfigurationClientSettings
{
    Endpoint = new Uri(...),
    Credential = new DefaultAzureCredential()
};

var client = new ConfigurationClient(settings);

Additionally, the Azure SDK introduced a widespread new capability to get client settings from .NET's IConfiguration system. See an overview of this new capability here: Azure/azure-sdk-for-net#55491

There is a notable example:

ConfigurationManager configuration = new();
configuration.AddJsonFile("appsettings.json");

ConfigurationClientSettings settings = configuration.GetAzureClientSettings<ConfigurationClientSettings>("AppConfiguration");
ConfigurationClient client = new(settings);

The underlying configuration would look like

{
  "AppConfiguration": {
    "Endpoint": "https://<your-store>.azconfig.io",
    "Credential": {
      "CredentialSource": "AzureCli"
    }
  }
}

New possibilities without any changes in this library

Without any changes to this library, there is still some value effected by these changes. For example, the web app sample code could be updated

Before ConfigurationClientSettings

        public static IWebHost BuildWebHost(string[] args)
        {
            return WebHost.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((hostingContext, config) =>
                {
                    config.AddAzureAppConfiguration(
                        new Uri(hostingContext.Configuration["AppConfiguration:Endpoint"]),
                        new DefaultAzureCredential());
                })
                .UseStartup<Startup>()
                .Build();
        }

After

        public static IWebHost BuildWebHost(string[] args)
        {
            return WebHost.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((hostingContext, config) =>
                {
                    ConfigurationClientSettings settings = hostingContext
                        .Configuration
                        .GetAzureClientSettings<ConfigurationClientSettings>("AppConfiguration");

                    config.AddAzureAppConfiguration(
                        settings.Endpoint,
                        settings.Credential); // note the type of the credential can be changed in configuration without code updates
                })
                .UseStartup<Startup>()
                .Build();
        }

Proposal

I want to call out two things first

  • The overloads of AddAzureAppConfiguration typically reflect the minimum required parameters to create an App Configuration client (ConfigurationClient) and ConfigurationClient now has a new constructor that accepts ConfigurationClientSettings
  • With this new Azure SDK capability, there is an expectation that users will become increasingly more used to defining Azure SDK client endpoints and credential sources in configuration, specifically appsettings.json files and environment variables.

For these two reasons, it seems reasonable to add new overloads to accept ConfigurationClientSettings.

Without proposal implemented


        public static IWebHost BuildWebHost(string[] args)
        {
            return WebHost.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((hostingContext, config) =>
                {
                    ConfigurationClientSettings settings = hostingContext
                        .Configuration
                        .GetAzureClientSettings<ConfigurationClientSettings>("AppConfiguration");

                    config.AddAzureAppConfiguration(
                        settings.Endpoint,
                        settings.Credential); // note the type of the credential can be changed in configuration without code updates
                })
                .UseStartup<Startup>()
                .Build();
        }

If proposal implemented

        public static IWebHost BuildWebHost(string[] args)
        {
            return WebHost.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((hostingContext, config) =>
                {
                    ConfigurationClientSettings settings = hostingContext
                        .Configuration
                        .GetAzureClientSettings<ConfigurationClientSettings>("AppConfiguration");

                    config.AddAzureAppConfiguration(settings);
                })
                .UseStartup<Startup>()
                .Build();
        }

Going further

There is an option to add an overload that builds the configuration builder and reads from the configuration section by name. This could help clean up the code a bit. For example,

        public static IWebHost BuildWebHost(string[] args)
        {
            return WebHost.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((hostingContext, config) =>
                {
                    config.AddAzureAppConfigurationFromSettings("AppConfiguration");
                })
                .UseStartup<Startup>()
                .Build();
        }

The drawback of this is that it would require the implementation to perform an intermediate build of the IConfigurationBuilder. Due to configuration provider ordering behavior in .NET this may cause issues that could be difficult to pin down. Especially because the Build is not visible to the user. One may think that the section reference happens on a configuration set that is resolved minus App Configuration.

Connect

Any overload of AddAzureAppConfiguration should also carry over to AzureAppConfigurationOptions.Connect

E.g.

        public static IWebHost BuildWebHost(string[] args)
        {
            return WebHost.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((hostingContext, config) =>
                {
                    ConfigurationClientSettings settings = hostingContext
                        .Configuration
                        .GetAzureClientSettings<ConfigurationClientSettings>("AppConfiguration");

                    config.AddAzureAppConfiguration(o =>
                    {
                        o.Connect(settings); // new overload
                    });
                })
                .UseStartup<Startup>()
                .Build();
        }

ConfigurationClientOptions

ConfigurationClientSettings has an Options property which is of type ConfigurationClientOptions. This contains properties for things like max retries. If we accept ConfigurationClientSettings as a parameter, then we must respect the ConfigurationClientOptions that comes with it. Currently, the only way to configure ConfigurationClientOptions is with AzureAppConfigurationOptions.ConfigureClientOptions. This method provides a callback to update our default options, which have minor tweaks. With this update, we will need to accept incoming options.

Needs further thought

How this works with key vault references and key vault client instantiation

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions