Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Save Changes of IConfigurationRoot sections to its *.json file in .net Core 2.2

i was digging to find out the solution but didn't manage to find it, i bet that someone has encountered this problem, so what is the problem?.

For test i have created simple console application (solution will be used in asp.net core web api).

I have TestSetting.json configuration file with 'Copy Always' setuped.

{
  "setting1" : "value1" 
}

And Simple code

IConfigurationBuilder configurationBuilder = new ConfigurationBuilder();

IConfigurationRoot configuration = configurationBuilder.AddJsonFile("TestSettings.json",false, reloadOnChange: true).Build();

Console.WriteLine(configuration.GetSection("setting1").Value); // Output: value1
//Change configuration manually in file while console is waiting
Console.ReadKey();

//Changed manually in file Value appears
Console.WriteLine(configuration.GetSection("setting1").Value); // Output: Whatever you have setuped
Console.ReadKey();

configuration.GetSection("setting1").Value = "changed from code";
//Changed in code value appear
Console.WriteLine(configuration.GetSection("setting1").Value); // Output: changed from code

I have 2 requirements, i want to make it possible to change value in json configuration file manually while application is running and application will see updated value during next get of setting Section and it is working.

Second requirement is that, i want to preserve some information, to be accurate a last execution time of task which should be executed once per setuped period ex. once a day, so some loop check last execution time value and determine if operation has to be executed. Someone would ask that what i have will work, but i need also to cover scenario when operation has been executed and application has been restarted (server error, user restart etc), and i need to save this information in a way which will allow me to read it after app startup.

Reading code sample we can see that after changing setting1 in code we see that this section has been changed while trying to output it to console.

configuration.GetSection("setting1").Value = "changed from code";
//Changed in code value appear
Console.WriteLine(configuration.GetSection("setting1").Value); // Output: changed from code

Here comes the question :). Is it possible that this settings section change will also affect actual value in json file? I don't want to manually change this file by some stream writers or whatever.

Actual result is that: after changing value in code, the new value is getable in runtime but when you will go to debug binaries you will se that value1 in TestSettings.json file hasnt been changed.

like image 518
Paweł Górszczak Avatar asked Dec 05 '22 09:12

Paweł Górszczak


2 Answers

Thank you "Matt Luccas Phaure Jensen" For this, information, i have't found any solution for this there. If any one wants to use IOptions here is an answer how to do it How to update values into appsetting.json?

I want to do it in the way i started, so i looked to the implementation of Microsoft.Extensions.Configuration.Json and i have prepared simple solution to allow writing and use base implementation. It probably has many limitations but it will work in simple scenarios.

Two implementations from above dll have to be extended. So lets do it.

Files to create

Implementation of WritableJsonConfigurationProvider with example save code of desired section.

Change values in JSON file (writing files)

public class WritableJsonConfigurationProvider : JsonConfigurationProvider
{
    public WritableJsonConfigurationProvider(JsonConfigurationSource source) : base(source)
    {
    }

    public override void Set(string key, string value)
    {
        base.Set(key,value);

        //Get Whole json file and change only passed key with passed value. It requires modification if you need to support change multi level json structure
        var fileFullPath = base.Source.FileProvider.GetFileInfo(base.Source.Path).PhysicalPath;
        string json = File.ReadAllText(fileFullPath);
        dynamic jsonObj = JsonConvert.DeserializeObject(json);
        jsonObj[key] = value;
        string output = JsonConvert.SerializeObject(jsonObj, Formatting.Indented);
        File.WriteAllText(fileFullPath, output);
    }
}

And implementation of WritableJsonConfigurationSource which is a extention of JsonConfigurationSource

public class WritableJsonConfigurationSource : JsonConfigurationSource
{
    public override IConfigurationProvider Build(IConfigurationBuilder builder)
    {
        this.EnsureDefaults(builder);
        return (IConfigurationProvider)new WritableJsonConfigurationProvider(this);
    }
}

and that's it, lets use it

IConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
IConfigurationRoot configuration = configurationBuilder.Add<WritableJsonConfigurationSource>(
    (Action<WritableJsonConfigurationSource>)(s =>
                                                     {
                                                         s.FileProvider = null;
                                                         s.Path = "TestSettings.json";
                                                         s.Optional = false;
                                                         s.ReloadOnChange = true;
                                                         s.ResolveFileProvider();
                                                     })).Build();

Console.WriteLine(configuration.GetSection("setting1").Value); // Output: value1
Console.ReadKey();

configuration.GetSection("setting1").Value = "changed from codeeee";
Console.WriteLine(configuration.GetSection("setting1").Value); // Output: changed from codeeee

Console.ReadKey();

Value is being changed in memory as well in file. Bingo :).

The code could have problems, can be refactored etc, this is only sample quick solution.

like image 53
Paweł Górszczak Avatar answered Jan 09 '23 23:01

Paweł Górszczak


It is not possible via the Microsoft.Extensions.Configuration package to save changes made to the configuration to disk. There is an issue about it on github here where they chose not to do it. It is possible to do, just not via the IConfiguration interface. https://github.com/aspnet/Configuration/issues/385

like image 30
Matt Luccas Phaure Minet Avatar answered Jan 09 '23 21:01

Matt Luccas Phaure Minet