Keywords: .NET Core Configuration | Microsoft.Extensions.Configuration | XML Configuration Provider | Options Pattern | Configuration Migration
Abstract: This article explores how to use Microsoft.Extensions.Configuration API for configuration management in .NET Core applications, covering various configuration sources including XML, JSON, and environment variables. It provides solutions for migrating traditional app.config to .NET Core, with practical code examples demonstrating configuration provider priorities, hierarchical data binding, and custom provider implementation to help developers build flexible and maintainable configuration systems.
Configuration System Overview
In the .NET Core ecosystem, the traditional System.Configuration.ConfigurationManager has been replaced by the Microsoft.Extensions.Configuration API. The new configuration system provides a more flexible and extensible architecture that supports seamless integration of multiple configuration sources.
Configuration Provider Priorities
Microsoft.Extensions.Configuration employs a hierarchical configuration model where configuration providers determine priority based on their addition order. Later-added providers have higher priority and can override settings from previous providers. The typical configuration source priority from highest to lowest is:
- Command-line arguments
- Environment variables
- User secrets (development environment)
appsettings.{Environment}.jsonappsettings.json
XML Configuration Provider Usage
While JSON has become the default configuration format in .NET Core, XML configuration remains well-supported. To use XML configuration, first install the Microsoft.Extensions.Configuration.Xml NuGet package:
dotnet add package Microsoft.Extensions.Configuration.Xml
Configure the XML provider in Program.cs:
var builder = WebApplication.CreateBuilder(args);
builder.Configuration
.AddXmlFile("app.config", optional: true, reloadOnChange: true)
.AddXmlFile($"app.{builder.Environment.EnvironmentName}.config",
optional: true, reloadOnChange: true);
Configuration Data Reading
Use the IConfiguration interface to read configuration values:
public class ConfigurationService
{
private readonly IConfiguration _configuration;
public ConfigurationService(IConfiguration configuration)
{
_configuration = configuration;
}
public string GetConnectionString()
{
return _configuration.GetConnectionString("sampleDatabase");
}
public string GetAppSetting(string key)
{
return _configuration[key];
}
}
Options Pattern
The options pattern is the recommended approach for reading related configuration values, providing strongly-typed configuration access:
public class CustomOptions
{
public const string SectionName = "custom";
public string Key { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
public int Age { get; set; }
}
// Register options service
builder.Services.Configure<CustomOptions>(
builder.Configuration.GetSection(CustomOptions.SectionName));
// Use options
public class MyService
{
private readonly CustomOptions _options;
public MyService(IOptions<CustomOptions> options)
{
_options = options.Value;
}
public void ProcessConfiguration()
{
Console.WriteLine($"Key: {_options.Key}, Name: {_options.Name}, Age: {_options.Age}");
}
}
Environment-Specific Configuration
Support for environment-specific configuration files such as appsettings.Development.json and appsettings.Production.json:
var builder = WebApplication.CreateBuilder(args);
// Automatically load environment-specific configuration
builder.Configuration
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json",
optional: true, reloadOnChange: true);
Custom Configuration Section Handling
For complex custom configuration sections, implement configuration section classes:
public class CustomConfigurationSection
{
public List<CustomConfiguration> CustomConfigurations { get; set; } = new();
}
public class CustomConfiguration
{
public string Key { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
public int Age { get; set; }
}
// Bind configuration
var customSection = new CustomConfigurationSection();
builder.Configuration.GetSection("custom").Bind(customSection);
Configuration Validation
Use data annotations for configuration validation:
using System.ComponentModel.DataAnnotations;
public class ValidatedOptions
{
[Required]
[MinLength(1)]
public string RequiredSetting { get; set; } = string.Empty;
[Range(1, 100)]
public int NumericSetting { get; set; }
}
// Validate configuration
var options = new ValidatedOptions();
builder.Configuration.GetSection("validated").Bind(options);
var validationContext = new ValidationContext(options);
var validationResults = new List<ValidationResult>();
bool isValid = Validator.TryValidateObject(options, validationContext, validationResults, true);
Configuration Reloading
Support for dynamic reloading of configuration files:
builder.Configuration
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddXmlFile("app.config", optional: true, reloadOnChange: true);
// Use IOptionsSnapshot to get latest configuration
public class ConfigAwareService
{
private readonly IOptionsSnapshot<CustomOptions> _optionsSnapshot;
public ConfigAwareService(IOptionsSnapshot<CustomOptions> optionsSnapshot)
{
_optionsSnapshot = optionsSnapshot;
}
public void UseCurrentConfig()
{
var currentOptions = _optionsSnapshot.Value;
// Use current configuration
}
}
Migration Recommendations
Recommendations for migrating from traditional app.config to the new configuration system:
- Convert XML configuration to JSON format for better performance and support
- Use options pattern instead of direct ConfigurationManager calls
- Leverage environment-specific configuration instead of configuration transforms
- Consider using user secrets for sensitive data management
- Implement configuration validation to ensure configuration integrity
Best Practices
- Use different configuration files for different configuration hierarchies
- Use user secrets for sensitive information in development environments
- Use secure configuration storage like Azure Key Vault in production environments
- Implement comprehensive configuration validation mechanisms
- Use appropriate configuration reloading strategies to balance performance and flexibility