Talking about the ConfigurationManager of. Net 6

introduce

This section brings you the newly added ConfigurationManager of. NET 6. Many people are curious about why to talk about this. You can read and load the configuration information easily. Let's look down.

This adds the new webapplication of ASP.NET Core and the types already used by WebApplicationBuilder, allowing reading from the configuration (such as appsettings.json and DOTNET_/ASPNETCORE_ environment variables), while still being able to add new configuration sources without explicitly rebuilding the configuration. Every time you add a source through the IConfiguration builder interface, IConfiguration is automatically updated immediately.

Review history

When developing with. NET 5, we use IConfigurationBuilder to add configuration source. Call the Build() builder to read each configuration source and build the final configuration IConfigurationRoot.

private static IConfigurationRoot BuildConfiguration()
        {
            var builder = new ConfigurationBuilder()
                .SetBasePath(Path.Combine(Directory.GetCurrentDirectory(), "../MyCompanyName.MyProjectName.DbMigrator/"))
                .AddJsonFile("appsettings.json", optional: false);

            return builder.Build();
        }

Of course, our normal system development basically does not call ConfigurationBuilder or Build(), which is completed for us at the bottom of the. Net Core.

So what is the meaning of this type of launch?

Take chestnut use application ID and X.509 certificate for non azure hosted apps, which is an official case given by Microsoft. Let me explain that configuring the Azure Key Vault provider requires a configuration value, so do I have a chicken or an egg first - the configuration source cannot be added before building the configuration!.

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureAppConfiguration((context, config) =>
        {
            if (context.HostingEnvironment.IsProduction())
            {
                var builtConfig = config.Build();

                using var store = new X509Store(StoreLocation.CurrentUser);
                store.Open(OpenFlags.ReadOnly);
                var certs = store.Certificates.Find(
                    X509FindType.FindByThumbprint,
                    builtConfig["AzureADCertThumbprint"], false);

                config.AddAzureKeyVault(new Uri($"https://{builtConfig["KeyVaultName"]}.vault.azure.net/"),
                                        new ClientCertificateCredential(builtConfig["AzureADDirectoryId"], builtConfig["AzureADApplicationId"], certs.OfType<X509Certificate2>().Single()),
                                        new KeyVaultSecretManager());

                store.Close();
            }
        })
        .ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup<Startup>());

Our steps are:

  • 1. Initialize configuration
  • 2. Call IConfigurationBuilder.Build() to build the configuration
  • 3. Retrieve the required configuration value from IConfigurationRoot
  • 4. Add configuration source
  • 5. The framework calls Build() to generate the final application configuration.

Here we call Build() twice. What's the problem?

Each call of ConfigurationBuilder.Build() will iterate over all sources, load providers, and generate a new instance ConfigurationRoot. Everyone should understand the consumption required to read the file.

New implementation

When we use the configuration manager, when IConfigurationSource adds an AddJsonFile() call, the provider will immediately load and update the configuration.

  using var config = new ConfigurationManager();

    config.AddEnvironmentVariables(prefix: "MyCustomPrefix_");

    if (config["FileConfig"] == "enabled")
    {
        config.AddJsonFile("MyConfig.json", optional: true, reloadOnChange: true);
    } 

    string myValueFromJson = config["JsonConfigValue"];


public class ConfigurationManager
{

    private void AddSource(IConfigurationSource source)
    {
        lock (_providerLock)
        {
            IConfigurationProvider provider = source.Build(this);
            _providers.Add(provider);

            provider.Load();
            _changeTokenRegistrations.Add(ChangeToken.OnChange(() => provider.GetReloadToken(), () => RaiseChanged()));
        }

        RaiseChanged();
    }
}


private void ReloadSources()
{
    lock (_providerLock)
    {
        DisposeRegistrationsAndProvidersUnsynchronized();

        _changeTokenRegistrations.Clear();
        _providers.Clear();

        foreach (var source in _sources)
        {
            _providers.Add(source.Build(this));
        }

        foreach (var p in _providers)
        {
            p.Load();
            _changeTokenRegistrations.Add(ChangeToken.OnChange(() => p.GetReloadToken(), () => RaiseChanged()));
        }
    }

    RaiseChanged();
}

Note: the configuration manager must delete everything and start again after any source changes, traverse each source and reload them. If you do a lot of configuration source manipulation, using configuration manager will have the opposite effect

Configuration manager is suitable for configuring partial build and full build.

epilogue

Please don't care whether to use ConfigurationManager or ConfigurationBuilder when using. Net 6. It's best to use different loading schemes according to needs in development.

In addition, my distributed transaction implementation code is nearing the end, which will be explained later

Finally, you are welcome to pay attention to my blog, https://github.com/MrChuJiu/Dppt/tree/master/src Welcome, Star

Contact author: Jia Qun: 867095512 @ mrchujiu

Tags: .NET

Posted on Tue, 23 Nov 2021 00:25:55 -0500 by warptwist