前言html
昨天修改代碼發現了一個問題,因爲本身要在WCF服務接口中添加了一個方法,那麼在相應調用的地方進行更新服務就能夠了,不料意外發生了,居然沒法更新。左查右查終於發現了問題。App.config配置文件中的配置貌似出現了問題。查找節點發現是以下節點:web
<configSections> <section name="Test1" type="Demo.Section1,Demo"/> .............. </configSections>
我當時也只是看到了下劃波浪線,才猜想是這裏的問題,因而我把configSections節點註釋後,從新更新WCF服務,沒想到真的能夠更新了,心想這是個什麼節點呢,雖然以前本身也見過這個節點,可是歷來沒用過,因而趁此機會就進行簡單的學習一下吧,以便以後說不定何時就會用到。數據庫
這裏個人講解暫時之針對.NET的Web.config文件和App.confg文件,也就是對.Net配置文件自定義節點進行學習記錄。緩存
配置文件優先級服務器
在此簡單的學習一個配置文件的優先級吧,由於本身以前對配置文件接觸的也比較少,沒詳細的進行學習過。app
首先在.net提供了一個針對當前機器的配置文件,這個文件是machine.config。所在地址以下圖所示。asp.net
而後此文件夾下還存在一個Web.confg的配置文件。ide
asp.net網站IIS啓動的時候會加載配置文件中的配置信息,而後緩存這些信息,這樣就沒必要每次去讀取配置信息。在運行過程當中asp.net應用程序會監視配置文件的變化狀況,一旦編輯了這些配置信息,就會從新讀取這些配置信息並緩存。函數
一、若是在當前頁面所在目錄下存在web.config文件,查看是否存在所要查找的結點名稱,若是存在返回結果並中止查找。
二、若是當前頁面所在目錄下不存在web.config文件或者web.config文件中不存在該結點名,則查找它的上級目錄,直到網站的根目錄。工具
三、若是網站根目錄下不存在web.config文件或者web.config文件中不存在該節點名則在C:WindowsMicrosoft.NETFrameworkv4.0.30319Config/web.config文件中查找。(這是我本機的地址,請根據狀況進行調整)
四、若是在C:WindowsMicrosoft.NETFrameworkv4.0.30319Config/web.config文件中不存在相應結點,則在C:WindowsMicrosoft.NETFrameworkv4.0.30319Config/machine.config文件中查找。
五、若是仍然沒有找到則返回null。
因此若是咱們對某個網站或者某個文件夾有特定要求的配置,能夠在相應的文件夾下建立一個web.config文件,覆蓋掉上級文件夾中的web.config文件中的同名配置便可。這些配置信息的尋找只查找一次,之後便被緩存起來供後來的調用。在asp.net應用程序運行過程當中,若是web.config文件發生更改就會致使相應的應用程序從新啓動,這時存儲在服務器內存中的用戶會話信息就會丟失(如存儲在內存中的Session)。
因此若是咱們對某個網站或者某個文件夾有特定要求的配置,能夠在相應的文件夾下建立一個web.config文件,覆蓋掉上級文件夾中的web.config文件中的同名配置便可。這些配置信息的尋找只查找一次,之後便被緩存起來供後來的調用。在asp.net應用程序運行過程當中,若是web.config文件發生更改就會致使相應的應用程序從新啓動,這時存儲在服務器內存中的用戶會話信息就會丟失(如存儲在內存中的Session)。一些軟件(如殺毒軟件)每次完成對web.config的訪問時就會修改web.config的訪問時間屬性,也會致使asp.net應用程序的重啓。
經常使用配置文件節點appSettings和connectionSettings說明
一、<appSettings>節點
<appSettings>節點主要用來存儲asp.net應用程序的配置信息,例如網站上傳文件的類型:
<appSettings> <!--容許上傳的格式類型--> <add key="ImageType" value=".jpg;.bmp;.gif;.png;.jpeg"/> <!--容許上傳的文件類型--> <add key="FileType" value=".jpg;.bmp;.gif;.png;.jpeg;.pdf;.zip;.rar;.xls;.doc"/> </appSettings>
對於<appSettings>節點中的值能夠按照key來進行訪問,如下就是一個讀取key值爲「FileType」節點值的例子:
string fileType=ConfigurationManager.AppSettings["FileType "];
二、<connectionStrings>節點
<connectionStrings>節點主要用於配置數據庫鏈接的,咱們能夠<connectionStrings>節點中增長任意個節點來保存數據庫鏈接字符串,未來在代碼中經過代碼的方式動態獲取節點的值來實例化數據庫鏈接對象,這樣一旦部署的時候數據庫鏈接信息發生變化咱們僅須要更改此處的配置便可,而沒必要由於數據庫鏈接信息的變化而須要改動程序代碼和從新部署。數據庫連接示例以下:
<connectionStrings> <add name="OraProfileConnString" connectionString="user id=admin;data source=CRMDB;password=123456;" providerName="System.Data.OracleClient"/> </connectionStrings>
在代碼中咱們能夠這麼實例化數據庫鏈接對象:
///1讀取web.config文件節點配置 string ConnectionStringProfile = ConfigurationManager.ConnectionStrings["OraProfileConnString"].ConnectionString; ///2實例化OracleConnection對象 OracleConnection conn = new OracleConnection(ConnectionStringProfile);
這樣作的好處是一旦開發時所用的數據庫和部署時的數據庫不一致,僅僅須要用記事本之類的文本編輯工具編輯connectionString屬性的值就好了。
自定義節點配置解析
通過查閱資料發現,有些人和我同樣,只用過我上面說的兩個節點,可是若是參數過多,這種作法的缺點也會明顯地暴露出來:appSetting中的配置參數項只能按key名來訪問,不能支持複雜的層次節點也不支持強類型, 並且因爲全都只使用這一個集合,你會發現:徹底不相干的參數也要放在一塊兒!解決的方法即是使用自定義節點配置來解析。
咱們來看一下如何在app.config或者web.config中增長一個自定義的配置節點。 在這篇博客中,我將介紹4種自定義配置節點的方式。
一、第一種狀況——Property
配置文件以下,依照屬性的方式處理:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="Test1" type="Demo.Section1,Demo"/> </configSections> <Test1 UserName="aehyok" Path="www.cnblogs.com/aehyok"></Test1> </configuration>
自定義一個類,以ConfigurationSection爲基類,各個屬性要加上[ConfigurationProperty] ,ConfigurationProperty的構造函數中傳入的name字符串將會用於config文件中,表示各參數的屬性名稱。
屬性的值的讀寫要調用this[],由基類去保存。
爲了能使用配置節點能被解析,須要在<configSections>中註冊,代碼如上<section name="Test1" type="Demo.Section1,Demo"/>。
實現代碼以下:
namespace Demo { public class Section1 : ConfigurationSection { [ConfigurationProperty("UserName")] public string UserName { get { return this["UserName"].ToString(); } set { this["UserName"] = value; } } [ConfigurationProperty("Path")] public string Path { get { return this["Path"].ToString(); } set { this["Path"] = value; } } } }
下面將要介紹另三種配置節點雖然複雜一點,可是一些基礎的東西與這個節點是同樣的,因此後面我就再也不重複說明了。
二、第二種狀況——Element
配置文件以下:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="Test2" type="Demo.Section2,Demo"/> </configSections> <Test2> <Users UserName="aehyok" Password="123456"></Users> </Test2> </configuration>
實現代碼以下:
namespace Demo { public class Section2 : ConfigurationSection { [ConfigurationProperty("Users", IsRequired = true)] public SectionElement Users { get { return (SectionElement)this["Users"]; } } public class SectionElement : ConfigurationElement { [ConfigurationProperty("UserName", IsRequired = true)] public string UserName { get { return this["UserName"].ToString(); } set { this["UserName"] = value; } } [ConfigurationProperty("Password", IsRequired = true)] public string Password { get { return this["Password"].ToString(); } set { this["Password"] = value; } } } } }
第二種狀況比第一種狀況的區別就是,數據類型也是本身定義的,具體的配置屬性寫在ConfigurationElement的繼承類中。
三、第三種狀況——CDATA
CDATA能夠包含比較長的字符串,且能夠包含HTML代碼段,這樣針對特殊字符的存放也比較方便。假如以下配置:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="Test3" type="Demo.Section3,Demo"/> </configSections> <Test3> <T1> <![CDATA[ Create proc _bank @param1 char(10),@param2 varchar(20),@param3 varchar(20),@param4 int,@param5 int output with encryption ---------加密 as bankMoney (id,userID,sex,Money) Values(@param1,@param2,@param3, @param4) @param5=sum(Money) bankMoney where userID=""Zhangsan"" go ]]> </T1> <T2> <![CDATA[ <html> <head> <title>Test</title> </head> <body> This is Test。 </body> </html> ]]> </T2> </Test3> </configuration>
代碼實現以下:
namespace Demo { public class Section3 : ConfigurationSection { [ConfigurationProperty("T1", IsRequired = true)] public MyTextElement Command1 { get { return (MyTextElement)this["T1"]; } } [ConfigurationProperty("T2", IsRequired = true)] public MyTextElement Command2 { get { return (MyTextElement)this["T2"]; } } } public class MyTextElement : ConfigurationElement { protected override void DeserializeElement(XmlReader reader, bool serializeCollectionKey) { CommandText = reader.ReadElementContentAs(typeof(string), null) as string; } protected override bool SerializeElement(XmlWriter writer, bool serializeCollectionKey) { if (writer != null) writer.WriteCData(CommandText); return true; } [ConfigurationProperty("data", IsRequired = false)] public string CommandText { get { return this["data"].ToString(); } set { this["data"] = value; } } } }
這裏由咱們控制對數據的讀寫操做,也就是要重載方法SerializeElement,DeserializeElement。
四、第四種狀況——Collection
配置信息以下:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="Test4" type="Demo.Section4,Demo"/> </configSections> <Test4> <add key="1" value="aehyok"></add> <add key="2" value="Leo"></add> <add key="3" value="Lynn"></add> </Test4> </configuration>
爲每一個集合中的參數項建立一個從ConfigurationElement繼承的派生類,可參考Section1。
爲集合建立一個從ConfigurationElementCollection繼承的集合類,具體在實現時主要就是調用基類的方法。
在建立ConfigurationSection的繼承類時,建立一個表示集合的屬性就能夠了,注意[ConfigurationProperty]的各參數。
實現代碼以下:
namespace Demo { public class Section4 : ConfigurationSection { private static readonly ConfigurationProperty s_property = new ConfigurationProperty(string.Empty, typeof(MyKeyValueCollection), null, ConfigurationPropertyOptions.IsDefaultCollection); [ConfigurationProperty("", Options = ConfigurationPropertyOptions.IsDefaultCollection)] public MyKeyValueCollection KeyValues { get { return (MyKeyValueCollection)base[s_property]; } } } [ConfigurationCollection(typeof(MyKeyValueSetting))] public class MyKeyValueCollection : ConfigurationElementCollection // 自定義一個集合 { // 基本上,全部的方法都只要簡單地調用基類的實現就能夠了。 public MyKeyValueCollection() : base(StringComparer.OrdinalIgnoreCase) // 忽略大小寫 { } // 其實關鍵就是這個索引器。但它也是調用基類的實現,只是作下類型轉就好了。 new public MyKeyValueSetting this[string name] { get { return (MyKeyValueSetting)base.BaseGet(name); } } // 下面二個方法中抽象類中必需要實現的。 protected override ConfigurationElement CreateNewElement() { return new MyKeyValueSetting(); } protected override object GetElementKey(ConfigurationElement element) { return ((MyKeyValueSetting)element).Key; } // 說明:若是不須要在代碼中修改集合,能夠不實現Add, Clear, Remove public void Add(MyKeyValueSetting setting) { this.BaseAdd(setting); } public void Clear() { base.BaseClear(); } public void Remove(string name) { base.BaseRemove(name); } } public class MyKeyValueSetting : ConfigurationElement // 集合中的每一個元素 { [ConfigurationProperty("key", IsRequired = true)] public string Key { get { return this["key"].ToString(); } set { this["key"] = value; } } [ConfigurationProperty("value", IsRequired = true)] public string Value { get { return this["value"].ToString(); } set { this["value"] = value; } } }
讀取配置文件信息
四個Read進行讀取數據的代碼以下:
private void button1_Click(object sender, EventArgs e) { Section1 sectioin1 = (Section1)ConfigurationManager.GetSection("Test1"); txtUserName.Text = sectioin1.UserName; txtPath.Text = sectioin1.Path; } private void button4_Click(object sender, EventArgs e) { Section2 sectioin2 = (Section2)ConfigurationManager.GetSection("Test2"); txtUName.Text = sectioin2.Users.UserName; txtPassword.Text = sectioin2.Users.Password; } private void button6_Click(object sender, EventArgs e) { Section3 section3 = (Section3)ConfigurationManager.GetSection("Test3"); T1.Text = section3.T1.CommandText.Trim(); T2.Text = section3.T2.CommandText.Trim(); } private void button8_Click(object sender, EventArgs e) { Section4 section4 = (Section4)ConfigurationManager.GetSection("Test4"); txtKeyValues.Text = string.Join("", ( kv in section4.KeyValues.Cast<MyKeyValueSetting>() let s = string.Format("{0}={1}", kv.Key, kv.Value) s).ToArray()); }
執行點擊以後數據讀取以下圖所示,也就是數據讀取成功。
在讀取自定節點時,咱們須要調用ConfigurationManager.GetSection()獲得配置節點,並轉換成咱們定義的配置節點類,而後就能夠按照強類型的方式來訪問了。
寫入配置文件信息
首先定義一個全局變量,代碼以下
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
四個Write保存按鈕以下:
private void button2_Click(object sender, EventArgs e) { Section1 sectioin1 = config.GetSection("Test1") as Section1; sectioin1.UserName = txtUserName.Text; sectioin1.Path = txtPath.Text; config.Save(); } private void button3_Click(object sender, EventArgs e) { Section2 sectioin2 = config.GetSection("Test2") as Section2; sectioin2.Users.UserName = txtUName.Text; sectioin2.Users.Password = txtPassword.Text; config.Save(); } private void button5_Click(object sender, EventArgs e) { Section3 section3 = config.GetSection("Test3") as Section3; section3.T1.CommandText = T1.Text.Trim(); section3.T2.CommandText = T2.Text.Trim(); config.Save(); } private void button7_Click(object sender, EventArgs e) { Section4 section4 = config.GetSection("Test4") as Section4; section4.KeyValues.Clear(); ( s in txtKeyValues.Lines let p = s.IndexOf(""="") where p > 0 new MyKeyValueSetting { Key = s.Substring(0, p), Value = s.Substring(p + 1) } ).ToList() .ForEach(kv => section4.KeyValues.Add(kv)); config.Save(); }
在修改配置節點前,咱們須要調用ConfigurationManager.OpenExeConfiguration(),而後調用config.GetSection()在獲得節點後,轉成咱們定義的節點類型, 而後就能夠按照強類型的方式來修改咱們定義的各參數項,最後調用config.Save();便可。 .net爲了優化配置節點的讀取操做,會將數據緩存起來,若是但願使用修改後的結果生效,您還須要調用ConfigurationManager.RefreshSection方法。若是是修改web.config,則須要使用 WebConfigurationManager。
最終修改效果展現動態圖
總結
一、本文主要參考大神做品http://www.cnblogs.com/fish-li/archive/2011/12/18/2292037.html從中學習取經。
二、經過本文本人也學習到了不少關於配置文件的知識,以前都沒有接觸學習過。
三、打算再將其餘的節點設置進行學習記錄下。
四、本文示例代碼連接http://pan.baidu.com/s/1o6JgUBg
五、ConfigSource的使用也比較有意思,本身以前整理的一篇文章,惋惜在真實項目中沒用過。
例如:
<appSettings configSource="configMy.config" />
就是關於appSettings下的配置節點都配置到了configMy.config文件中。
有關博文連接http://www.cnblogs.com/aehyok/archive/2013/05/23/3095019.html