[C#] 如何在 app.config 存放「物件形式」陣列資料

當需存放多筆「數值」於 app.config 中時,最簡單的作法就是使用特殊符號將字串分開,後續再從程式碼中以切割字串方式轉換為陣列;但有時會需要存放「物件形式」陣列資料,例如設定單筆伺服器可能就會包含名稱、位置、參數等資訊,而此時就可以透過自定義 ConfigurationSection 來實現。

情境說明


筆者想建立一支監看各資料夾資料變動情況的應用程式,希望讓使用者自行增減多組資料夾設定,分別歸類在 indoor 及 outdoor 兩個集合中,其中需提供「名稱」、「路徑位置」及「啟用狀態」三項資料夾資訊, 而預期目標就是要將所有設定放至 app.config 中,因此預計在 app.config 中會以下圖方式設定配置,而實際做法請參考以下說明。

  1. ConfigurationElement 物件 
  2. ConfigurationElementCollection 物件 
  3. ConfigurationSection 物件

 

建立 ConfigurationElement 物件


建立繼承自 ConfigurationElement 的 FolderElement 物件,可依照所需存放的「資訊」來建立屬性 。

public class FolderElement : ConfigurationElement
{
    // 資料夾名稱
    [ConfigurationProperty("name", DefaultValue = "", IsKey = true, IsRequired = true)]
    public string Name
    {
        get { return (string)base["name"]; }
        set { base["name"] = value; }
    }

    // 資料夾路徑
    [ConfigurationProperty("path", DefaultValue = "", IsKey = false, IsRequired = true)]
    public string Path
    {
        get { return (string)base["path"]; }
        set { base["path"] = value; }
    }

    // 是否啟用
    [ConfigurationProperty("isActive", DefaultValue = "true", IsKey = false, IsRequired = false)]
    public bool IsActive
    {
        get { return (bool)base["isActive"]; }
        set { base["isActive"] = value; }
    }
}

 

建立 ConfigurationElementCollection 物件


建立繼承自 ConfigurationElementCollection 的 FolderCollection 物件,指定使用 <folder> 標籤作為 app.config 中 element 名稱 ,並使用 FolderElement 來 override 各所需方法。

[ConfigurationCollection(typeof(FolderElement))]
public class FolderCollection : ConfigurationElementCollection
{
    // 設定 app.config 中 collection 的 element 標籤為 <folder>
    internal const string _propertyName = "folder";

    public override ConfigurationElementCollectionType CollectionType
    {
        get
        {
            return ConfigurationElementCollectionType.BasicMapAlternate;
        }
    }

    protected override bool IsElementName(string elementName)
    {
        return elementName.Equals(_propertyName, StringComparison.InvariantCultureIgnoreCase);
    }

    protected override ConfigurationElement CreateNewElement()
    {
        return new FolderElement();
    }

    protected override object GetElementKey(ConfigurationElement element)
    {
        return ((FolderElement)(element)).Name;
    }     
}

 

建立 ConfigurationSection 物件


建立繼承自 ConfigurationSection 的 FolderCollection 物件,依照需求建立所需集合屬性;在此建立 IndoorFolderCollection 及 OutdoorFolderCollection 屬性,並分別指定使用 <IndoorFolders> 及 <OutdoorFolders> 標籤於 app.config 中表示各集合組態區塊。

public class FolderSection : ConfigurationSection
{
    // 定義 app.config 中此 section 所使用的 collection 標籤為 <indoorFolders>
    [ConfigurationProperty("indoorFolders")]
    public FolderCollection IndoorFolderCollection
    {
        get { return ((FolderCollection)(base["indoorFolders"])); }
        set { base["indoorFolders"] = value; }
    }

    // 定義 app.config 中此 section 所使用的 collection 標籤為 <outdoorFolders>
    [ConfigurationProperty("outdoorFolders")]
    public FolderCollection OutdoorFolderCollection
    {
        get { return ((FolderCollection)(base["outdoorFolders"])); }
        set { base["outdoorFolders"] = value; }
    }
}

 

設定 app.config 


最後在 app.config 中建立 configSections 區塊,可於此定義多組 Section 並明確標示名稱及型態 (full class name, assembly name),接著就可以在下方使用相同名稱建立 section 內容。

<configuration>

  <!-- Config Sections -->
  <configSections>
    <!-- type = full section class name, assembly name -->
    <section name="folderSection" 
             type="Sample.FileCleaner.CustomerConfig.FolderSection, Sample.FileCleaner"/>
  </configSections>  

  <!-- Customer Section -->
  <folderSection>
    <indoorFolders>
      <folder name="內網-圖片" 
              path="\InFileServer\Photo" 
              isActive="true"/>
      <folder name="內網-影片" 
              path="\InFileServer\Video" 
              isActive="true"/>
    </indoorFolders>
    <outdoorFolders>
      <folder name="外網-圖片" 
              path="\OutFileServer\Photo" 
              isActive="true"/>
      <folder name="外網-影片" 
              path="\OutFileServer\Video" 
              isActive="true"/>
    </outdoorFolders>
  </folderSection>

  <!-- 略 -->

</configuration>

 

取出資料 


可以先建立一個 ConfigSetting 類別,以此統一處理向 app.config 取值的作業;以下就是透過 FolderSection - FolderCollection - FolderElement 關係,依序找到我們所記載在 app.config 的資料。

public class ConfigSetting
{
    // 取得 FolderSection
    private static FolderSection _folderSection = 
        ConfigurationManager.GetSection("folderSection") as FolderSection;

    // 取得 FolderSection - IndoorFolderCollection - FolderElements
    public static IEnumerable<FolderElement> GetMonitorIndoorFolders()
    {
        var folderCollection = _folderSection.IndoorFolderCollection;
        foreach (FolderElement folder in folderCollection)
        {
            if (folder != null)
                yield return folder;
        }
    }

    // 取得 FolderSection - OutdoorFolderCollection - FolderElements
    public static IEnumerable<FolderElement> GetMonitorOutdoorFolders()
    {
        var folderCollection = _folderSection.OutdoorFolderCollection;
        foreach (FolderElement folder in folderCollection)
        {
            if (folder != null)
                yield return folder;
        }
    }
}

來看看取得的資料

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine($"====== 【Indoor Folders】=======");
        ShowFolders(ConfigSetting.GetMonitorIndoorFolders());

        Console.WriteLine($"=======【Outdoor Folders】=======");
        ShowFolders(ConfigSetting.GetMonitorOutdoorFolders());

        Console.Read();
    }

    public static void ShowFolders(IEnumerable<FolderElement> folders)
    {
        foreach (var folder in folders)
        {
            Console.WriteLine($"Name: {folder.Name}");
            Console.WriteLine($"Path: {folder.Path}");
            Console.WriteLine($"IsActive: {folder.IsActive}");
            Console.WriteLine($"--");
        }
    }

}

順利將資料通通取出囉!

 

 


希望此篇文章可以幫助到需要的人

若內容有誤或有其他建議請不吝留言給筆者喔 !