It is not uncommon for some clients I'm working with to have applications deployed on several environments for which I need to debug an application on different environments. Data is often different on each environment which is great to catch issues before going to production.
Secrets (like API Keys, connections strings ...) cannot be stored in regular "appsettings.json". It is adviced to store them with the "secrets.json" file for development-only purposes.
Nevertheless with several non-production environments switching easily from an environment (or secrets of an environment) to another is not straightforward.
I think it would be great if we could, like with standard appsettings.json and appsettings.Debug.json use environment secrets files like:
secrets.json
secrets.{env}.json
It's done the same way with appsettings.json in method ApplyDefaultAppConfiguration(HostBuilderContext hostingContext, IConfigurationBuilder appConfigBuilder, string[]? args) of file \src\libraries\Microsoft.Extensions.Hosting\src\HostingHostBuilderExtensions.cs.
Due to an issue regarding a circular dependency build issue when adding these new extensions methods I don't have a PR to submit (See Risks).
But preview of the code (and the changes to bring to Microsoft.Extensions.Configuration.UserSecrets) are available as a standalone Nuget package Chrysalit.Extensions.UserSecrets and the source code available on Github.
While Visual Studio does fully integrate the secrets.json file (Manage User Secrets on the project menu in Solution Explorer) opening the default secrets.json file, adding environment secrets may break this integration, or may require some updates accordingly.
An MSBuild solution is proposed as well in the documentation of the Nuget Package Chrysalit.Extensions.UserSecrets to easily access the various secrets for the project directly from the Solution Explorer.
API Proposal
Adding the following extensions methods may help to either:
use the environment defined on the Host
use a custom environment factory to let end-user choose the appropriate environment name
// With the default builder and the .UseEnvironment extension method.
var host = Host.CreateDefaultBuilder(args)
.UseEnvironment("dev")
.ConfigureAppConfiguration((context, config) =>
{
config.AddUserSecrets<Program>(context);
})
.Build();
// with an environment variable DOTNET_ENVIRONMENT = "dev"
var host2 = new HostBuilder()
.ConfigureHostConfiguration(config =>
{
config.AddEnvironmentVariables("DOTNET_");
})
.ConfigureAppConfiguration((context, config) =>
{
config.AddUserSecrets<Program>(context.HostingEnvironment);
})
.Build()
/* with a custom key defined in any configuration file (or elsewhere) and a factory to build the environement value.
appsettings.json
{
"customkey": "dev"
}
*/
var host3 = new HostBuilder()
.ConfigureHostConfiguration(config =>
{
config.AddJsonFile("appsettings.json");
})
.ConfigureAppConfiguration(config) =>
{
confbuilder.AddUserSecrets<Program>(() => config["customkey"]);
})
.Build()
By setting explicitely the environment to "dev", the API would load in order:
the default secrets.json file
a new secrets.dev.json file
Alternative Designs
The dotnet tool user-secrets is misleading. The tool accepts a --configuration parameter but doesn't use it anywhere and update only the file secrets.json. It would be interesting if the tool, when providing a non null configuration, could write to a secrets.{configuration}.json file, while still writing to secrets.json file when the parameter is not explicitely defined on the command-line.
Using this parameter would be fully aligned with the current API proposal.
Risks
While these changes are easy enough to implement, there's a problem on the where should these methods being implemented:
Microsoft.Extensions.Hosting has a dependency on Microsoft.Extensions.Configuration.UserSecrets
These new methods would create a dependency for Microsoft.Extensions.Configuration.UserSecrets on Microsoft.Extensions.Hosting
This leads to a circular dependency build issue.
I don't know where these methods should be implemented.
But Microsoft.Extensions.Hosting uses only one method AddUserSecrets() in file src\libraries\Microsoft.Extensions.Hosting\src\HostingHostBuilderExtensions.cs. But I don't see how this dependency could be reversed.
Propositions regarding this dependency issue;
use the provided external standalone Nuget package
create a new project Microsoft.Extensions.Configuration.UserSecrets.Additions that would enrich the namespace `Microsoft.Extensions.Configuration.UserSecrets with these new extensions methods.
add these new extensions methods in Microsoft.Extensions.Hosting
I don't how a one way dependency of project Microsoft.Extensions.Configuration.UserSecrets with Microsoft.Extensions.Hosting package could be achieved.
Background and motivation
It is not uncommon for some clients I'm working with to have applications deployed on several environments for which I need to debug an application on different environments. Data is often different on each environment which is great to catch issues before going to production. Secrets (like API Keys, connections strings ...) cannot be stored in regular "appsettings.json". It is adviced to store them with the "secrets.json" file for development-only purposes. Nevertheless with several non-production environments switching easily from an environment (or secrets of an environment) to another is not straightforward.
I think it would be great if we could, like with standard
appsettings.json
andappsettings.Debug.json
use environment secrets files like:secrets.json
secrets.{env}.json
It's done the same way with
appsettings.json
in methodApplyDefaultAppConfiguration(HostBuilderContext hostingContext, IConfigurationBuilder appConfigBuilder, string[]? args)
of file\src\libraries\Microsoft.Extensions.Hosting\src\HostingHostBuilderExtensions.cs
.Due to an issue regarding a circular dependency build issue when adding these new extensions methods I don't have a PR to submit (See Risks). But preview of the code (and the changes to bring to
Microsoft.Extensions.Configuration.UserSecrets
) are available as a standalone Nuget package Chrysalit.Extensions.UserSecrets and the source code available on Github.While Visual Studio does fully integrate the
secrets.json
file (Manage User Secrets
on the project menu inSolution Explorer
) opening the defaultsecrets.json
file, adding environment secrets may break this integration, or may require some updates accordingly.An MSBuild solution is proposed as well in the documentation of the Nuget Package Chrysalit.Extensions.UserSecrets to easily access the various
secrets
for the project directly from theSolution Explorer
.API Proposal
Adding the following extensions methods may help to either:
environment
defined on theHost
environment
factory to let end-user choose the appropriateenvironment
nameAPI Usage
By setting explicitely the environment to "dev", the API would load in order:
secrets.json
filesecrets.dev.json
fileAlternative Designs
The dotnet tool
user-secrets
is misleading. The tool accepts a--configuration
parameter but doesn't use it anywhere and update only the filesecrets.json
. It would be interesting if the tool, when providing a non null configuration, could write to asecrets.{configuration}.json
file, while still writing tosecrets.json
file when the parameter is not explicitely defined on the command-line. Using this parameter would be fully aligned with the current API proposal.Risks
While these changes are easy enough to implement, there's a problem on the where should these methods being implemented:
Microsoft.Extensions.Hosting
has a dependency onMicrosoft.Extensions.Configuration.UserSecrets
Microsoft.Extensions.Configuration.UserSecrets
onMicrosoft.Extensions.Hosting
This leads to a circular dependency build issue.
I don't know where these methods should be implemented. But
Microsoft.Extensions.Hosting
uses only one methodAddUserSecrets()
in filesrc\libraries\Microsoft.Extensions.Hosting\src\HostingHostBuilderExtensions.cs
. But I don't see how this dependency could be reversed.Propositions regarding this dependency issue;
`Microsoft.Extensions.Configuration.UserSecrets
with these new extensions methods.Microsoft.Extensions.Hosting
Microsoft.Extensions.Configuration.UserSecrets
withMicrosoft.Extensions.Hosting
package could be achieved.