In the world of software development, managing configuration settings is a critical aspect of building robust and scalable applications. The .NET Core framework provides powerful tools and mechanisms to handle various configuration settings, making it easier for developers to securely store sensitive and non-sensitive information. In this blog post, we will delve into the concept of configuration settings in .NET Core, explore the mechanisms and patterns used for this purpose, and guide you on the path to becoming a configuration settings maestro.
Before we dive into the intricacies of configuration settings, let’s understand why they are essential. Configuration settings are the parameters and values that dictate how your application behaves. They encompass a wide range of information, from database connection strings and API keys to application-specific settings like the number of threads for parallel processing or feature flags. The ability to adjust these settings without changing the code allows for flexibility, scalability, and enhanced security.
In a .NET Core application, configuration settings can be used to control application behavior, manage external service integrations, and store sensitive data such as connection strings, secrets, and authentication tokens. But how do you effectively manage and access these settings? That’s where the magic of .NET Core’s configuration system comes into play.
Mechanisms for Configuration Settings
Now, let’s explore the mechanisms for working with configuration settings in .NET Core.
JSON Configuration Files
JSON files are a popular choice for storing configuration settings in .NET Core. These files can be organized into sections, making it easy to structure your settings. Here’s an example of a JSON configuration file:
ways to get the Key-Value pairs in the c# code:
Using the app.configuration() method we can get the key values in the program.cs file like
app.UseEndpoints(endpoints => {
endpoints.Map("/", async context =>
{
await context.Response.WriteAsync(app.Configuration.GetValue<string>("Key") + "\n");
});
});
By using Iconfiguration inside the controller :
public class HomeController : Controller
{
//private field
private readonly IConfiguration _configuration;
//constructor
public HomeController(IConfiguration configuration)
{
_configuration = configuration;
}
[Route("/")]
public IActionResult Index()
{
//Hierarchical Configuration
//var getConnection= _configuration.GetSection("DBConnection");
//getConnection["ConnectionString"]
ViewBag.MyKey = _configuration["Key"];
ViewBag.MyAPIKey = _configuration.GetValue("APIKey", "the default key");
return View();
}
}
Using the options pattern, we can tie the JSON setting to the class model: Assume we have an API client ID and client secret in the appsettings.These values are bound to a class in the JSON file and then used as follows:
Options pattern (strongly typed)uses custom classes to specify what configuration settings are to be loaded into properties.
//appsetting.json
{
"apiValues":
{
"ClientID": "",
"ClientSecret":""
}
}
public class ApiOptions
{
public string? ClientID { get; set; }
public string? ClientSecret { get; set; }
}
// inside the action method
[Route("/")]
public IActionResult Index()
{
ApiOptions options = new ApiOptions();
_configuration.GetSection("apiValues").Bind(options);
ViewBag.ClientID = options.ClientID;
ViewBag.ClientSecret = options.ClientSecret;
return View();
}
Configuration as a service — instead of getting the values every time in each controller we can use the configuration as a service which is injected into any controller to get the key value fields :
//add this in program.cs file
builder.Services.Configure<ApiOptions>(builder.Configuration.GetSection("apiValues"));
//in controller class
public class HomeController : Controller
{
//private field
private readonly ApiOptions _options;
//constructor
public HomeController(IOptions<ApiOptions> apiOptions)
{
_options = apiOptions.Value;
}
[Route("/")]
public IActionResult Index()
{
ViewBag.ClientID = _options.ClientID;
ViewBag.ClientSecret = _options.ClientSecret;
return View();
}
}
Environment Specific Configuration
Order of Precedence of Configuration Sources
First, the key-value pairs in the appsettings.json are checked, If they are found, they are returned; if they are not found, they are searched in the following section, appsettingsEnvironment.json file. This environment will be located in the launchsettings.json file under the properties folder, the Precedence will function similarly to the values found in the most recent settings they are only fetched.
User Secrets
User secrets are a convenient way to store development-specific settings that should not be included in version control. You can use the dotnet user-secrets
command to manage these secrets at the user level. For example, you can store a database connection string as a user secret:
If you want to store the keys that are outside the source control the user-secrets is the best place to configure it, the user-secrets are stored on the developer machine, and the secret key is created for this configuration.
Run the command: dotnet user-secret init
you can see the <UserSecretId> per developer machine is created, in order to add the new keys inside this secrets.json :
cmd: dotnet user-secrets set “FirstKey” “FirstValue”
To view the newly added secret keys right-click on the project and goto Manage secrets then the secrets.json file will be opened :
Environment Variables
Environment variables are an excellent choice for storing sensitive information because they can be securely managed at the system level. .NET Core allows you to load environment variables directly into your configuration: In the prod environment we don’t get any visual studio there to configure the values only the Terminal will be available, we can set configuration values as in-process environment variables.
$Env:ParentKey__ChildKey="value"
dotnet run --no-launch-profile
//__ (underscore and underscore) is the separator between parent key and child key.
Custom Json Configuration
We can also add custom JSON files to contain the key-value pairs; this was utilized in large-scale projects where a lot of configuration needed to be preserved; in this idea, the custom JSON file is bonded to the model class.
builder.Host.ConfigureAppConfiguration( (hostingContext, config) => {
config.AddJsonFile("filename.json", optional: true, reloadOnChange: true);
});
Azure Key Vault
When working with sensitive data in a secure way, Azure Key Vault is a popular choice. .NET Core provides an Azure Key Vault configuration provider, allowing you to fetch secrets and configuration settings from Azure Key Vault securely. This is ideal for managing production secrets and certificates.
var azureKeyVaultEndpoint = "https://your-key-vault.vault.azure.net/";
var configuration = new ConfigurationBuilder()
.AddAzureKeyVault(azureKeyVaultEndpoint)
.Build();
Configuring your .NET Core application effectively is a crucial aspect of software development. With the powerful configuration system provided by .NET Core, you can easily manage settings, both sensitive and non-sensitive, to build robust and flexible applications. By following best practices and patterns, such as strongly typed configuration and secrets management, you can ensure your application is secure and scalable.
In a world where data security is paramount, .NET Core’s configuration management capabilities empower developers to navigate the complexities of sensitive information confidently. Whether you’re safeguarding API keys, managing database connections, or fine-tuning application behavior, a deep understanding of .NET Core’s configuration settings will undoubtedly set you on the path to success.
So, the next time you embark on a.NET Core project, remember that configuration settings are more than just variables; they are the cornerstone that assures your application’s integrity and resilience in the face of changing problems. Accept the power of configuration management and watch your .NET Core projects fly to new heights of efficiency and security. Happy coding!