I am using the IOptions pattern as described in the official documentation.
This works fine when I am reading values from appsetting.json,
Simplified version of Matze's answer:
public interface IWritableOptions : IOptionsSnapshot where T : class, new()
{
void Update(Action applyChanges);
}
public class WritableOptions : IWritableOptions where T : class, new()
{
private readonly IHostingEnvironment _environment;
private readonly IOptionsMonitor _options;
private readonly string _section;
private readonly string _file;
public WritableOptions(
IHostingEnvironment environment,
IOptionsMonitor options,
string section,
string file)
{
_environment = environment;
_options = options;
_section = section;
_file = file;
}
public T Value => _options.CurrentValue;
public T Get(string name) => _options.Get(name);
public void Update(Action applyChanges)
{
var fileProvider = _environment.ContentRootFileProvider;
var fileInfo = fileProvider.GetFileInfo(_file);
var physicalPath = fileInfo.PhysicalPath;
var jObject = JsonConvert.DeserializeObject(File.ReadAllText(physicalPath));
var sectionObject = jObject.TryGetValue(_section, out JToken section) ?
JsonConvert.DeserializeObject(section.ToString()) : (Value ?? new T());
applyChanges(sectionObject);
jObject[_section] = JObject.Parse(JsonConvert.SerializeObject(sectionObject));
File.WriteAllText(physicalPath, JsonConvert.SerializeObject(jObject, Formatting.Indented));
}
}
public static class ServiceCollectionExtensions
{
public static void ConfigureWritable(
this IServiceCollection services,
IConfigurationSection section,
string file = "appsettings.json") where T : class, new()
{
services.Configure(section);
services.AddTransient>(provider =>
{
var environment = provider.GetService();
var options = provider.GetService>();
return new WritableOptions(environment, options, section.Key, file);
});
}
}
Usage:
services.ConfigureWritable(Configuration.GetSection("MySection"));
Then:
private readonly IWritableOptions _options;
public MyClass(IWritableOptions options)
{
_options = options;
}
To save the changes to the file:
_options.Update(opt => {
opt.Field1 = "value1";
opt.Field2 = "value2";
});
And you can pass a custom json file as optional parameter (it will use appsettings.json by default):
services.ConfigureWritable(Configuration.GetSection("MySection"), "appsettings.custom.json");