【.net 深呼吸】自定义应用程序配置节
實際上,應用程序配置文件 App.config,是由各個節(Configuration Section)組成的,通常,配置節是按功能劃分的,比如我們很熟悉的 appSettings、connectionStrings、startup、system.ServiceModel……
在實際開發中,我們的應用程序也應該需要一個咱們程序專且功能的配置節,這樣也方便我們在代碼中通過相關的API來讀取,而不是用普通的XML文件讀取方法。
其實,實現自定義配置節并不難,只是,有幾個問題要注意。
老周一邊給大伙伴們演示一邊講解,這樣會比較有情調。
要自定義應用配置節,必須從?ConfigurationSection 類派生,該類是個抽象類,所以我們必須以其作為基類來定義自己的配置節。雖然它是一個抽象類,但是,功能很完善,多數情況下,我們是不需要重寫它的成員(特殊需求的話,可以按需重寫),給大家演示一下,看看我這個類。
public class MyDemoSection : ConfigurationSection{……}那么,我們在這個類中要干啥呢?我們要給它添加我們需要的屬性。比如,我需要兩個屬性——一個 User,字符串類型;另一個Age,類型為int。
public class MyDemoSection : ConfigurationSection{public string User{get {……}set { ……}}public int Age{get { ……}set { …… }}}這時候,你一定會想到一個問題:那配置文件API在保存到配置文件時,是如何識別的呢。其實這個?ConfigurationSection 類的基類是?ConfigurationElement。ConfigurationElement 是所有配置文件元素的共同基類。配置節實則就是一種特殊的配置元素,它與普通的配置元素的區別在于,配置節通常作為一類功能的主節點。而配置節的子元素就是普通的配置元素;配置節在使用前必須在?configSections 節點下進行聲明,聲明后才能在配置文件中使用。這個咱們后面再談。
?
ConfigurationElement 類公開了以下兩個版本的索引器:
protected internal object this[string propertyName] { get; set; }protected internal object this[ConfigurationProperty prop] { get; set; }我們一般用的是帶string參數的版本,這個索引器只能在派生類中訪問,不對外部公開。而?ConfigurationSection 類是從?ConfigurationElement 類派生的,自然會繼承這個索引器。
所以,我們在自定義配置節的屬性包裝中,可以通過這個索引器來存取內容,其操作方法類似于字典。
public class MyDemoSection : ConfigurationSection{public string User{get { return (string)this["user"]; }set { this["user"] = value; }}public int Age{get { return (int)this["age"]; }set { this["age"] = value; }}}?
代碼寫到這里,貌似是完成了,其實未然。這時候,如果你想用代碼把這個自定義節點寫入配置文件,就會收到以下異常。
因為我們的自定義配置節類還沒有完工,還差一個 Attribute 沒有應用。應該這樣寫。
[ConfigurationProperty("user")]public string User{get { return (string)this["user"]; }set { this["user"] = value; }}[ConfigurationProperty("age")]public int Age{get { return (int)this["age"]; }set { this["age"] = value; }}注意,嚴重要注意!!應用的ConfigurationPropertyAttribute 中指定的name一定要和索引器(this["....."])中使用的名字相同,比如上面的代碼,age要一致,如果改為這樣,就會報錯。
[ConfigurationProperty("number")]public int Age{get { return (int)this["age"]; }set { this["age"] = value; }}因為 number 和 age 不匹配,不過,類型的屬性名不要求,比如,Age屬性可以改為 Num。
[ConfigurationProperty("age")]public int Num{get { return (int)this["age"]; }set { this["age"] = value; }}把屬性名改為 Num 是不會報錯的。只要?ConfigurationPropertyAttribute 中的 name 參數與索引器中的名字一致即可。
?
下面,我們試試這個自定義配置節,我們通過代碼來配置,然后保存到 App.Config 中。
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);MyDemoSection sect = new MyDemoSection();config.Sections.Add("myInfo", sect);//sect.SectionInformation.ForceSave = false;sect.User = "Ben Dan";sect.Age = 25;// 保存config.Save(ConfigurationSaveMode.Modified);通過....Sections.Add 方法就可以把自定義的配置節添加配置文件中,其中,有一個name 參數,它用來指定在使用該配置時的XML元素名稱。這個你如果不理解,不急,你先記住我們代碼中寫的名字叫 myInfo。
然后執行一下上面的代碼,再打開與應用程序相關的App.config文件,注意不是項目中的config文件,是bin\\ 目錄下的。打開后你會看到這樣的內容。
<configuration><configSections><section name="myInfo" type="CustConfigs.MyDemoSection, CaiDemo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> </configSections>??? <myInfo user="Ben Dan" age="25" />
…… </configuration>
怎么樣,你現在看明白了沒,知道那個 myInfo 怎么用了吧。
首先,要在?configSections 節中用?section 元素來配置一下自定義配置節的類型,type指定的就是我們剛剛定義的那個?MyDemoSection 類,其實只需要寫上類型名和程序集名即可。name 指定一個名稱,就是你隨后在配置文件使用時的XML元素名,如本例中的 myInfo。
?在上面的代碼中,可能你注意到有一行代碼被注釋了,
sect.SectionInformation.ForceSave = false;MSDN 上說,這個屬性指示是否要強制保存配置節的內容,哪怕它沒有被修改過,這里我用不上,就注釋掉了,因為MSDN上的示例有這一行,我故意加上來裝逼一下的。
?
剛才,我們通過代碼應用我自定義配置節,內容已寫入 app.config 文件,此時我們如果再次運行上面的代碼,你會發現報錯了。
原來配置節是不能重復 Add 的,所以我們改改代碼,先進行判斷。
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);MyDemoSection sect = config.Sections["myInfo"] as MyDemoSection;if(sect == null){sect = new MyDemoSection();config.Sections.Add("myInfo", sect);} sect.User = "Ben Dan";sect.Age = 25;// 保存config.Save(ConfigurationSaveMode.Modified);好了,這樣可避免報錯了。
?
接下來,老周再給各位舉一例,這一次我們不用代碼來寫配置文件,而是直接編輯配置文件,然后在代碼中讀出配置信息。這種做法應該最常用。
還是那樣,我們自定義一個配置節類型。
public class DBSection : ConfigurationSection{[ConfigurationProperty("dbName", DefaultValue = "db.mdf")]public string DBName{get { return (string)this["dbName"]; }set { this["dbName"] = value; }}[ConfigurationProperty("loginName", DefaultValue = "sa")]public string LoginName{get { return (string)this["loginName"]; }set { this["loginName"] = value; }}}假設,DBName 表示數據庫文件的名字,LoginName表示登入 MSSQL 的名稱(默認是 sa)。
?
然后,我們打開\bin\debug 下面的app.config,注意,不是項目中的配置文件。先為自定義配置節進行聲明。
<configSections> <section name="db" type="CustConfigs.DBSection, CaiDemo"/> </configSections>這時候,要配置的話,XML元素名為db。
<db dbName ="app.mdf" loginName="admin" />注意這里設置的屬性名不是類上的屬性名,而是?ConfigurationPropertyAttribute 所指定的名稱。
?
現在,我們在代碼中讀出這些配置參數。
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);DBSection sect = config.Sections["db"] as DBSection;if (sect != null){string s = $"數據庫:{sect.DBName},登錄名:{sect.LoginName}。";Console.WriteLine(s);}注意剛剛我們在配置文件中聲明時,給自定義節的元素命名為 db 。
<section name="db" type="CustConfigs.DBSection, CaiDemo"/>所以,我們讀的時候,也要用 db 作為名字取出配置節實例,然后再讀屬性的值。
最后,輸出結果如下:
?
?好了,今天的內容就扯到這里吧,這個玩意兒,大家學會之后,還是很有實戰價值的,而且也不難。
?
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的【.net 深呼吸】自定义应用程序配置节的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 搭建MongoDB分片集群
- 下一篇: BZOJ 1046: [HAOI2007