.Net本身有系統參數設置機制(Configuration System),其加入的外部設定檔稱為Application Configuration File。光看全名會不懂是什麼東西,其實就是.Net App(ASP.NET, .Net Console, Window Form App)的Web.config, App.config。Section為設定區間的最小單位。因為Application Configuration File是.Net Configuration System提供的,所以有既有的XML Schema,如:<configuration>, <runtime>, <assemblyBinding>...等,這些Schema對應到.Net Configuration System的功能。但如果要加入自己的設定Section要如何加呢?在限量教學之前讓我們先來看看一些概念。
Application Configuration File的Schema為樹狀結構,最底層的Schema為<configuration>,接著為<sectionGroup>,最後為<section>。如果要引用自訂的Section,必須在內建Schema <configSections>區間中定義我們要的Schema。你一定會想說那怎麼那些內建Schema都沒有定義?答案是有的,其實系統在運行啟動時,會先去.Net Framework資料夾底下讀取Machine.config,Machine.config裏頭就定義了那些內建Schema,例如:<appSettings>, <runtime>, <system.web>...等,所以App.config可以說是繼承Machine.config。
再來分別說明Section與SectionGroup:
我們先來看一段自定義Section的區段:
App.config
要自訂Section時,要在<configSections>區間裡定義。<configSections>會在系統啟動時先被載入,這樣後面.Net Configuration System才能識別。接著填入name與type的值,name代表的是後面.Net Configuration System要識別的Schema名稱(在上面範例中,限量定義Test的Schema,所以name的值要填"Test");type則是自訂Section的類別路徑,格式就像寫國外郵件地址一樣範圍由小到大(Namespace + Class, Namespace)。我們再來看看自訂Section的類別:
TestSection.cs
CommEle.cs
概念很簡單,在.Net Configuration類別中,最基本的元素反而是ConfigurationElement,ConfigurationSection就繼承ConfigurationElement。所有在Schema中的Attribute都在類別中用Property表示,並透過ConfigurationProperty指示在Schema中對應的Attribute名稱(例如:在TestSection類別中,Type Property在App.config中對應的是type Attribute)。Section內的巢狀設定都要自訂ConfigurationElement類別(例如:CommEle),而巢狀設定的Property只要設置get就好了,因為.Net Configuration會自動幫我們產生巢狀設定類別的實體。下面我們來看看如何使用.Net Configuration取得自訂Section:
Program.cs
使用方式就是要引入System.Configuration,然後使用ConfigurationManager.GetSection方法取得目標Section,因為回傳的是物件,所以記得要轉型成Section類別,接著就可以在VS的Intelligent Sense裡看到我們定義的Property。
使用ConfigurationManager.GetSection是快速的方法,直接針對目標Section去取得。如果想要從整個Config資料去取得Section可以用以下方法:
呼叫ConfigurationManager.OpenExeConfiguration()可以取得整個App.config檔Parse出來的資訊,因為範例中的Section在第一層,所以直接在Section屬性中指定Index Name就可以取得,但若Section是在SectionGroup裡面的話,就要遞迴一層一層的去Parse。
範例情境為一個服務,定義了各個公司所定義的系統參數,這樣一來透過SectionGroup就可以以各公司的設定進而提供服務。
App.config
Program.cs
在這裡使用GetSection,裡面放的Section名稱要是絕對路徑,會比較快找到目標Section。但如果要用整個樹狀結構去找的話可以用以下方法:
.Net Configuration System的基本使用大概就是這樣,接著後面還有許多種變化的應用,像是巢狀設定, 多設定值陣列, 泛型應用...等,限量會再持續更新。
站內相關文章:
C# - App.config自訂section程式碼架構Part II (巢狀, 陣列)
C# - App.config自訂section程式碼架構Part III (使用泛型)
參考來源:
MSDN - Application Configuration Files
Application Configuration File的Schema為樹狀結構,最底層的Schema為<configuration>,接著為<sectionGroup>,最後為<section>。如果要引用自訂的Section,必須在內建Schema <configSections>區間中定義我們要的Schema。你一定會想說那怎麼那些內建Schema都沒有定義?答案是有的,其實系統在運行啟動時,會先去.Net Framework資料夾底下讀取Machine.config,Machine.config裏頭就定義了那些內建Schema,例如:<appSettings>, <runtime>, <system.web>...等,所以App.config可以說是繼承Machine.config。
再來分別說明Section與SectionGroup:
Section
Section為.Net Configuration System區間的最小單位,但是Section裡面還可以有許多巢狀的設定結構,但是內部結構就不叫Section,而是ConfigurationElement。我們先來看一段自定義Section的區段:
App.config
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="Test" type="TestSolution.TestSection, TestSolution" /> </configSections> <Test name="MyTestConfig" type="Console"> <Comm value="0" /> </Test> </configuration>
要自訂Section時,要在<configSections>區間裡定義。<configSections>會在系統啟動時先被載入,這樣後面.Net Configuration System才能識別。接著填入name與type的值,name代表的是後面.Net Configuration System要識別的Schema名稱(在上面範例中,限量定義Test的Schema,所以name的值要填"Test");type則是自訂Section的類別路徑,格式就像寫國外郵件地址一樣範圍由小到大(Namespace + Class, Namespace)。我們再來看看自訂Section的類別:
TestSection.cs
public class TestSection : ConfigurationSection { [ConfigurationProperty("name", IsRequired = true)] public string Name { get { return this["name"] as string; } set { this["name"] = value; } } [ConfigurationProperty("type", IsRequired = false)] public string Type { get { return this["type"] as string; } set { this["type"] = value; } } [ConfigurationProperty("Comm")] public CommEle Comm { get { return this["Comm"] as CommEle; } } }
CommEle.cs
public class CommEle : ConfigurationElement { [ConfigurationProperty("value", IsRequired = true)] public string Value { get { return this["value"] as string; } set { this["value"] = value; } } }
概念很簡單,在.Net Configuration類別中,最基本的元素反而是ConfigurationElement,ConfigurationSection就繼承ConfigurationElement。所有在Schema中的Attribute都在類別中用Property表示,並透過ConfigurationProperty指示在Schema中對應的Attribute名稱(例如:在TestSection類別中,Type Property在App.config中對應的是type Attribute)。Section內的巢狀設定都要自訂ConfigurationElement類別(例如:CommEle),而巢狀設定的Property只要設置get就好了,因為.Net Configuration會自動幫我們產生巢狀設定類別的實體。下面我們來看看如何使用.Net Configuration取得自訂Section:
Program.cs
static void Main(string[] args) { var section = ConfigurationManager.GetSection("Test") as TestSection; WriteLine("Name: " + section.Name); WriteLine("Type: " + section.Type); var comm = section.Comm; WriteLine("Value: " + comm.Value); /* 執行結果 * Name: MyTestConfig * Type: Console * Value: 0 */ }
使用方式就是要引入System.Configuration,然後使用ConfigurationManager.GetSection方法取得目標Section,因為回傳的是物件,所以記得要轉型成Section類別,接著就可以在VS的Intelligent Sense裡看到我們定義的Property。
使用ConfigurationManager.GetSection是快速的方法,直接針對目標Section去取得。如果想要從整個Config資料去取得Section可以用以下方法:
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); var section = config.Sections["Test"] as TestSection;
呼叫ConfigurationManager.OpenExeConfiguration()可以取得整個App.config檔Parse出來的資訊,因為範例中的Section在第一層,所以直接在Section屬性中指定Index Name就可以取得,但若Section是在SectionGroup裡面的話,就要遞迴一層一層的去Parse。
SectionGroup
各Section代表的是不同種類的設定,而SectionGroup可以算是包裝Section的容器。在同一個App.config中,同一個Section是可以出現多次的,但是為了增加識別性就必須在外層套上SectionGroup,以檔案系統比喻來說,Section就像是檔案一樣,每個檔案都是獨立的個體,可是同一個檔案可以到處複製的,所以SectionGroup就像資料夾一樣,裡頭可以有各種不同的Section,而對於不同SectionGroup相同Section的來說,他們的絕對路徑是一定不相同的,藉此才識別,以下為有SectionGroup的情況下,取得Section資訊的範例:範例情境為一個服務,定義了各個公司所定義的系統參數,這樣一來透過SectionGroup就可以以各公司的設定進而提供服務。
App.config
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <sectionGroup name="CompanyA"> <sectionGroup name="Debug"> <section name="Setting" type="TestSolution.TestSection, TestSolution" /> </sectionGroup> <sectionGroup name="Online"> <section name="Setting" type="TestSolution.TestSection, TestSolution" /> </sectionGroup> </sectionGroup> <sectionGroup name="CompanyB"> <sectionGroup name="Debug"> <section name="Setting" type="TestSolution.TestSection, TestSolution" /> </sectionGroup> <sectionGroup name="Online"> <section name="Setting" type="TestSolution.TestSection, TestSolution" /> </sectionGroup> </sectionGroup> </configSections> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> </startup> <CompanyA> <Debug> <Setting name="CompanyADebug" type="Console"> <Comm value="0" /> </Setting> </Debug> <Online> <Setting name="CompanyAOnline" type="Web"> <Comm value="1" /> </Setting> </Online> </CompanyA> <CompanyB> <Debug> <Setting name="CompanyBDebug" type="Service"> <Comm value="2" /> </Setting> </Debug> <Online> <Setting name="CompanyBOnline" type="Window"> <Comm value="3" /> </Setting> </Online> </CompanyB> </configuration>
Program.cs
static void Main(string[] args) { var companyADebug = ConfigurationManager.GetSection("CompanyA/Debug/Setting") as TestSection; var companyAOnline = ConfigurationManager.GetSection("CompanyA/Online/Setting") as TestSection; OutputInfo(companyADebug); OutputInfo(companyAOnline); var companyBDebug = ConfigurationManager.GetSection("CompanyB/Debug/Setting") as TestSection; var companyBOnline = ConfigurationManager.GetSection("CompanyB/Online/Setting") as TestSection; OutputInfo(companyBDebug); OutputInfo(companyBOnline); /* 執行結果 * Name: CompanyADebug * Type: Console * Value: 0 * * Name: CompanyAOnline * Type: Web * Value: 1 * * Name: CompanyBDebug * Type: Service * Value: 2 * * Name: CompanyBOnline * Type: Window * Value: 3 */ Read(); } static void OutputInfo(TestSection section) { WriteLine("Name: " + section.Name); WriteLine("Type: " + section.Type); var comm = section.Comm; WriteLine("Value: " + comm.Value); WriteLine(); }
在這裡使用GetSection,裡面放的Section名稱要是絕對路徑,會比較快找到目標Section。但如果要用整個樹狀結構去找的話可以用以下方法:
static void Main(string[] args) { var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); IterateSectionGroup(config.SectionGroups); /* 執行結果 * Name: CompanyADebug * Type: Console * Value: 0 * * Name: CompanyAOnline * Type: Web * Value: 1 * * Name: CompanyBDebug * Type: Service * Value: 2 * * Name: CompanyBOnline * Type: Window * Value: 3 */ Read(); } static void IterateSectionGroup(ConfigurationSectionGroupCollection groups) { foreach(ConfigurationSectionGroup group in groups) { if(group.GetType() == typeof(ConfigurationSectionGroup)) { if(group.SectionGroups.Count > 0) IterateSectionGroup(group.SectionGroups); foreach(var section in group.Sections) { OutputInfo(section as TestSection); } } } } static void OutputInfo(TestSection section) { WriteLine("Name: " + section.Name); WriteLine("Type: " + section.Type); var comm = section.Comm; WriteLine("Value: " + comm.Value); WriteLine(); }
.Net Configuration System的基本使用大概就是這樣,接著後面還有許多種變化的應用,像是巢狀設定, 多設定值陣列, 泛型應用...等,限量會再持續更新。
站內相關文章:
C# - App.config自訂section程式碼架構Part II (巢狀, 陣列)
C# - App.config自訂section程式碼架構Part III (使用泛型)
參考來源:
MSDN - Application Configuration Files
留言
張貼留言