I want my .Net Core 5 console application to select settings from the appropriate appsettings file based on the DOTNET_ENVIRONMENT environment variable. I'm testing this by running it in the Visual Studio 2019 debugger and fetching the environment from my launchSettings.json file.
In a .Net Core 5 console application I have 4 "appsettings" files:
Each file Properties is set to Build Action : Content, and Copy to Output Directory: Copy if newer.
In my launchSettings.json I have my environment set to "Staging" like so:
{
"profiles": {
"MyAppName": {
"commandName": "Project",
"dotnetRunMessages": "true",
"environmentVariables": {
"DOTNET_ENVIRONMENT": "Staging"
}
}
}
}
I need access to my configuration in the "Main" method in Program.cs, so in that class I am setting a module-level string variable "_environment" like so in the static constructor:
_environment = Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT");
This works; the value "Staging" gets loaded into the variable _environment.
I then load my Configuration into a static variable like so: (EDIT--this was my mistake, assuming this static property loaded AFTER the static ctor. In fact it loaded BEFORE the static ctor. This meant the _environment variable was not set, which means my environment-specific appsettings file never loaded).
private static IConfiguration Configuration { get; } = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{_environment}.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables()
.Build();
When I then examine the contents of the Configuration, I see that it is only loading values from appsettings.json. It is not loading values from appsettings.Staging.json. The specific value I am looking for is "ConnectionStrings". This is how the ConnectionStrings section looks in appsettings.json:
"ConnectionStrings": {
"ConnectionStringName": "Data Source=SqlDevelopment; Initial Catalog=MyTable; Integrated Security=SSPI;",
}
And this is how that same section looks in appsettings.Staging.json:
"ConnectionStrings": {
"ConnectionStringName": "Data Source=SqlStaging; Initial Catalog=MyTable; Integrated Security=SSPI;",
}
But when I read the DataSource from the Configuration it is always "SqlDevelopment", even though the environment is Staging.
After trying and failing, I tried loading these 4 Nuget packages, but it had no effect:
What am I missing?
Thank you everyone and especially @CodeCaster for helping me.
The issue is that the _environment variable was an empty string when the static Configuration was set. I assumed that since I was setting it in the static constructor it was available, but the static ctor was actually running after I set my static Configuration, so _environment was an empty string, so the "Staging" configuration was never loaded.
I altered the code so that there is no chance that the runtime will set variables in an order that I did not expect:
private static IConfiguration Configuration { get; } = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT")}.json", optional: true, reloadOnChange: true)
.Build();
A number of posters essentially told me "you're doing it wrong." I realize that the runtime provides a dependency-injected Configuration after Host.CreateDefaultBuilder() is called. For reasons outside the scope of this question I happen to need Configuration before that call occurs, inside Program.Main. If I did not need Configuration in Program.Main, before the call to Host.CreateDefaultBuilder, none of this would be necessary.