.NET 7 Environment variables in appsettings.json - c#

In Java, I use a file called application.properties where I can reference environment variables like this
database.url=${DATABASE_URL}
In .NET 7 we use appsettings.json to define configurations for our application.
In my specific case, Azure is going to have all these configurations values stored in a Keyvault that is going to be used as environment variables to my .NET 7 application. I don't know any value that is stored in keyvault so having one appsettings file for each environment with everything in it is not an option.
What I need to have is something similar to what happens in Java, I imagined something like:
appsettings.json:
{
"DatabaseUrl":"${DATABASE_URL}"
}
Is there a way to achieve this? Or maybe another way to replace this config value with the environment variable.

Related

Environment variables in grpc.AspNet core [GRPC_TRACE, GRPC_VERBOSITY]

I'm migrating from grpc.core to Grpc.AspNetCore. I've tried to set enviroment variables to get detailed logs but can't see any difference in the logs. Does Grpc.AspNetCore still uses enviroment variables like GRPC_TRACE or GRPC_VERBOSITY (see here the list of env variables) for logs? How can I set the verbosity of my logs in Grpc.AspNetCore?
For example, I'd like to see logs related to transport_security,tsi. I used to do the following in grpc.core:
$GrpcTrace = "transport_security,tsi"
$GrpcTraceVerbosity = "Debug"
[Environment]::SetEnvironmentVariable("GRPC_VERBOSITY", $GrpcTraceVerbosity, [System.EnvironmentVariableTarget]::Process)
[Environment]::SetEnvironmentVariable("GRPC_TRACE", $GrpcTrace -join ",", [System.EnvironmentVariableTarget]::Process)
I know that Grpc.AspNetCore uses Microsoft.Extensions.Logging for logging, but not sure if this means the env variables are no longer needed.
I think you want the guidance provided here: https://learn.microsoft.com/en-us/aspnet/core/grpc/diagnostics?view=aspnetcore-6.0
Those variables work for a different project, the C-library with a C# wrapper. That C# library is in maintenance mode.

What values should be in appsetting.json?

In the modern .net application there is a default config file - appsettings.json.
From the best practices, what values should I put in this file?
From my understanding, I should keep something that is commonly used by any environment in the system. Am I correct here?
For example, I have a dummy config key that has different values in each of my environments.
I define the value for this key in appsetting.Development.json, appsetting.Production.json, etc. What is the best option for appsetting.json in this case - omit it or provide a fallback value or keep empty?
I believe this page answers your question quite well:
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-6.0
From the page above:
The default JsonConfigurationProvider loads configuration in the following order:
appsettings.json
appsettings.{Environment}.json
For example, the appsettings.Production.json and appsettings.Development.json files. The environment version of the file is loaded based on the IHostingEnvironment.EnvironmentName.
appsettings.{Environment}.json values override keys in appsettings.json.

How can I use a Windows environment variable in my .NET Core API?

We are creating an .NET Core 2.1 application with a Web API project that connects to a SQL Server database.
I am trying to get my head around the proper use of environment variables when it comes storing my connection strings in the most secure location possible.
When I heard that I could use environment variables to store things like a connection string that sounded really good. It is secure and we can have the variables differ from developer to developer and on staging and production environment. Which is useful as they do not all have the same name for their SQL Server instance.
But when I now add a connection string to my Windows environment variables like so:
or through the PowerShell like so:
setx CUSTOMCONNSTR_MyContextDb "Server=.\\MYSQLSERVER;Database=MyDb_local;Trusted_Connection=True;ConnectRetryCount=0"
And I try to get it like so:
var connectionString = Configuration.GetConnectionString("MyContextDb");
But this does not work. The string is null.
I can only get this line of code to work if I add the CUSTOMCONNSTR_MyContextDb variable and the value to the environment variables when I go to the properties of the project and than enter the environment variable there on the Debug tab. Which basically just sets them in the launchSettings.json file. This hardly seems a better location than appsettings.json (or is it?).
Have I misunderstood the use of environment variables in .NET Core? Can I not use the windows-defined environment variables? Or can I only use real Windows environment variables on my IIS server?
It looks like I can, because I see a list of over 80 environment variables when I debug and look at the Configuration object.
For reference, this post with a short YouTube clip helped me to better understand the concepts around this, but I do not fully grasp everything, and I hope you can help.
Configuration.* reads from Application Configuration files. You're looking for
Environment.GetEnvironmentVariable("CUSTOMCONNSTR_MyContextDb")
For the question of "Where should connection strings be stored", is not so easy to answer. It is a bit of an opinion question, and as usual it depends.
If the only bit of configuration data that was expected to change, I would consider sticking to using just the appsettings.json for convenience. If more configuration options were of concern, like running locally and on Azure, I may consider an overriding approach like this. Another consideration would be the number of team members working on the same project. Each might have their own local database instance with different settings. In that case SecretManager might be a good option.
There's lots of tools and methods to the madness, as you've probably seen so far. Unfortunately there isn't a catch-all solution I can recommend above others. I would stick with what you're trying now until it doesn't work.
I don't believe you've misunderstood the concept overall, except "windows defined environment variables" and the other phrase "real environment variables on my IIS server". Windows and IIS are still just software that someone else wrote. They don't have any more or less value than your environment variables.
I've never set the environment variables in the tab you mentioned, so I had no idea that's stored in the launchSettings.json. I'll have to dig more on that later.
The code for the GetConnectionString method looks like this:
public static string GetConnectionString(this IConfiguration configuration, string name)
{
return configuration?.GetSection("ConnectionStrings")?[name];
}
This shows that the connection-string itself must live inside a ConnectionStrings section. As your IConfiguration instance represents what is essentially a dictionary of string to string, this ends up looking for a key named ConnectionStrings:[name].
To resolve the problem with your environment variable not being found, you should name it ConnectionStrings:MyContextDb (you can also use __ instead of :, but : is much more common).
When I first read your question, I was surprised that adding it to the launchSettings.json file made it work, but I've since discovered that this value of CUSTOMCONNSTR_MyContextDb is being converted into ConnectionStrings:MyContextDb for you. You can confirm this by using something like this:
new ConfigurationBuilder()
.AddEnvironmentVariables()
.Build()
.AsEnumerable()
.ToList()
.ForEach(x => Console.WriteLine("{0} => {1}", x.Key, x.Value));
That's just a very cheap and cheerful way of viewing all of the key/value pairs that have been added to an IConfiguration instance.
I think there's a clear misunderstanding of environment variables here.
When talking about the configuration of a single ASP application, especially since Docker is a thing, etc., an environment variable means a configuration variable for that specific application stored in appsettings.json or launchsettings.json.
The Windows environment variables are not meant here and usually are not taken into account for ASP.NET Core applications for quite a few reasons.
Your snippet there:
var connectionString = Configuration.GetConnectionString("MyContextDb");
is explicitly reading data from the "ConnectionString" section in appsettings.json. You can't overwrite that.
The best approach to have "per user" settings is in my eyes to use one global appsettings.json with values valid for all developers/users and every user has its own appsettings_develop.json containing his/her personal connection string and so on. The personal one is added to gitignore and not committed and only living on the user's machine.
I'd advise not to use any environment variables from the host system (your Windows User environment variables there, for example) as you'd need to make sure they exist everywhere you want to use your application, if you put it in Docker the Docker container needs to have them, etc., can't commit environment variables using GitHub or TFS. JSON configurations are your best option I'd say.

c# pattern for two applications sharing a configuration file

I have two applications that have many common configuration properties. When a configuration property of one changes, I want the other to change as well. Does anyone have a sensible way to accomplish this before I start off down the wrong track?
EDIT: I'm using .NET 2.0
You can create and reference a common configSource for the configuration section(s) involved. For instance, if you wanted a common set of AppSettings, copy your current appSettings to a new file (say appSettings.shared.config) and replace them in both app configs with this:
<appSettings configSource="appSettings.shared.config"/>
Here's more documentation: http://sunali.com/2008/01/23/configsource-property-dividing-configuration-files-into-pieces/
Far as I know, this cannot be done for an entire file, only sections, and each section will need its own file (and the section must still be declared in the configurationsections element of the app.config). But, this has a number of really cool uses; for instance, you can separate your connection strings into files geared towards different environments (local, development, testing, staging, production) and by changing one filename in one place you've now pointed your app at the different environment.
One easy way to accomplish this is to use the configSource attribute in the app.config in both applications, and point this to a common file. Bingo, change one file, all apps are updated.
Check the MSDN documentation on it here.
there are a couple of different ways you could do this:
use the registry
use a config file in a common location
use a configuration table in a database

ConfigurationSettings vs Properties.Settings

I have a Winform app that has 16 SQL Connections currently stored in the DAL Projects Settings.settings.
I am trying to write a "Manager" class to simplify this(like here). However, most of the examples I find on the web seem to use ConfigurationSettings.AppSettings["something"]. While, I WAS using Properties.Settings.Default.something.
Can someone, please, explain which is considered CORRECT and why for a Desktop applications?
I think the correct way is to use the app.config file and store them in the connectionStrings section?
Then you can access them like:
ConfigurationManager.ConnectionStrings["something"].ConnectionString
You could write a wrapper around that easily if that is too "ugly".
public class ConnectionManager
{
public string Something
{
get
{
// TODO: check to make sure the configuration exists and throw an exception perhaps
return ConfigurationManager.ConnectionStrings["something"].ConnectionString;
}
}
}
Oops...as pointed out I meant to do ConfigurationManager and not ConfigurationSettings.
I've never been a big fan of putting sql connection strings into configuration files for software. Users have a habit of goofing them up out of curiosity or stupidity (or some combination of the two). I like to put all of my connection strings (development, model, production, whatever) into the Properties of my data access library, and include within it a ConfigurationSettings class that I use to access them based on some property that is set by the consuming application:
public class ConfigurationSettings
{
public static string MyConnectionString
{
get
if(ConfigurationSettings.TestMode)
return Properties.Settings.Default.MyConnectionStringTest;
else
return Properties.Settings.Default.MyConnectionStringProd;
}
}
// I typically only have test and not-test. This could
// easily be some other combination of values to satisfy
// multiple environments.
public static bool TestMode { get; private set;}
}
This allows me to call the static properties of this class through a common name and have all connection strings available depending on some criteria. This gets your specific datasets, entities, whatever data model you're using from being in the business of worrying about connection strings and the settings can be compiled into the .dll (and no longer need to worry about them). This method can also be modified to pull settings from an app.config (which I do for ASP.Net sites) in a similar method.
UPDATE: There really is no "correct" way as you imply. The app.config was designed to hold configuration settings that are modifiable without rebuilding the application. Property Settings were designed to hold settings that are not modifiable. So both are perfectly valid. Probably the most "correct" way is a way that makes sense both for your application and for your development team.
We prefer to use Properties.Settings (aka. settings.settings) because it's strongly typed. Don't try to do fancy tricks that have different environments (dev/prod) in the same config file. It is much easier to have a separate config file per environment, and to rename the configs when you deploy them. i.e.
app.config
app.stage.config
app.test.config
app.prod.config
We use PowerShell scripts (batch files on steroids) to do our deployments. I'll simplify what we do as a traditional batch file - (pseudo code/untested sample):
#echo off
:: %1 is the environment name (first parameter)
setlocal
set source=c:\tfs\project\bin\release\
set target=\\server\share\path\
xcopy /s/e %source% %target%
:: Using a copy command to rename/overwrite the env specific version
if exists %target%\app.%1.config copy /y %target%\app.%1.config %target%\app.config
Properties.Settings.Default are generally used to save application internal state like the color of the background, to remember user settings.
ConfigurationSettings is actually the "Manager" class you were talking about and can access other custom sets of settings from the app.config file, including connection strings.

Categories

Resources