Reputation: 956
This is my setup for my .NET Core application:
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args)
{
return WebHost.CreateDefaultBuilder(args)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.ConfigureAppConfiguration((builderContext, config) =>
{
var entryAssemblyFolder = new FileInfo(Assembly.GetEntryAssembly().Location).DirectoryName;
IHostingEnvironment env = builderContext.HostingEnvironment;
config
.SetBasePath(entryAssemblyFolder)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
})
.UseStartup<Startup>()
.Build();
}
}
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public static IConfiguration Configuration { get; set; }
}
All of the above runs when the program starts. At a later point in time during the execution of the program, I'd like to be able to add additional configuration based on data which isn't known at startup time. The following is pseudo-code since there's no parameter to the ConfigurationBuilder constructor:
public class Helper
{
public void Add(string key, string value)
{
//pseudo-code:
var builder = new ConfigurationBuilder(Startup.Configuration);
builder.AddInMemoryCollection(new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>(key, value)
});
Startup.Configuration = builder.Build();
}
}
How can I add to the existing configuration, while keeping what's already there (including the reloadOnChange: true) ?
Thanks,
Upvotes: 0
Views: 1977
Reputation: 151
I did some more digging into the source of MemoryConfigurationProvider. The provider copies the initial data into it's own Data property.
So even if you update your original dictionary, the provider will still only have the original values, when it was initialized.
Haven't tried the GetReloadToken
approach which might work, but here is an alternative more direct approach.
Consider this be your configuration:
public class MyConfiguration
{
public static Dictionary<string,string> InMemoryCollection =
new Dictionary<string, string>
{
{"InMemoryCollection:Option1", "value1"},
{"InMemoryCollection:Option2", "value2"}
};
}
Initialize your configuration:
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(builder => {
builder.AddInMemoryCollection(MyConfiguration.InMemoryCollection);
})
.UseStartup<Startup>();
Assume you have a controller to read and enter new values:
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
private IConfigurationRoot configuration;
/// <summary>
/// Initializes a new instance of the <see cref="ValuesController"/> class.
/// Value injected through DI.
/// </summary>
/// <param name="configuration">The configuration.</param>
public ValuesController(IConfiguration configuration)
{
this.configuration = (IConfigurationRoot)configuration;
}
[HttpGet]
/// <summary>
/// Get in memory values.
/// </summary>
/// <returns></returns>
public IDictionary<string,string> Get()
{
var result = new Dictionary<string, string>();
this.configuration.GetSection("InMemoryCollection").Bind(result);
return result;
}
[HttpPost]
/// <summary>
/// Enter a new value.
/// </summary>
/// <param name="value">The value.</param>
public void Post([FromBody] string value)
{
//get the provider instance from the configuration root.
MemoryConfigurationProvider memoryProvider =
(MemoryConfigurationProvider)this.configuration.Providers
.First(p =>
p.GetType() == typeof(MemoryConfigurationProvider));
//add the new option into the providers data collection.
var nextKey = MyConfiguration.InMemoryCollection.Count + 1;
memoryProvider.Add(
$"InMemoryCollection:Option{nextKey}",
value);
}
}
Note: I don't know the details/requirements for configuration options that are added dynamically, but using the AddInMemoryCollection
approach doesn't look like it's the best of choices. Unless of course, you deliberately don't want to persist them.
I am fairly certain though that there are other approaches/solutions to resolve the issue, without necessarily using the Microsoft.Extensions.Configuration APIs.
Upvotes: 1