自訂應用程式組態檔區段

  • 3477
  • 0

雖然App.config是很老的東西了,但有時候還是蠻好用的.自訂區段可以讓你的App.config有更好的結構.一些Open Source的外掛模組也是用這一種方式去做設定的.

先定好目標是在app.config的<configuration>區定義一個自訂的<section>,然後section的內容是一個列表,就好像connection string的列表一樣,每一個entry就是一個<add>.結果如下

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="MyCustomSection" type="MyNameSpace.Config.MySection, MyCompileOutput" />
  </configSections>
  <connectionStrings>
   </connectionStrings>
  <appSettings>
     </appSettings>
  
  <MyCustomSection>
    <MyValues>
      <add StationId="O03" MaxPga="5.23" MaxIntensity="1"/>
      <add StationId="O05" MaxPga="6.11" MaxIntensity="4"/>
      <add StationId="O07" MaxPga="6.11" MaxIntensity="4"/>
      <add StationId="O11" MaxPga="6.11" MaxIntensity="4"/>
      <add StationId="O14" MaxPga="6.11" MaxIntensity="4"/>
      <add StationId="O44" MaxPga="6.11" MaxIntensity="4"/>
      <add StationId="O47" MaxPga="6.11" MaxIntensity="4"/>
      <add StationId="O60" MaxPga="6.11" MaxIntensity="4"/>
    </MyValues>
  </MyCustomSection>
</configuration>

有一個重要的地方是,type設定好類別名稱後,後面要接一個組件名稱,不然會找不到類別.

要達到這個目的,要用到幾個類別: ConfigurationSection, ConfigurationElementCollection, ConfigurationElement.顧名思義就是ConfigurationSection對應Section,ConfigurationElementCollection對應MyValues,ConfigurationElement對應一個<add>.

寫一個Section Class繼承ConfigurationSection,我們的Section裡只有一個列表,所以就有一個回傳列表的方法,要注意的是ConfigurationProperty第一個參數字串就是你app.config裡對應的tag名稱.當你需要修改Section裡的資料時才需要override IsReadOnly()這個方法.

 public class MySection : ConfigurationSection
    {
        public override bool IsReadOnly()
        {
            //return base.IsReadOnly();
            return false;
        }

        [ConfigurationProperty("MyValues", IsRequired = false, IsDefaultCollection = true)]
        public MaxValueCollection MaxValues
        {
            get
            {
                MaxValueCollection maxValues = (MaxValueCollection)base["MyValues"];
                return maxValues;
            }
        }
    }

回傳的MaxValueCollection就是繼承ConfigurationElementCollection的類別,沒甚麼特別就不說明了.

 public class MaxValueCollection : ConfigurationElementCollection
    {
        public MaxValueCollection() { }

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

        public MaxValueElement this[int index]
        {
            get { return (MaxValueElement)BaseGet(index); }
            set
            {
                if (BaseGet(index) != null)
                {
                    BaseRemoveAt(index);
                    BaseAdd(index, value);
                }
            }
        }

        public MaxValueElement this[string key]
        {
            get { return (MaxValueElement)BaseGet(key); }
            set
            {
                if (BaseGet(key) != null)
                {   
                    BaseRemove(key);
                    BaseAdd(value);
                }
            }
        }

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

        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((MaxValueElement)element).StationId;
        }

        public void Add(MaxValueElement element)
        {
            BaseAdd(element);
        }

        //public void Clear()
        //{
        //    BaseClear();            
        //}

        //public void Remove(string name)
        //{
        //    BaseRemove(name);
        //}
    }

MaxValueElement繼承ConfigurationElementCollection,就是實際上記錄著資料的Entry.要注意ConfigurationProperty裡的字串就是<add>裡面Attribute的名稱,用base[]取得值時也要用相同的字串.

 public class MaxValueElement : ConfigurationElement
    {
        public MaxValueElement()
        {
        }

        public MaxValueElement(string stationId, float maxPga, int maxIntensity) 
        {
            base["StationId"] = stationId;
            base["MaxPga"] = maxPga;
            base["MaxIntensity"] = maxIntensity;
        }

        public override bool IsReadOnly()
        {
            //return base.IsReadOnly();
            return false;
        }

        [ConfigurationProperty("StationId")]
        public string StationId { get { return base["StationId"].ToString(); } }
        [ConfigurationProperty("MaxPga")]
        public double MaxPga { get { return double.Parse(base["MaxPga"].ToString()); } set { base["MaxPga"] = value; } }
        [ConfigurationProperty("MaxIntensity")]
        public int MaxIntensity { get { return int.Parse(base["MaxIntensity"].ToString()); } set { base["MaxIntensity"] = value; } }
    }

接下來就是實際應用了,如果單純只是讀取的話,用Configuration.GetSection("") as CustomSection.接下來就可以用強型別讀取了.GetSection的參數是<section>裡name的值.如果要修改的話,就比較複雜一點.要用適當的層級(Level)去取得Configuration.然後設定強制Save.如下面的code

 Configuration l_appcfg = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            MySection l_mySection = l_appcfg.GetSection("MyCustomSection") as MySection;
            l_mySection.SectionInformation.ForceSave = true;
//用強型別修改你要修改的值...
            l_appcfg.Save(ConfigurationSaveMode.Full);
            ConfigurationManager.RefreshSection("MyCustomSection");

修改完記得儲存和更新.

My WP Blog with english technical docs.