1. 程式人生 > >【.net 深呼吸】自定義應用程序配置節

【.net 深呼吸】自定義應用程序配置節

system 深呼吸 進行 eve none 價值 判斷 發現 debug

實際上,應用程序配置文件 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 作為名字取出配置節實例,然後再讀屬性的值。

最後,輸出結果如下:

技術分享

好了,今天的內容就扯到這裏吧,這個玩意兒,大家學會之後,還是很有實戰價值的,而且也不難。

【.net 深呼吸】自定義應用程序配置節