将 IConfigurationRoot 部分的更改保存到 .net Core 2.2 中的 *.json 文件

Paw*_*zak 2 c# asp.net-web-api .net-core

我一直在寻找解决方案,但没有设法找到它,我敢打赌有人遇到过这个问题,那么问题是什么?。

为了测试,我创建了简单的控制台应用程序(解决方案将在 asp.net core web api 中使用)。

我已经设置了“始终复制”的 TestSetting.json 配置文件。

{
  "setting1" : "value1" 
}
Run Code Online (Sandbox Code Playgroud)

和简单的代码

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
Run Code Online (Sandbox Code Playgroud)

我有 2 个要求,我希望可以在应用程序运行时手动更改 json 配置文件中的值,并且应用程序将在下次获取设置部分时看到更新的值并且它正在工作。

第二个要求是,我想保留一些信息,准确地说是任务的最后执行时间,应该在每个设置的时间段执行一次,例如。每天一次,所以一些循环检查上次执行时间值并确定是否必须执行操作。有人会问我有什么可以工作,但我还需要涵盖执行操作和重新启动应用程序时的场景(服务器错误、用户重新启动等),我需要以一种允许我的方式保存这些信息在应用程序启动后阅读它。

阅读代码示例我们可以看到,在代码中更改 setting1 后,我们看到该部分在尝试将其输出到控制台时已更改。

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

问题来了:)。此设置部分更改是否也可能影响 json 文件中的实际值?我不想由某些流编写者或其他任何人手动更改此文件。

实际结果是:更改代码中的值后,新值可在运行时获取,但是当您去调试二进制文件时,您会发现 TestSettings.json 文件中的 value1 没有更改。

Paw*_*zak 7

谢谢“Matt Luccas Phaure Jensen” 对于这个信息,我在那里没有找到任何解决方案。如果有人想使用 IOptions,这里是一个答案How to update values into appsetting.json?

我想按照我开始的方式来做,所以我查看了 Microsoft.Extensions.Configuration.Json 的实现,我准备了简单的解决方案来允许编写和使用基本实现。它可能有很多限制,但它可以在简单的场景中工作。

必须扩展上述 dll 的两个实现。所以让我们去做吧。

要创建的文件

使用所需部分的示例保存代码实现 WritableJsonConfigurationProvider。

更改 JSON 文件中的值(写入文件)

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

和 WritableJsonConfigurationSource 的实现,它是 JsonConfigurationSource 的扩展

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

就是这样,让我们​​使用它

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();
Run Code Online (Sandbox Code Playgroud)

内存和文件中的值都在更改。宾果游戏:)

代码可能有问题,可以重构等,这只是示例快速解决方案。


Mat*_*sen 5

无法通过 Microsoft.Extensions.Configuration 包将对配置所做的更改保存到磁盘。github 上有一个关于它的问题,他们选择不这样做。这是可以做到的,只是不通过 IConfiguration 接口。 https://github.com/aspnet/Configuration/issues/385