Lion
Lion

Reputation: 17879

Load appsettings.{envName}.json file in ASP.NET Core 2.1

In prior versions of ASP.NET Core we could dynamically add appsetting.json files with the environment suffix like appsettings.Production.json for production environment.

Since the structure is a bit different, it seems that the configuration now got loaded in class Program. But we dont have the `` injected here,so I tried it myself using environment variable:

public class Program {
        public static void Main(string[] args) {
            CreateWebHostBuilder(args).Build().Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) {
            string envName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
            string envConfigFile = $"appsettings.{envName}.json";

            var config = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile(envConfigFile, optional: true);

            var finalConfig = config.Build();
            return WebHost.CreateDefaultBuilder(args)
                .UseUrls("http://0.0.0.0:5000")
                .UseConfiguration(finalConfig)
                .UseStartup<Startup>();
        }
    }

The code got executed but it doesn't override my appsettings.json config. Let's say I have the following appsettings.json:

{
    "MyConnectionString": "Server=xxx,Database=xxx, ..."
}

This ConnectionString is working. Now I createappsettings.Development.json

{
    "MyConnectionString": ""
}

and set ASPNETCORE_ENVIRONMENT=Development. This should definitely throw an exception. But the app start correctly with the ConnectionString from appsettings.json.

According to ASP.NET Core 2 configuration changes, the WebHost.CreateDefaultBuilder method should itself use the new ConfigureAppConfiguration approach and load environment specific config by default. Also the official docs say that appsettings.{Environment}.json are loaded automatically. But this doesn't work and also loading it manually like this doesn't solve the problem:

return WebHost.CreateDefaultBuilder(args)
                .UseUrls("http://0.0.0.0:5000")
                .ConfigureAppConfiguration((builderContext, config) => {
                    IHostingEnvironment env = builderContext.HostingEnvironment;
                    config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
                })
                .UseStartup<Startup>();

How can I override the config using "appsettings.{envName}.json" pattern? I liked that cause it was handy to override env specific things in ASP.NET Core.

Upvotes: 1

Views: 13181

Answers (6)

Babul Reddy Chintala
Babul Reddy Chintala

Reputation: 35

Environment variable Settings Image

Based on Enviroment Variables settings we can use appsettings.environment.json file as config file

 public Startup(IHostingEnvironment env)
            {
                var builder = new ConfigurationBuilder()
                    .SetBasePath(env.ContentRootPath)
                    .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                    .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
                    .AddEnvironmentVariables();
                Configuration = builder.Build();
            }

Upvotes: 2

Yahoo Serious
Yahoo Serious

Reputation: 3908

According to docs, the JSON Configuration Provider should automatically load twice in ASP.NET Core 2.1 (and ASP.NET Core 2.1) when using CreateDefaultBuilder (so move your code from the separate ConfigurationBuilder).

AddJsonFile is automatically called twice when you initialize a new WebHostBuilder with CreateDefaultBuilder. The method is called to load configuration from:

  • appsettings.json – This file is read first. The environment version of the file can override the values provided by the appsettings.json file.
  • appsettings.{Environment}.json – The environment version of the file is loaded based on the IHostingEnvironment.EnvironmentName.

Their example:

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .ConfigureAppConfiguration((hostingContext, config) =>
        {
            config.SetBasePath(Directory.GetCurrentDirectory());
            config.AddJsonFile(
                "config.json", optional: true, reloadOnChange: true);
        })

(If you want to use connection strings from your startup (UI MVC) project, for adding migrations in a different migrations project you may want to check this answer.)

Upvotes: 4

Fausto Carias
Fausto Carias

Reputation: 28

You should check your build settings. If you want your project to load an specific environment then you should specify to the compiler wish environment settings you want to be loaded.

I hope it helps. Good luck.

Upvotes: 0

Lion
Lion

Reputation: 17879

Found out that I had a custom DesignTimeDbContextFactory class for migrations:

public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<ApplicationDbContext> {
        public ApplicationDbContext CreateDbContext(string[] args) {
            var builder = new DbContextOptionsBuilder<ApplicationDbContext>();
            string connectionString = Config.GetConnectionString("AppDbContext");
            builder.UseMySql(connectionString);

            return new ApplicationDbContext(builder.Options);
        }
    }

Since the injection of the configratuion doesn't seem to work here (at the time I got errors for my connection strings when using default Startup class), I wrote some custom configuration class:

public class Config {
        static IConfigurationRoot config;
        static IConfigurationRoot AppConfig {
            get {
                if (config == null) {
                    config = new ConfigurationBuilder()
                             .SetBasePath(Directory.GetCurrentDirectory())
                             .AddJsonFile("appsettings.json")
                             .Build();
                }
                return config;
            }
        }
        public static string GetConnectionString(string name) {
            var connectionString = AppConfig.GetConnectionString(name);
            return connectionString;
        }
    }

So the problem was, that ASP.NET Core's default ConfigureAppConfiguration wasn't used for consistence. Instead my solution only loads appsettings.json since at the time of writing this class, no environment specific config was used.

I simply need to add loading here like this:

    static IConfigurationRoot AppConfig {
        get {
            if (config == null) {
                var environmentName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
                config = new ConfigurationBuilder()
                         .SetBasePath(Directory.GetCurrentDirectory())
                         .AddJsonFile("appsettings.json")
                         // https://github.com/aspnet/MetaPackages/blob/rel/2.0.0/src/Microsoft.AspNetCore/WebHost.cs
                         .AddJsonFile($"appsettings.{environmentName}.json", optional: true, reloadOnChange: true)
                         .Build();
            }
            return config;
        }
    }

I'd appreciate it if someone has a cleaner solution here that let me use the default ConfigureAppConfiguration approach in EF migrations, cause it seems less error prone when using such default stuff instead of customized methods.

Upvotes: 5

rbennett485
rbennett485

Reputation: 2163

Try using CreateDefaultBuilder() which should provide you with the configuration settings you want (as in the example in the docs). Note that if you are running on Linux it is case sensitive - if the file name has a capital P for Production, the value of the environment variable must as well. Also, check you have the files in the correct directory - print the value of Directory.CurrentDirectory() at runtime. This is where they should be.

If this works but you don't actually want a default builder, just copy the parts you need from the source.

Upvotes: 0

Judy007
Judy007

Reputation: 5860

You need to go to your solution in visual studio 2017c click on the solution, in menu click properties > build and you’ll see That environment variable has already been created for the environment named Development. If you override that value within the properties page for your given web project , it will pull the environment variables from the app environment specific app settings . I would also just keep your web host builder default code if your version is 2.1 or above

Upvotes: 0

Related Questions