C# 讀取 JSON 設定檔

之前在 C# 設定檔教學 (三) 最方便的 Json設定檔 這篇中有介紹到讀取 JSON 的設定檔,那時是使用最簡單的方式,直接讀取文字檔案,然後反序列化為物件讀取。 不過其實會有個小問題,就是各類型的設定值無法拆分,不管是什麼功能(模組)的設定值都需要維護同一個 class ,耦合性很高,其實我們可以使用和 ASP.NET Core 一樣的方式,有個「設定值提供者」來負責主要的讀取,要使用這種方式很容易,只要安裝微軟的套件即可。

安裝

先使用 NuGet 安裝 Microsoft.Extensions.Configuration.Json 套件,或是使用 .NET CLI 執行以下指令安裝
	
dotnet add package Microsoft.Extensions.Configuration.Json
    

另外還需要安裝 Microsoft.Extensions.Configuration.Binder 套件,用來自動將設定值的鍵值對資料反序列化為物件
	
dotnet add package Microsoft.Extensions.Configuration.Binder
    

讀取設定檔

我們建立一個 appsettings.json 檔案,用來放置設定檔內容,範例設定值如下:
    
{
  "Module1": {
    "Key1": "Value1"
  },
  "Module2": {
    "Key2": "Value2"
  }
}
    

建立兩個類別用來處理設定值:
    
public class Module1Options
{
    public string Key1 { get; set; }
}
    

    
public class Module2Options
{
    public string Key2 { get; set; } = null!;
}
    

這裡示範只有最基礎的 string 型別,但其實 int, List 等都是可以的。

就可以很簡單的讀取設定值了:
    
var configuration = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory()) // 設定基本路徑為目前專案的目錄
    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
    .Build();

Module1Options? module1Options = configuration.GetSection("Module1").Get<Module1Options>();
if(module1Options == null) throw new Exception("設定檔讀取錯誤,找不到 Module1 設定");

Console.WriteLine($"Key1: {module1Options.Key1}");


Module2Options? module2Options = configuration.GetSection("Module2").Get<Module2Options>();
if(module2Options == null) throw new Exception("設定檔讀取錯誤,找不到 Module2 設定");

Console.WriteLine($"Key2: {module2Options.Key2}");
    


註: 上面的 Directory.GetCurrentDirectory() 是設定讀取 appsettings.json 的路徑為專案執行路徑,這樣在哪裡使用 dotnet run 就會讀取該資料夾下的 appsettings.json 檔案,也可以自行變更。

儲存設定值

尷尬的來了,在 ASP.NET Core 的設定中並不需要儲存設定值,所以在我們剛剛安裝的套件中並沒有這個功能。
不過如果會需要寫回設定值,那我們只能自己實現將不同功能(模組)的設定值寫回,不過這個套件其實可以讀取多個設定檔,並依照優先順序決定要套用哪一個值,但是在寫回時我們沒有辦法簡單的分辨,只能都寫到其中一個設定檔中,這點需要注意。

下面是筆者寫的簡單實現:
    
void SaveConfiguration(string configName, object newOptions)
{
    const string configPath = "appsettings.json";
    var jsonSerializerOptions = new JsonSerializerOptions
    {
        WriteIndented = true,
        Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
    };


    string json = File.ReadAllText(Path.Combine(Directory.GetCurrentDirectory(), configPath));
    var jsonObject = JsonDocument.Parse(json).RootElement.Clone();

    // 將修改後的設定值寫入 JSON 物件
    using (var stream = new MemoryStream())
    {
        using (var writer = new Utf8JsonWriter(stream))
        {
            jsonObject.WriteTo(writer);
        }

        var modifiedJson = JsonSerializer.Deserialize<Dictionary<string, object>>(stream.ToArray());
        if (modifiedJson == null) throw new Exception("設定檔讀取錯誤");
        modifiedJson[configName] = newOptions; // 更新部分設定

        string updatedJson = JsonSerializer.Serialize(modifiedJson, jsonSerializerOptions);
        File.WriteAllText(Path.Combine(Directory.GetCurrentDirectory(), configPath), updatedJson);
    }
}
    

這樣假設 Module2Options 的內容更新後要儲存時就可以這樣使用:
    
module2Options.Key2 = "新的值123";
SaveConfiguration("Module2", module2Options);
    

留言

張貼留言

如果有任何問題、建議、想說的話或文章題目推薦,都歡迎留言或來信: a@ruyut.com