ASP.NET Core Configuration
2024-07-01
筆記 ASP.NET Core Configuration 的基本要點。
Configuration
We add a model first to map the configuration.
public class WebsiteProfileOptions
{
public string ThemeColor { get; set; } = "green";
public string FontSize { get; set; } = "16px";
}
[Route("api/[controller]")]
[ApiController]
public class OptionsController : ControllerBase
{
readonly IOptions<WebsiteProfileOptions> _options;
public OptionsController(IOptions<WebsiteProfileOptions> options)
{
_options = options;
}
// Get api/options
[HttpGet]
public WebsiteProfileOptions Get()
{
return _options.Value;
}
}
😎 You don't have to register Options in the DI container, it will be automatically registered by ASP.NET Core.
We can use Primary Constructor to inject the configuration.
[Route("api/[controller]")]
[ApiController]
public class OptionsController(IOptions<WebsiteProfileOptions> _options) : ControllerBase
{
// this setting is optional, if you want to make _options readonly
readonly IOptions<WebsiteProfileOptions> _options = _options;
// Get api/options
[HttpGet]
public WebsiteProfileOptions Get()
{
return _options.Value;
}
}
We can change the configuration in the Program.cs
file.
builder.Services.AddControllers();
builder.Services.Configure<WebsiteProfileOptions>(options =>
{
options.ThemeColor = "blue";
options.FontSize = "20px";
});
var app = builder.Build();
But best practice is to setting the configuration in appsettings.json
file.
builder.Services.Configure<WebsiteProfileOptions>(builder.Configuration);
var app = builder.Build();
{
"WebsiteProfileOptions": {
"ThemeColor": "blue",
"FontSize": "18px"
}
}
Nested configuration in the appsettings.json
file.
builder.Services.Configure<WebsiteProfileOptions>(builder.Configuration.GetSection("WebsiteProfile"));
{
"WebsiteProfile": {
"ThemeColor": "yellow",
"FontSize": "36px"
}
}
We can use IOptionsSnapshot
to get the fresh configuration per request.
[Route("api/[controller]")]
[ApiController]
public class OptionsController(IOptionsSnapshot<WebsiteProfileOptions> _options) : ControllerBase
{
// Get api/options
[HttpGet]
public WebsiteProfileOptions Get()
{
return _options.Value;
}
}
IOptions: Singleton, static configuration values.
IOptionsSnapshot: Scoped, fresh configuration per request.
IOptionsMonitor: Singleton, dynamic configuration with change notifications.
We can use AddJsonFile
to add custome configuration file.
builder.Configuration.AddJsonFile("profile.json", optional: true, reloadOnChange: true);
builder.Services.Configure<WebsiteProfileOptions>(builder.Configuration.GetSection("WebsiteProfile"));
profile.json
{
"WebsiteProfile": {
"ThemeColor": "red",
"FontSize": "24px"
}
}
If we add multiple configuration files, the last one will override the previous one.
builder.Configuration.AddJsonFile("profile.json", optional: true, reloadOnChange: true);
builder.Configuration.AddInMemoryCollection(new Dictionary<string, string?>
{
["WebsiteProfile:ThemeColor"] = "Red",
["WebsiteProfile:FontSize"] = "1px"
});
builder.Services.Configure<WebsiteProfileOptions>(builder.Configuration.GetSection("WebsiteProfile"));
We can use builder.Configuration as IConfigurationRoot
to get the configuration order.
foreach (var provider in (builder.Configuration as IConfigurationRoot).Providers)
{
Console.WriteLine(provider.ToString());
}
MemoryConfigurationProvider
EnvironmentVariablesConfigurationProvider Prefix: 'ASPNETCORE_'
MemoryConfigurationProvider
EnvironmentVariablesConfigurationProvider Prefix: 'DOTNET_'
JsonConfigurationProvider for 'appsettings.json' (Optional)
JsonConfigurationProvider for 'appsettings.Development.json' (Optional)
EnvironmentVariablesConfigurationProvider
Microsoft.Extensions.Configuration.ChainedConfigurationProvider
JsonConfigurationProvider for 'profile.json' (Optional)
MemoryConfigurationProvider
We can also add XML and INI configuration files.
profile.xml
<WebsiteProfile>
<ThemeColor>blue</ThemeColor>
<FontSize>18px</FontSize>
[WebsiteProfile]
ThemeColor=green
FontSize=16px
builder.Configuration.AddXmlFile("profile.xml", optional: true, reloadOnChange: true);
builder.Configuration.AddIniFile("profile.ini", optional: true, reloadOnChange: true);
Get Configuration by key without Model to bind
We can use IConfiguration
to get the configuration by key, instead of using IOptions
to skip Model binding 😉
[Route("api/[controller]")]
[ApiController]
public class ConfigController(IConfiguration _configuration) : ControllerBase
{
[HttpGet]
public string? Get() => _configuration["WebsiteProfile:ThemeColor"];
}
Using Bind to bind the configuration
[HttpGet("Bind")]
public WebsiteProfileOptions Bind()
{
WebsiteProfileOptions options = new ();
_configuration.Bind("WebsiteProfile", options);
return options.options;
}
⭐ Using IConfiguration
, it's useful when you need to access a single or a few configuration values directly and you don't want to create a class to represent those settings, otherwise, use IOptions
to bind the configuration to a class.
Multiple Configuration Files
Named options in .NET allow you to configure and manage multiple instances of options with different settings. This feature is particularly useful when you need to inject different configurations into various parts of your application.
⚡ If we want to use multiple configuration files, we can use NamedOptions
to bind the configuration.
builder.Configuration.AddJsonFile("configSource1.json", optional: false, reloadOnChange: true);
builder.Configuration.AddJsonFile("configSource2.json", optional: false, reloadOnChange: true);
builder.Services.Configure<ConfigSettings>("Source1", builder.Configuration.GetSection("CommonSettings"));
builder.Services.Configure<ConfigSettings>("Source2", builder.Configuration.GetSection("CommonSettings"));
var app = builder.Build();
public class ConfigSettings
{
public string Setting { get; set; }
}
[ApiController]
[Route("[controller]")]
public class MyController : ControllerBase
{
private readonly ConfigSettings _source1Config;
private readonly ConfigSettings _source2Config;
public MyController(IOptionsSnapshot<ConfigSettings> source1ConfigOptions, IOptionsSnapshot<ConfigSettings> source2ConfigOptions)
{
_source1Config = source1ConfigOptions.Get("Source1");
_source2Config = source2ConfigOptions.Get("Source2");
}
[HttpGet("source1")]
public IActionResult GetSource1Config()
{
return Ok(_source1Config);
}
[HttpGet("source2")]
public IActionResult GetSource2Config()
{
return Ok(_source2Config);
}
}
// configSource1.json
{
"CommonSettings": {
"Setting": "Value in source 1 🦊"
}
}
//configSource2.json
{
"CommonSettings": {
"Setting": "Value in source 2 🐸"
}
}