Matthew James Davis
Matthew James Davis

Reputation: 12295

Use appsettings to drive environment specific settings such as UseUrls

When I'm developing locally using VS Code, I'm going to use port 3000 because I'm a hipster. The non-hipsters want it on port 8080 on the server. That's cool, we got this. Microsoft docs give me the following example:

public static void Main(string[] args)
{
    var config = new ConfigurationBuilder()
        .AddJsonFile("hosting.json", optional: true)
        .AddCommandLine(args)
        .Build();

    var host = new WebHostBuilder()
        .UseConfiguration(config)
        .UseKestrel()
        .Configure(app =>
        {
            app.Run(async (context) => await context.Response.WriteAsync("Hi!"));
        })
        .Build();

    host.Run();
}

I don't want to use hosting.json. Why would I want that? I have this appsettings.{environment}.json file for exactly this situation. Sweet, I'll just paste that bad boy in

public static void Main(string[] args)
{
    var config = new ConfigurationBuilder()
        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
        .AddCommandLine(args)
        .Build();

What the compiler error? env does not exist in the current context. It only exists in the Startup.cs file--which is not called on startup, but called from the startup file, Program.cs, with sorcery.

So, how do I solve this problem? How can I store my environment-specific hosting settings in my environment-specific appsettings.json, and subsequently use it in while building my environment-specific web host via the WebHostBuilder in Program.cs?

Upvotes: 7

Views: 5486

Answers (2)

Alexander Christov
Alexander Christov

Reputation: 10045

Or, starting from .NET Core 2.0, when creating the default IWebHostBuilder that will build the IWebHost implementation, you can use

return WebHost.CreateDefaultBuilder(args)
            .UseConfiguration(configuration)
            .ConfigureAppConfiguration((builderContext, config) =>
            {
                // nb: here you may clear configuration(s) loaded so far
                var env = builderContext.HostingEnvironment;
                config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                    .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: false, reloadOnChange: true);
            })
            .UseStartup<Startup>();

Upvotes: 0

Justin Saraceno
Justin Saraceno

Reputation: 2516

This is possible. Expanding on the answer given here, by creating the WebHostBuilder and ConfigurationBuilder in the Program.cs, it is possible to have access to the host environment and then configure the host URL and port in environment-specific appsettings files.

Assuming an appsettings.json and an apppsettings.Development.json file each with the following:

"hostUrl": "http://*:<port number here>"

Modify the Main with the following:

public static void Main(string[] args)
{
    var host = new WebHostBuilder();
    var env = host.GetSetting("environment");
    var builder = new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
        .AddJsonFile($"appsettings.{env}.json", optional: true)
        .AddEnvironmentVariables();
    var configuration = builder.Build();

    host.UseKestrel()
        .UseUrls(configuration["hostUrl"])
        .UseContentRoot(Directory.GetCurrentDirectory())
        .UseStartup<Startup>()
        .Build()
        .Run();
}

Using this code, the Startup.cs will still need to declare its own ConfigurationBuilder in order to publicly expose its Configuration property.

Upvotes: 8

Related Questions