How can appSettings.{environment}.json be loaded before environment is known? (AspNetCore) - asp.net-core

According to microsoft blog the ASPNETCORE_ENVIRONMENT variable is loaded in order:
appsettings.json file
appsettings.{env.EnvironmentName}.json file
The local User Secrets File
Environment Variables
Command Line Arguments (or equivalently launchSettings.json)
and "The last key loaded wins".
Questions:
But how can the file appsettings.{env.EnvironmentName}.json be loaded before the final Environment is known?
Can it happen that I set 'Staging' environment through command-line and appSettings.Development.json is loaded because during step 2 it is not yet known?

There are two sets of configuration for an ASP.NET Core application:
The configuration for the WebHost.
The configuration for the application itself.
First the WebHost configuration is built (source):
_config = new ConfigurationBuilder()
.AddEnvironmentVariables(prefix: "ASPNETCORE_")
.Build();
As the source code shows, the configuration for the WebHost uses only environment variables and only those that are prefixed with ASPNETCORE_. One of those environment variables is, unsurprisingly, ASPNETCORE_ENVIRONMENT.
A little later down the line, an implementation of IHostingEnvironment is instantiated. This ends up using _config to retrieve a configuration setting named environment, which comes from the ASPNETCORE_ENVIRONMENT variable. If there is no such value, it defaults to Production.
Next up, the configuration for the application itself gets built. At step 2 in your question, the value of env.EnvironmentName is from the IHostingEnvironment I've already mentioned. If you were to set an environment value of e.g. Staging as a command-line argument, it would not change the value used in the WebHost configuration, as this applies only to the application configuration.
Andew Lock goes into more detail about how this all works and also demonstrates how to configure the WebHost to use additional configuration sources.

Related

user secrets file gets ignored in asp.net core 6

I have two projects targeted .net 6 and there are no any explicit declarations for using user secrets (I remember, it was required in previous versions to use AddUserSecrets()). Though, one project gets the right config from secrets.json, but another one - tries to get it from appsettings.json.
So, I'm wondering, what's the issue? How the behavior was changed in .net 6?
In .Net6, WebApplication.CreateBuilder initializes a new instance of the WebApplicationBuilder class with preconfigured defaults. The initialized WebApplicationBuilder (builder) provides default configuration and calls AddUserSecrets when the EnvironmentName is Development.
As long as you initialize your web application using the WebHost.CreateDefaultBuilder method, ASP.NET Core automatically picks up your configuration from the secrets.json file in .Net6. If you initialize your application manually or not .Net6, make sure to call the AddUserSecrets-method.
refer to this

.NET Core 2.2 API on IIS returns error if it attempts to connect to Db but otherwise works fine

When I publish my .NET core app to a development IIS server, I make a call to the API and the method works fine locally. This method makes a Db call using a connection string stored in
appSettings.json as well as appSettings.Development.json
Observations:
- Yes, I have ASPNETCORE_ENVIRONMENT = Development and I have both an appSettings.json file AND appSettings.Development.json file
- So I started looking at the published files and I had BOTH of these json files in the published folder, even though appSettings.Development.json properties is set to "Build Action" = content and Copy to Output Directory = Do Not Copy
- If I comment out the code that his the Db, and return dummy data, and republish the api, i get the results fine with no complaints about "development mode"
Error I get when calling the API trying to hit the Db
Error.
An error occurred while processing your request.
Request ID:
0HLL1GOCEHH73:00000001
Development Mode
Swapping to the
Development environment displays detailed information about the error that occurred.
The Development environment shouldn't be enabled for deployed applications.
It can result in displaying sensitive information from exceptions to end users.
For local debugging, enable the
Development environment by setting the
ASPNETCORE_ENVIRONMENT environment variable to
Development
and restarting the app.
Questions:
- The Db connection strings are in both
[ update ]
Brain-fart! The db connection strings were using 'trusted', so no wonder they worked locally! Once I put in the credentials, and re-published, things worked like I expected. However, the error message threw me off.
Im still not sure why I have both of those appSettings files published? Which one will it use?
I am assuming your appsetting files are named as following:
appSettings.json
appSettings.dev.json
typically, you have to explicitly set the environment to dev. if you use Visual Studio for development, it sets an environment variable that tells the application to put it in dev mode.
Without seeing the initializing logic, I would say in prod it will use the appSettings.json.
Take a look at this article, it explains configuration in more details.

Azure web app for containers (aspnetcore 2.2) not reading azure appsettings values on startup

I've got a webapp for containers running in Azure that I have working locally with a local appsettings file.
once I deploy to Azure, I want the container to pull appsettings values from the azure settings. These are set via AzureDevops and appear correctly when I check the portal.
However, the site is not pulling the appsettings values from Azure once deployed. It is using the ones from the file. I am using the double-underscore names as specified.
I have created a testcontroller to output the appsettings values. This is an a snippet of what the test view outputs:
Build version: 2019.1.23.1
Location: local
Database__DatabaseConnectionString: Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=application;Data Source=.
---
-------
Env vars: Key WEBSITE_AUTH_SIGNING_KEY Value ASDS*(&*&*(SDSD05C29
Key DOTNET_RUNNING_IN_CONTAINER Value true
Key WEBSITE_ROLE_INSTANCE_ID Value 0
Key Database__DatabaseConnectionString Value Server=tcp:servername01.database.windows.net,1433;Initial Catalog=application;Persist Security Info=False;User ID=applicationUser;Password=password;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;
Key APPSETTING_Database__DatabaseConnectionString Value Server=tcp:servername01.database.windows.net,1433;Initial Catalog=application;Persist Security Info=False;User ID=applicationUser;Password=password;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;
As can be seen, the Database__DatabaseConnectionString should be consumed by the app. But it's not being.
What could be the problem here? This should be standard functionality according to the aspnetcore documentation.
Turns out this was a bug in the application. The controllers in question has an injected IOptions being injected into the constructor. Unfortunately, one of the controllers had different behaviour as a concrete instance was being inject in instead. As this object was not being correctly initialised in Startup.cs, this has the effect of passing empty values into the constructor.
Finally as empty values were found, this mean the default appsettings.json values were used.
Having fixed this above bug (by ensuring all controller use the same IOptions values), the azure appsettings values are being picked up and used correctly by the application at startup time.

How to have a config file for local development and one for the development server in AspNet Core without breaking the IsDevelopment function logic

With AspNet Core, I would like to have a different config value when I develop a web site on my local computer and when the web site is published on the development server.
For exemple, on my computer, the log files use the path "..\..\logs\app.log" and on the development server it's "w:\logs\app.log". Since that by default, AspNet Core is using the appsettings.Development.json file wherever I'm on my development computer or on the development server, I cannot set the path differently.
So how can I distinguish when the code run on my local computer and when it run on my development server and have a different settings in my appsettings.json files and still use env.IsDevelopment() that will return true on both environment? The reason I need that is because Microsoft use the IsDevelopment() function in there own logic and I don't want to break that.
.NET Core solves this problem by using "Environments".
It's kind of evolved over the versions so it's a little different depending on which version of .NET Core you are actually using. But in short, your code will typically load appsettings.json first, then overwrite any settings from a file called :
appsettings.{env.EnvironmentName}.json
Notice how the Environment is suffixed to your appSettings. To set the environment for your machine, if you are on Windows you can run a powershell command like :
$Env:ASPNETCORE_ENVIRONMENT = "Development"
Or have a quick google around "How to set environment variables". As long as the key is "ASPNETCORE_ENVIRONMENT", then whatever you set it to, you can then load that file as your settings.
More info : https://dotnetcoretutorials.com/2017/05/03/environments-asp-net-core/
From your description, I understood that you want to keep single Config file. If that is the case, you can alter your configuration setting on server side using environment variables.
Logging__logPath=C:\dir\file.log
this link may help you https://medium.com/thirddev/overriding-configuration-using-environmental-variables-in-asp-net-core-d38079475654
If your server is hosted on IIS then you can change your environment variables under Configuration Editor. Here is the step by step instructions
Go to your application in IIS and choose Configuration Editor.
Select Configuration Editor
Choose system.webServer/aspNetCore (RC2 and RTM) or system.webServer/httpPlatform (RC1) in Section combobox
Choose Applicationhost.config ... in From combobox.
Click on enviromentVariables element and open edit window.
Set your environment variables.
Close the window and click Apply. Done
REF: https://stackoverflow.com/a/36836533/1118978
Visal demonstration:
https://www.andrecarlucci.com/en/setting-environment-variables-for-asp-net-core-when-publishing-on-iis/
If you prefer to have multiple config files, then :
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();
}
and environment variable is needed to be set ASPNETCORE_ENVIRONMENT=DevServer and your config file will be appsettings.DevServer.json

Which values does WebHost read from appsettings.json

In .Net Core you can self host a web server using WebHost. There is a method called CreateDefaultBuilder(), to which the Microsoft documentation states the following:
CreateDefaultBuilder performs the following tasks:
Loads app configuration from:
appsettings.json.
However, there doesn't seem to be any documentation on which parameters you can put into appsettings.json to have the WebHost automatically get configuration values other than the default values.
For example, I tried adding the following to my appsettings.json, but the server is started with http://localhost:5000 regardless:
{
"Kestrel" : {
"urls" : "http://*:8080"
},
"server" : {
"urls" : "http://*:8080"
}
}
I know I can read appsettings.json myself using ConfigurationBuilder, but that sort of defeats the purpose of the documentation
So, what do I need to put into my appsettings.json file to have CreateDefaultBuilder() not use the default values? A list of all possible values to put into appsettings.json would be welcome as well.
Why does CreateDefaultBuilder not configure the host with appsettings.json values?
Part of the answer is to distinguish between host and app configuration. The documentation says that CreateDefaultBuilder...
Loads host configuration from:
Environment variables prefixed with ASPNETCORE_ ...
Command-line arguments.
Loads app configuration from:
appsettings.json.
appsettings.{Environment}.json.
From within CreateDefaultBuilder, the reason that appsettings.json does not automatically affect the host, is that those settings are configuring the app, and the app config does not affect the host config. The documentation indicates that when it says:
IWebHostBuilder configuration is added to the app's configuration, but the converse isn't true — ConfigureAppConfiguration doesn't affect the IWebHostBuilder configuration.
Looking at the source code shows that the CreateDefaultBuilder method only adds the appsettings.json values from within its call to ConfigureAppConfiguration. That is why those values are not automatically impacting the host.
How can we configure the host with values from a *.json file?
CreateDefaultBuilder does not automatically configure the host with a *.json file. We need to do that manually, and the documentation specifies how. In the example the file is named hostsettings.json, and the example adds it explicitly like this:
var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("hostsettings.json")
.Build();
return WebHost.CreateDefaultBuilder(args)
// this impacts *both* host and app config
.UseConfiguration(config)
.UseStartup<Startup>();
There is no magic in the name hostsettings.json. In fact, we could combine our host settings and our app settings into one file named appsettings.json. The way CreateDefaultBuilder works encourages us to keep those settings somewhat separate.
What keys can we put in a *.json file to configure the host?
This is the list of keys that we can use to configure the host:
"applicationName"
"startupAssembly"
"hostingStartupAssemblies"
"hostingStartupExcludeAssemblies"
"detailedErrors"
"environment"
"webroot"
"captureStartupErrors"
"urls"
"contentRoot"
"preferHostingUrls"
"preventHostingStartup"
"suppressStatusMessages"
"shutdownTimeoutSeconds"