Configuration in .NET Core
Setting up
From the beginning of .NET we used web.config or app.config files for application configuration. When you’re create new ASP.NET Core project you’ll no longer find those files, instead you’ll have appsettings.json file and in Startup class constructor you’ll find setup of it:
public Startup(IHostingEnvironment env) { var builder = new ConfigurationBuilder() .SetBasePath(env.ContentRootPath) .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true); if (env.IsDevelopment()) { // For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709 builder.AddUserSecrets<Startup>(); } builder.AddEnvironmentVariables(); Configuration = builder.Build(); }
This configuration tells us to search for settings file in main application directory (env.ContentRootPath), use appsettings.json file, that must exist (optional: false) and reload whole application, when it’s changed (reloadOnChange: true – available in .NET Core 1.1). Later in the file we have line AddJsonFile($”appsettings.{env.EnvironmentName}.json”, optional: true); which allows us to create settings for each environment, similar how we done it with web.config transformats. To enable this option we also need to run function builder.AddEnvironmentVariables(); as its done at the end of method. With this approach we just replace standard config with new values for other environment. Order matters here, the latter have higer priority. More about environments here.
Also in this method, we have call to AddUserSecrets, which will be covered later and at the end, we call Build() method to create Configuration object.
When it comes to this solution – you’ll also have to include as dependencies:
- Microsoft.Extensions.Configuration
- Microsoft.Extensions.Configuration.Json
Accessing configuration
Ok, we know how to set up configuration mechanism, but how to get saved settings? The simplest solution is to access them directly. To do that first you need to register in DI container Configuration class created in previously as an instance of IConfigurationRoot and then in a controller or other class resolve it and access as indexer – configurationRoot[“key”].
Apart from that, we have a more sophisticated mechanism – Options, which allows us to map settings into custom classes and use it from dependency injection container. First, we need to create simple POCO class representing options, property names represent configuration keys:
public class SimpleOptions { public string Setting { get; set; } }
Then we register it in DI container:
services.Configure<SimpleOptions>(Configuration);
And resolve later in code:
public HomeController(IOptions<SimpleOptions> options) { Console.WriteLine(options.Setting); }
Secret manager
One of the standard problems when developing any website or other types of applications is where to store secret application settings like credentials, api keys or most commonly – connection strings. This issue is really important for open source projects, as their code and configuration are publicly available. There are solutions for this like Azure Key Value or Lockbox (created by Piotr Gankiewicz, winner of previous Get Noticed competition). Microsoft with new .NET Core provided us with another solution – Secret Manager – which stores configuration on a local machine. A downside to that – these settings aren’t encrypted, but for simple purposes, it’s more than sufficient.
To install it, you need to add Microsoft.Extensions.SecretManager.Tools to project references, but you need to do it manually as it won’t work from Visual Studio manage NuGet packages wizard because it isn’t a standard .NET package, it’s treated as a tool:
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="1.1.0" /> <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="1.1.0-msbuild3-final" PrivateAssets="All" /> <PackageReference Include="RestEase" Version="1.3.2" /> </ItemGroup> <ItemGroup> <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="1.0.0-msbuild3-final" /> <DotNetCliToolReference Include="Microsoft.Extensions.SecretManager.Tools" Version="1.0.0-msbuild3-final" /> <DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="1.0.0-msbuild3-final" /> <DotNetCliToolReference Include="Microsoft.Extensions.SecretManager.Tools" Version="1.0.0-msbuild3-final" /> </ItemGroup>
Apart from that, you need to have unique project id generated, so it can be distinguished between various projects. To do that you need to add to csproj file property UserSecretsId, it’s added automatically if you’re using project creator:
<PropertyGroup> <UserSecretsId>aspnet-TeamScreen-202d60c9-e8ec-456f-ba84-b20a344ef576</UserSecretsId> </PropertyGroup>
After that, you need to run dotnet restore command. At the end run command dotnet user-secrets -h to check if it’s working properly. If you using Package Manager Console and got an error – No executable found matching command “dotnet-user-secrets” – you need to enter directory where csproj file resides – cd Dir_With_csproj and try again.
When everything is ok, it’s time to add some actual settings. To do that we use command dotnet user-secrets set MySecret ValueOfMySecret and to check if it’s working we call command dotnet user-secrets list to display all saved secrets. In application, we need to have reference to Microsoft.Extensions.Configuration.UserSecrets and in Startup class call method builder.AddUserSecrets(); To access saved settings, we use the same methods described previously.
We can also access file with saved secrets on disk, based on operating system secrets reside in:
- Windows: %APPDATA%\microsoft\UserSecrets\\secrets.json
- Linux: ~/.microsoft/usersecrets//secrets.json
- Mac: ~/.microsoft/usersecrets//secrets.json
Other things to consider:
- By default, you can only read from configuration, to save you have to create custom configuration provider
- Configuration keys are case insensitive
- From .NET Core 1.1 you have OptionsSnapshot mechanism to track changing configuration
- You’re not limited to saving configuration in appsettings.json file, you can use:
- Other file formats (INI and XML)
- Command-line arguments
- Environment variables
- In-memory .NET objects
- Azure Key Vault
- Custom providers, which you install or create
TeamScreen usage
As you can see, it’s very powerful mechanism, much more sophisticated than web.config was. How do I plan to use it TeamScreen project? Most of all I need to safely store urls and credentials that allow me to access TeamCity, JIRA and other services, so I’ll add those settings to appsettings.json file, enable secret store mechanism and use DI injection to pass them to appropriate controllers. As I described in project introduction, in future most likely I’ll use database for storing such things, so for now, I plan to use the simplest mechanism – accessing settings using IConfigurationRoot interface. You can check actual usage in github source. For now, thanks for reading and I hope to see you here next time 🙂
2 thoughts on “Configuration in .NET Core”
Thanks a lot for this article. You just saved my day. Plus ‘ dotnet restore’ will not work for dotnet SDK less than Preview 3.
Happy to help 🙂 Good to know about dotnet restore issue 🙂