.NET Core - 讀取外部設定檔方式

通常我們在寫一套系統的時候,會有設定的機制,不管是設定環境變數或讀取設定檔,這些都能讓使用者可以藉由修改設定檔的設定來改變系統的運作模式,當然這些設定是開發人員制定的。在 .Net Framework 中,比較常用 App.config 或 Web.config 這種 .Net 預設的設定檔格式,限量在先前有介紹過。然而隨著技術不斷的轉變,大家漸漸地喜歡以 JSON 格式表示,.Net Core 也使用了 appsettings.json 作為預設的設定檔,讀取設定檔的方式也改變了,今天就是來看看到底 .Net 是如何讀取設定的。


.Net Core 以 Package 為導向,有許多 DLL 都套件化,對於 Configuration 部分也有套件可以使用。 開啟 NuGet Package Manager,然後搜尋 Microsoft.Extensions.Configuration,會看到與 Configuration 相關的一堆 Package,像 
Microsoft.Extensions.Configuration, 
Microsoft.Extensions.Configuration.Json, 
Microsoft.Extensions.Configuration.Xml, 
Microsoft.Extensions.Configuration.Ini
... 等,
這些都是針對各種設定檔類型所提供的機制,當然,只要針對你需要的安裝就好,這就是 .Net Core 的精神。在安裝的時候要注意 Package 下方的 Dependencies 描述,因為有些 Package 有相依其他的 Package,在安裝時會連同其他的 Package 一起安裝,但是在你的安裝列表中只會顯示一個。例如:Microsoft.Extensions.Configuration.Json 相依 Microsoft.Extensions.Configuration,安裝時會一起裝 Microsoft.Extensions.Configuration,所以我們可以不用再特地選一次 Microsoft.Extensions.Configuration 安裝。

在新版的 Configuration 中,有兩大主角,ConfigurationBuilder IConfiguration

ConfigurationBuilder顧名思義,就是把外部設定格式化,轉換成我們可以存取的介面。根據我們所安裝的各種機制的 Package,會有不同的方法,例如:安裝 Json 機制的 Package 會提供 AddJsonFile 的擴充方法;安裝 Xml 機制的 Package 會提供 AddXmlFile 的擴充方法。

IConfiguration,是 ConfigurationBuilder 轉換而成的資料存取介面,就類似 .Net Framework 的 ConfigurationManger一樣。透過這個介面我們就可以輕鬆的取得各種設定值,例如可以使用 GetSection 取得指定的 ConfigurationSection,或使用 Index 方式取得該節點的設定值(後面會有一些範例來說明)。

我們來看看簡單的應用:
下面是一個簡單的 JSON 設定檔:

appsettings.json

{
  "ConnectionStrings": {
    "TestDBConn": "Data Source=D:/TestDb.db"
  },

  "Company": {
    "Debug": [
      {
        "Name": "Debug1",
        "Type": "Console",
        "Comm": {
          "Value": "0"
        }
      },
      {
        "Name": "Debug2",
        "Type": "Console",
        "Comm": {
          "Value": "-1"
        }
      }
    ],
    "Online": [
      {
        "Name": "Online",
        "Type": "Web",
        "Comm": {
          "Value": "1"
        }
      }
    ]
  }
}


要讀取它很簡單,下面是讀取 Configuration 的程式碼:
class Program
{
 static IConfigurationRoot Configuration { get; set; }
 static void Main(string[] args)
 {
  var builder = new ConfigurationBuilder()
   .SetBasePath(Directory.GetCurrentDirectory())  // 設定跟目錄
   .AddJsonFile("appsettings.json", true);   // 讀取appsettings.json檔案

  Configuration = builder.Build();

  var sections = Configuration.GetChildren();

  // 顯示所有節點資訊
  foreach(var s in sections)
  {
   ShowSectionInfo(s);
  }
 }
 // 顯示節點資訊
 static void ShowSectionInfo(IConfigurationSection section)
 {
  if (section.GetChildren().Count() == 0) {
   Console.WriteLine($"Path: {section.Path}, Value: {section.Value}");
   return;
  }


  Console.WriteLine($"Path: {section.Path}");
  foreach (var s in section.GetChildren())
  {
   ShowSectionInfo(s);
  }
 }
}

主要幾個重點就是

  1. 注意設定檔的路徑,你可以使用 SetBasePath 來設定,預設路徑是程式執行路徑。
  2. 指定設定檔名稱,你可以使用 AddXXXFile 加入多個設定檔,它們將會整合到同一個。

執行結果如下:

Path: Company
Path: Company:Debug
Path: Company:Debug:0
Path: Company:Debug:0:Comm
Path: Company:Debug:0:Comm:Value, Value: 0
Path: Company:Debug:0:Name, Value: Debug1
Path: Company:Debug:0:Type, Value: Console
Path: Company:Debug:1
Path: Company:Debug:1:Comm
Path: Company:Debug:1:Comm:Value, Value: -1
Path: Company:Debug:1:Name, Value: Debug2
Path: Company:Debug:1:Type, Value: Console
Path: Company:Online
Path: Company:Online:0
Path: Company:Online:0:Comm
Path: Company:Online:0:Comm:Value, Value: 1
Path: Company:Online:0:Name, Value: Online
Path: Company:Online:0:Type, Value: Web
Path: ConnectionStrings
Path: ConnectionStrings:TestDBConn, Value: Data Source=D:/TestDb.db

為什麼限量在這個範例程式裡要 Show 這些資訊呢?其實 Show 這個是有目的的,看到 Path 沒有,這個 Path 就是用來直接取的該節點的路徑。比如說我想要直接抓 CompanyB => Online => 第一個物件 => Comm => Value 的值,讓我們參考一下上面的路徑表,接著只要用 IConfiguration 的 GetSection 方法,或者是透過 Index 的方式將 Path 傳入就可以直接拿到該區段的物件。

看到這邊是不是覺得還少了一點什麼,你會覺得啊這樣要取得設定不就超麻煩的,還要用路徑哩。其實這些只是基本,接下來要來說明的是一個超棒的功能,就是將設定檔轉成我們客製化的資料結構。
這個功能需要其他 Package 的輔助,安裝 Microsoft.Extensions.Configuration.Binder。接著很簡單,我們只要定義好設定檔的 Class,範例如下:

AppConfig.cs
public class AppConfig
{
 public IDictionary ConnectionStrings { get; set; }
 public CompanySetting Company { get; set; }
}

public class CompanySetting
{
 public DebugSetting[] Debug { get; set; }

 public OnlineSetting[] Online { get; set; }
}

public interface IDeploy
{
 string Name { get; set; }

 string Type { get; set; }

 CommSetting Comm { get; set; }
}

public abstract class DeploySettingBase : IDeploy
{
 public string Name { get; set; }

 public string Type { get; set; }

 public CommSetting Comm { get; set; }
}

public class DebugSetting : DeploySettingBase
{
  
}

public class OnlineSetting : DeploySettingBase
{

}

public class CommSetting
{
 public string Value { get; set; }
}

最後我只要在剛剛範例程式裡加入一行

var setting = Configuration.Get<AppConfig>();

完成了,打完收工,執行看看結果如何:




看到結果真的是太感動了,再也不用像以前一樣寫一堆繼承 ConfigurationSection 的 Class,以後就可以快快樂樂的使用漂亮的設定檔資料。

Configuration Package 能做的事當然不只這樣,他還有許多相關的 Package 可以做其他事,如果你自己有想到其他好玩的好用的方法,也可以繼承介面自己做,做完還可以貢獻到 NuGet 上分享,因為 .Net Core 是 OpenSource 的,大家一起讓 .Net Core 變得更加強大吧。



站內相關文章:
C# - App.config自訂section程式碼架構Part I(基本用法)
C# - App.config自訂section程式碼架構Part II (巢狀, 陣列)
C# - App.config自訂section程式碼架構Part III(使用泛型)


參考來源:
Microsoft Docs - Configuration in ASP.NET Core




留言