An Introduction to ASP.NET’s Configuration System – Part 1

If you are just starting your explorations in ASP.NET, you’ll inevitably come across a situation where you’ll need to connect to a database… or maybe it is a third-party API. Perhaps you’ll need to fire off an email and you need to connect to a mail server. In these situations, you may initially opt to save the connection information directly in your C# code but there are some issues with this approach that you should consider:

  • Hard-coding secrets – API keys, usernames, passwords, etc. within source code is a big no-no. Such sensitive information will inevitably end up on GitHub or whatever source control system that you are using and available for all to see.
  • You may have to connect to different systems in different environments. For example, you may need to connect to a test database server during development and testing and may need to connect to an entirely different system in production.

Thankfully, dotnet provides a very capable and flexible configuration system that will allow you to separate this environment-specific and/or secret information from your source code in an elegant fashion. Let’s look at how we can set it up and use it.

Configuration Providers

ASP.NET Configuration System provides you with a wide variety of options in terms of storing your configuration values and retrieve them during runtime:

Command-Line Arguments

Not sure how valuable these are in a production scenario, but you can certainly start up your dotnet app from the command line with one or more configuration parameters included in the command. Consider this simple dotnet app that echoes out a configuration item named MySecret:

var builder = WebApplication.CreateBuilder(args);
var mySecret = builder.Configuration.GetValue<string>("MySecret");
Console.WriteLine($"MySecret: {mySecret}");

var app = builder.Build();

app.MapGet("/", () => "Hello World!");

app.Run();

Now, let’s run this app from the terminal, passing the config parameter along with the run command: dotnet run MySecret="Hello World"

The app will produce the following output:

Terminal showing the output of the above program.  It displays the output of the MySecret configuration value which it sourced from the startup command argument.

Environment Variables

Your ASP.NET app is capable of reading environment variables, as well. Try it out by setting a new environment variable:

export SecretKey="Hello from Environment"

If you’re on Windows, enter set SecretKey="Hello from Environment" command from the cmd command-line window, instead.

Now, run the app above again but this time just do dotnet run without any additional arguments. You should see the following output:

Mac bash terminal window showing the setting of an environment variable and that value being output by the demo ASP.NET application.

Secret Manager

Another configuration provider that you find in dotnet is the Secrets Manager. Unlike the others, this approach is meant for local development, only. Although you can set this up manually, the easiest way to do this via the dotnet cli (or by utilizing the tooling in Visual Studio). Since not everyone is using Visual Studio, I’ll go over the CLI approach today. If you’re following along, navigate to the directory where you have the simple demo application from above, stored. Issue the following command to have dotnet setup a secrets.json file for this project:

dotnet user-secrets init

When you run this command, dotnet does two things behind the scenes to setup your project with Secret Manager:

Firstly, it generates a random/unique UserSecretsId for your project and saves it within your .csproj file. Open your csproj file in a text editor and you’ll see something like below:

csproj file in a text editor with the usersecretsid highlighted.

Secondly, it created a secrets.json file in a location outside your project directory. This is intentional and by design. By creating it outside your project directory, you mitigate the risk of accidentally committing this secrets file (with potential sensitive information) into your source control repository. By default, this file is stored in ~/.microsoft/usersecrets/<user_secrets_id>/secrets.json on a Linux or Mac machine. On Windows, you can find this file at %APPDATA%\Microsoft\UserSecrets\<user_secrets_id>\secrets.json.

You can certainly navigate to this file and create your json structure that you can then pull in during the running of your application. Alternatively, you can use the dotnet cli to add/remove/update secrets.

dotnet user-secrets list | remove | set "MySecret" "Hello from secrets.json"

Run your app again. It should display output similar to this:

terminal output showing the setting of a user-secret but the configuration output is instead displaying the environment variable value from the previous example.

But wait a minute! That didn’t work. Instead of the app picking up the value from your secrets.json file, it instead displayed the value of the Environment Variable with the same MySecret name from the previous example! This demonstrates another important aspect of ASP.NET’s configuration system: It harvests configuration information from all different configuration sources. You do not have to stick to a single configuration source for a given application. But as demonstrated in the example above, there is a default order of precedence. Here they are from the highest priority to the lowest:

  • Command line
  • Environment Variables
  • Secrets.json
  • appsettings.Environment.json
  • appsettings.json

So, based on this order of precedence, my “MySecret” environment variable trumped the “MySecret” secrets.json value that I had set. Go ahead and remove that environment variable and run the app again.

terminal window output showing the unsetting of the MySecret environment variable and the asp.net output now showing the secrets.json output instead

This time, it pulled the configuration value from the secrets.json file.

appsettings.json and appsettings.environment.json

You can add these files to your project and ASP.NET will harvest values from within them, as well. They work identical to a secrets.json file. But note that a plain-old appsettings.json will have lesser priority than an environment specific appsettings.json file. For instance, if your application is running in the “production” environment, an appsettings.production.json file will take precedence over a regular appsettings.json file. But how does ASP.NET know what environment your app is in? What are the distinct types of environment specifications available?

Your ASP.NET application determines the particular environment context it is running under by either the DOTNET_ENVIRONMENT or the ASPNETCORE_ENVIRONMENT environment variables. In a web context, the latter takes precedence. If these variables have not been set, the app will default to Production. The framework provides three environments out of the box: Development, Staging and Production. However, you can have as many environment specifications as needed as you can manually check and compare them during runtime.

Closing Remarks

We have barely scratched the surface of dotnet’s configuration system. In upcoming episodes, we can look at how we change some of the defaults, how to save complex and hierarchical data in configuration, how to add type-safety and other related aspects of this system. Stay tuned.

Leave a Comment

Your email address will not be published. Required fields are marked *