Is there a way "out of the box" to have environment variables in appsettings.json
values expanded automatically?
To take a contrived example:
{
...
"MyPath1": "C:/MyApp/%ENV%/Myfolder1/MyFile1.dat",
"MyConnectionString": "Server=MyServer%ENV%..."
...
}
My objective is to be able to switch my environment by changing a single environment variable, and have it affect multiple appsetting values, rather than having per-environment configuration files.
UPDATE
I've looked through the source code of JsonConfigurationProvider and as far as I can see there is no such feature out of the box.
I can see that it should be possible by deriving a custom class from JsonConfigurationProvider
and overriding the Load()
method:
public override void Load()
{
base.Load();
foreach(var key in Data.Keys)
{
Data[key] = Environment.ExpandEnvironmentVariables(key);
}
}
But I'm quite new to .NET Core configuration, which leads to a second question:
How do I get this custom implementation to replace the standard one? I.e. to remove the default appsettings.json and appsettings.environment.json providers and replace by the custom one. Presumably something to be added in Program.cs
:
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.ConfigureAppConfiguration(config =>
{
config.??? what do I need here?
}
);
NET Core and as far as I see from my search on the web, appsettings.Development. json is used for development config while developing the app and appsettings. Production. json is used on the published app in production server.
Of course, we can add and use multiple appsettings. json files in ASP.NET Core project. To configure and read data from your custom json files, you can refer to the following code snippet.
To create and use a custom configuration source, two implementations are needed:
IConfigurationSource
IConfigurationProvider
It's the IConfigurationSource
implementation that gets added to the IConfigurationBuilder
's sources. This implementation is also responsible for creating its own IConfigurationProvider
, which is reponsible for loading the data from the source.
Here's both a custom implementation of IConfigurationSource
(ExpandJsonConfigurationSource
) and IConfigurationProvider
(ExpandJsonConfigurationProvider
):
public class ExpandJsonConfigurationSource : JsonConfigurationSource
{
public override IConfigurationProvider Build(IConfigurationBuilder builder)
{
EnsureDefaults(builder);
return new ExpandJsonConfigurationProvider(this);
}
}
public class ExpandJsonConfigurationProvider : JsonConfigurationProvider
{
public ExpandJsonConfigurationProvider(ExpandJsonConfigurationSource source)
: base(source) { }
public override void Load()
{
base.Load();
Data = Data.ToDictionary(
x => x.Key,
x => Environment.ExpandEnvironmentVariables(x.Value),
StringComparer.OrdinalIgnoreCase);
}
}
There's not a lot going on here. These implementations just follow the same approach as the existing JsonConfigurationSource
and JsonConfigurationProvider
implementations, with custom processing for expanding the environment variables.
To replace the preconfigured JSON-based sources, use the following:
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.ConfigureAppConfiguration((ctx, builder) =>
{
var jsonConfigurationSources = builder.Sources
.OfType<JsonConfigurationSource>()
.ToList();
foreach (var jsonConfigurationSource in jsonConfigurationSources)
{
var indexOfJsonConfigurationSource = builder.Sources
.IndexOf(jsonConfigurationSource);
builder.Sources.RemoveAt(indexOfJsonConfigurationSource);
builder.Sources.Insert(
indexOfJsonConfigurationSource,
new ExpandJsonConfigurationSource
{
FileProvider = jsonConfigurationSource.FileProvider,
Path = jsonConfigurationSource.Path,
Optional = jsonConfigurationSource.Optional,
ReloadOnChange = jsonConfigurationSource.ReloadOnChange
});
}
});
The delegate passed in to ConfigureAppConfiguration
does the following:
JsonConfigurationSource
. There should be two instances: for appsettings.json
and for e.g. appsettings.Development.json
.ExpandJsonConfigurationSource
, copying across the properties to ensure it has the same path, optional flag, etc.I created a library to perform variable substitution, it substitutes from any configuration source, not just environment variables. See: https://github.com/molinch/ConfigurationSubstitutor
You just need to register it as another configuration source, this is done by calling .EnableSubstitutions()
on the ConfigurationBuilder.
With your example:
"MyPath": "C:/MyApp/%ENV%/Myfolder1/MyFile1.dat"
ENV = Foo
.EnableSubstitutions("%", "%")
Finally when requesting MyPath from the configuration you will get: C:/MyApp/Foo/Myfolder1/MyFile1.dat
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With