Search code examples
c#asp.net-coreasp.net-core-3.0

How to read configuration settings before initializing a Host in ASP .NET Core?


Before initializing the application Host I need to read some settings from the application's configuration to setup some other things.

In ASP .NET Core 2.x to read settings before initializing the application Host I used to do the following:

public static void Main(string[] args)
{
    //...

    var configuration = new ConfigurationBuilder()
        .AddEnvironmentVariables()
        .AddCommandLine(args)
        .AddJsonFile("appsettings.json")
        .Build();

    //Do something useful with the configuration...

    var host = WebHost.CreateDefaultBuilder()
        .UseStartup<Startup>()
        .UseConfiguration(configuration)
        .Build();

    //...
}

In ASP .NET Core 3.x WebHost has been deprecated in favor of .NET Generic Host.
.NET Generic Host has only .ConfigureHostConfiguration() and .ConfigureAppConfiguration() that do not take a built configuration as parameter, but instead accept only a delegate used to setup the configuration.

For HTTP workloads you can still use the method .UseConfiguration() has it is exposed by IWebHostBuilder and do essentially the same as before:

public static void Main(string[] args)
{
    //...

    var configuration = new ConfigurationBuilder()
        .AddEnvironmentVariables()
        .AddCommandLine(args)
        .AddJsonFile("appsettings.json")
        .Build();

    //Do something useful with the configuration...

    var host = Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>()
                .UseConfiguration(configuration);
        })
        .Build();

    //...
}

But this only works for HTTP workloads and not for Worker Services.

To get the configuration before setting up the Host I've come up with the following approach:

public static void Main(string[] args)
{
    //...

    var configuration = ConfigureConfigurationBuilder(args)
        .Build();

    //Do something useful with the configuration...

    var host = Host.CreateDefaultBuilder(args)
        .ConfigureAppConfiguration(builder => ConfigureConfigurationBuilder(args, builder))
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        })
        .Build();

    //...
}

public static IConfigurationBuilder ConfigureConfigurationBuilder(string[] args, IConfigurationBuilder configurationBuilder = null)
{
    configurationBuilder ??= new ConfigurationBuilder();

    configurationBuilder
        .AddEnvironmentVariables()
        .AddCommandLine(args)
        .AddJsonFile("appsettings.json");

    return configurationBuilder;
}

Essentially I've wrote a method that setups a ConfigurationBuilder and returns it, so that I can reuse the same configuration. This works in practice, but I build the same configuration twice.

Is there a simpler/more correct way (that works for HTTP workloads and non-HTTP workloads) to build and reuse the configuration before setting up the Host ?


Solution

  • You can clear the default sources added by CreateDefaultBuilder then add a pre-built IConfiguration with the AddConfiguration extension method.

    public static void Main(string[] args)
    {
        //...
    
        var configuration = new ConfigurationBuilder()
            .AddEnvironmentVariables()
            .AddCommandLine(args)
            .AddJsonFile("appsettings.json")
            .Build();
    
        //Do something useful with the configuration...
    
        var host = Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration(builder =>
            {
                builder.Sources.Clear();
                builder.AddConfiguration(configuration);
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            })
            .Build();
    
        //...
    }