首页 > 解决方案 > 将 IConfigurationRoot 部分的更改保存到 .net Core 2.2 中的 *.json 文件

问题描述

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

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

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

{
  "setting1" : "value1" 
}

和简单的代码

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

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

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

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

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

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

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

标签: c#asp.net-web-api.net-core

解决方案


谢谢“Matt Luccas Phaure Jensen”为此,信息,我在那里没有找到任何解决方案。如果有人想在这里使用 IOptions 是一个答案怎么做如何将值更新到 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);
    }
}

以及 WritableJsonConfigurationSource 的实现,它是 JsonConfigurationSource 的扩展

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

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

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();

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

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


推荐阅读