.Net中的System.Configuration名稱空間為我們在web.config或者app.config中自定義配置提供了完美的支援。最近看到一些專案中還在自定義xml檔案做程式的配置,所以忍不住寫一篇用系統自定義配置的隨筆了。
如果你已經對自定義配置瞭如指掌,請忽略這篇文章。
言歸正傳,我們先來看一個最簡單的自定義配置
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="simple" type="ConfigExample.Configuration.SimpleSection,ConfigExample"/> </configSections> <simple maxValue="20" minValue="1"></simple> </configuration>
在配置檔案中使用自定義配置,需要在configSections中新增一個section元素,並制定此section元素對應的型別和名字。然後再在configuration根節點下面新增此自定義配置,如上例中的simple節點。simple節點只有兩個整形數的屬性maxValue和minValue。
要在程式中使用自定義配置我們還需要實現存取這個配置塊的型別,一般需要做如下三件事:
1. 定義型別從System.Configuration.ConfigurationSection繼承
2. 定義配置類的屬性,這些屬性需要用ConfigurationProperty特性修飾,並制定屬性在配置節中的名稱和其他一些限制資訊
3. 通過基類的string索引器實現屬性的get ,set
非常簡單和自然,如下是上面配置類的實現:
public class SimpleSection:System.Configuration.ConfigurationSection { [ConfigurationProperty("maxValue",IsRequired=false,DefaultValue=Int32.MaxValue)] public int MaxValue { get { return (int)base["maxValue"]; } set { base["maxValue"] = value; } } [ConfigurationProperty("minValue",IsRequired=false,DefaultValue=1)] public int MinValue { get { return (int) base["minValue"];} set { base["minValue"] = value; } } [ConfigurationProperty("enabled",IsRequired=false,DefaultValue=true)] public bool Enable { get { return (bool)base["enabled"]; } set { base["enabled"] = value; } } }
這樣子一個簡單的配置類就完成了,怎麼在程式中使用這個配置呢?需要使用ConfigurationManager類(要引用System.configuration.dll這個dll只有在.Net2.0之後的版本中才有)的GetSection方法獲得配置就可以了。如下程式碼:
SimpleSection simple = ConfigurationManager.GetSection("simple") as SimpleSection; Console.WriteLine("simple minValue={0} maxValue = {1}",simple.MinValue,simple.MaxValue);
這個配置類太過簡陋了,可能有時候我們還需要更復雜的構造,比如在配置類中使用類表示一組資料,下面我們看一個稍微複雜一點的自定義配置
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="complex" type="ConfigExample.Configuration.ComplexSection,ConfigExample"/> </configSections> <complex height="190"> <child firstName="James" lastName="Bond"/> </complex> </configuration>
這個配置的名字是complex,他有一個屬性height,他的節點內還有一個child元素這個元素有兩個屬性firstName和lastName;對於這個內嵌的節點該如何實現呢?首先我們需要定義一個類,要從ConfigurationElement類繼承,然後再用和SimpleSection類似的方法定義一些用ConfigurationProperty特性修飾的屬性就可以了,當然屬性值的get,set也要使用基類的索引器。如下實現:
public class ComplexSection : ConfigurationSection { [ConfigurationProperty("height", IsRequired = true)] public int Height { get { return (int)base["height"]; } set { base["height"] = value; } } [ConfigurationProperty("child", IsDefaultCollection = false)] public ChildSection Child { get { return (ChildSection)base["child"]; } set { base["child"] = value; } } } public class ChildSection : ConfigurationElement { [ConfigurationProperty("firstName", IsRequired = true, IsKey = true)] public string FirstName { get { return (string)base["firstName"]; } set { base["firstName"] = value; } } [ConfigurationProperty("lastName", IsRequired = true)] public string LastName { get { return (string)base["lastName"]; } set { base["lastName"] = value; } } }
還有稍微再複雜一點的情況,我們可能要在配置中配置一組相同型別的節點,也就是一組節點的集合。如下面的配置:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="complex" type="ConfigExample.Configuration.ComplexSection,ConfigExample"/> </configSections> <complex height="190"> <child firstName="James" lastName="Bond"/> <children> <add firstName="Zhao" lastName="yukai"/> <add firstName="Lee" lastName="yukai"/> <remove firstName="Zhao"/> </children> </complex> </configuration>
請看children節點,它就是一個集合類,在它裡面定義了一組add元素,也可以有remove節點把已經添進去的配置去掉。
要使用自定義節點集合需要從ConfigurationElementCollection類繼承一個自定義類,然後要實現此類GetElementKey(ConfigurationElement element)和ConfigurationElement CreateNewElement()兩個方法;為了方便的訪問子節點可以在這個類裡面定義只讀的索引器。請看下面的實現
public class Children : ConfigurationElementCollection { protected override object GetElementKey(ConfigurationElement element) { return ((ChildSection)element).FirstName; } protected override ConfigurationElement CreateNewElement() { return new ChildSection(); } public ChildSection this[int i] { get { return (ChildSection)base.BaseGet(i); } } public ChildSection this[string key] { get { return (ChildSection)base.BaseGet(key); } } }
當然要使用此集合類我們必須在Complex類中新增一個此集合類的屬性,並要指定集合類的元素型別等屬性,如下:
[ConfigurationProperty("children", IsDefaultCollection = false)] [ConfigurationCollection(typeof(ChildSection), CollectionType = ConfigurationElementCollectionType.AddRemoveClearMap, RemoveItemName = "remove")] public Children Children { get { return (Children)base["children"]; } set { base["children"] = value; } }
我們會經常用到類似appSettings配置節的鍵值對的構造,這時候我們就不必再自己實現了,我們可以直接使用現有的System.Configuration.NameValueConfigurationCollection類來定義一個自定義的鍵值對。可以在Complex類中定義如下屬性
[ConfigurationProperty("NVs", IsDefaultCollection = false)] public System.Configuration.NameValueConfigurationCollection NVs { get { return (NameValueConfigurationCollection)base["NVs"]; } set { base["NVs"] = value; } }
然後在配置檔案的complex節中新增鍵值對配置
<NVs> <add name="abc" value="123"/> <add name="abcd" value="12d3"/> </NVs>
到這兒已經基本上可以滿足所有的配置需求了。不過還有一點更大但是不復雜的概念,就是sectionGroup。我們可以自定義SectionGroup,然後在sectionGroup中配置多個section;分組對於大的應用程式是很有意義的。
如下配置,配置了一個包含simple和一個complex兩個section的sectionGroup
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <sectionGroup type="ConfigExample.Configuration.SampleSectionGroup,ConfigExample" name="sampleGroup"> <section type="ConfigExample.Configuration.SimpleSection,ConfigExample" allowDefinition="Everywhere" name="simple" /> <section type="ConfigExample.Configuration.ComplexSection,ConfigExample" allowDefinition="Everywhere" name="complex"/> </sectionGroup> </configSections> <sampleGroup> <simple maxValue="20" minValue="1"> </simple> <complex height="190"> <child firstName="James" lastName="Bond"/> <children> <add firstName="Zhao" lastName="yukai"/> <add firstName="Lee" lastName="yukai"/> <remove firstName="Zhao"/> </children> <NVs> <add name="abc" value="123"/> <add name="abcd" value="12d3"/> </NVs> </complex> </sampleGroup> </configuration>
為了方便的存取sectionGroup中的section我們可以實現一個繼承自System.Configuration.ConfigurationSectionGroup類的自定義類。實現很簡單,就是通過基類的Sections[“sectionName”]索引器返回Section。如下:
public class SampleSectionGroup : System.Configuration.ConfigurationSectionGroup { public SimpleSection Simple { get { return (SimpleSection)base.Sections["simple"]; } } public ComplexSection Complex { get { return (ComplexSection)base.Sections["complex"]; } } }