忙乎了一天,終於將VS 2005下應用程序配置文件加解密及多項目共用一個配置文件的問題搞定。
實際要求是:因爲準備編寫一個數學試題庫管理系統,自然考慮到要將數據庫連接字符串保存到配置文件中,C#中當然是保存在App.Config文件。如果你的項目名稱是TestLib,生成的可執行文件是TestLib.EXE,配置文件就是TestLib.EXE.Config。因爲數據庫連接的用戶名和密碼都是放在配置文件中,於是考慮到要將連接字符串加密。同時,爲了方便部署,希望編寫一個程序,能夠按照要求修改連接字符串,並將其保存。這個程序要求必須是一個單獨的EXE文件,僅在部署時纔用到它。用戶平時使用題庫時並不需要用它。
先解決數據庫連接字符串加解密的問題。
從“菩提樹下的楊過.Net”的博客中找到了“再談web.config/app.config敏感數據加/解密的二種方法”的文章(http://www.cnblogs.com/yjmyzz/archive/2008/08/22/1274395.html)
加密的方法如下:
//加密web.Config中的指定節
private void ProtectSection(string sectionName)
{
Configuration config = WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
ConfigurationSection section = config.GetSection(sectionName);
if (section != null && !section.SectionInformation.IsProtected)
{
section.SectionInformation.ProtectSection("DataProtectionConfigurationProvider");
config.Save();
}
}
//解密web.Config中的指定節
private void UnProtectSection(string sectionName)
{
Configuration config = WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
ConfigurationSection section = config.GetSection(sectionName);
if (section != null && section.SectionInformation.IsProtected)
{
section.SectionInformation.UnprotectSection();
config.Save();
}
}
雖然是加解密ASP.NET中的Web.Config文件,但只要將
Configuration config = WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
改爲:
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
就可以了。
加密前的配置文件爲:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<connectionStrings>
<add name="MathConnStr" connectionString="Data Source=s10.0.13.100;Initial Catalog=Maths;User ID=Maths;password=5975238"
providerName="System.Data.SqlClient" />
</connectionStrings>
</configuration>
加密後的配置文件爲:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<connectionStrings configProtectionProvider="DataProtectionConfigurationProvider">
<EncryptedData>
<CipherData>
<CipherValue>AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAnnUA3X3xO0G6yCdMO0YNYwQAAAACAAAAAAADZgAAqAAAABAAAAAhKw7WeiJ2xsjZ1uraDXgDAAAAAASAAACgAAAAEAAAAEKF+hGsklR2pcTePGmtB2igAQAAJDN2SLtXGNKojOGq9ukpFTJg0YrNlgEfaosx7Rxm9spCgKqolicr59L6mthOBeUaVxlx3Rk3YACr7IrWGDj6Pbu4macRf5V5TWSxUv+7dqyljS8uvUuEOLfC25Og4sYqyPsYk/dAnOFAFGbRhDGqlpsvGApOGzgb5vUorzqVVvvK38jdQU/klgqLcDJ5K+WC7GPTcuAfRrCcnvkHA2wPDb+XQGF9Y7ErmoQLazPlBOkIE6qyXQ/6xVEcIc/7FMX3KSgzxTGcITFHBxby/ZIFQ15uauHaxXR1v+gm22pG8o3lLZ1pw/7q5sBpR2wNdlNnl1ExB/t9PK6OFAITV2vOGL8tlx+Gl32+A3EsGGz7GKX3rdpKquugNuBytF3TYYl10k2Z1U/vLMgeUMhG0Ntdb4JJll4VbFmIS9AyBvxM5sO9ZbIbuYavH60BJ2Z1S+ZH1Hm37qjrq0yZLZUetf6RrvDKtkiJcmii6cX3pOt6Ecgdj2vitdN/OJva3JJDhAJOcC49lTwOH2ZZ29tfyuMB/8H/+avchr2e5MwLar2nZ3sUAAAAYczvUuIIqdw7NjlyFowywgYrxRQ=</CipherValue>
</CipherData>
</EncryptedData>
</connectionStrings>
</configuration>
加解密數據庫連接字符串很快就解決了,接下來要解決編寫另外的小程序來修改這個連接字符串。開始考慮到直接做在試題庫的應用程序中。
從“我們的家園”博客上找到了修改數據庫連接字符串(實際上可以是配置文件中的任何一節)的文章“讀取並修改App.config文件(轉載)”(http://www.cnblogs.com/xshy3412/archive/2007/11/24/971374.html),他也是轉載的喲,從哪兒轉載我就不知道了。這裏面提供了一個修改數據庫連接字符串的方法:
///<summary>
///依據連接串名字connectionName返回數據連接字符串
///</summary>
///<param name="connectionName"></param>
///<returns></returns>
private static string GetConnectionStringsConfig(string connectionName)
{
string connectionString =
ConfigurationManager.ConnectionStrings[connectionName].ConnectionString.ToString();
Console.WriteLine(connectionString);
return connectionString;
}
///<summary>
///更新連接字符串
///</summary>
///<param name="newName">連接字符串名稱</param>
///<param name="newConString">連接字符串內容</param>
///<param name="newProviderName">數據提供程序名稱</param>
private static void UpdateConnectionStringsConfig(string newName,
string newConString,
string newProviderName)
{
bool isModified = false; //記錄該連接串是否已經存在
//如果要更改的連接串已經存在
if (ConfigurationManager.ConnectionStrings[newName] != null)
{
isModified = true;
}
//新建一個連接字符串實例
ConnectionStringSettings mySettings =
new ConnectionStringSettings(newName, newConString, newProviderName);
// 打開可執行的配置文件*.exe.config
Configuration config =
ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
// 如果連接串已存在,首先刪除它
if (isModified)
{
config.ConnectionStrings.ConnectionStrings.Remove(newName);
}
// 將新的連接串添加到配置文件中.
config.ConnectionStrings.ConnectionStrings.Add(mySettings);
// 保存對配置文件所作的更改
config.Save(ConfigurationSaveMode.Modified);
// 強制重新載入配置文件的ConnectionStrings配置節
ConfigurationManager.RefreshSection("ConnectionStrings");
}
有了這個,很快就實現了在應用程序中修改配置文件中已經加密的連接字符串。但考慮到將這個功能放在應用程序中,用戶可能隨便使用,於是考慮將其另外作爲一個可執行文件,這樣,用戶就不會隨便到可執行程序文件夾下執行這個程序了。
聯想到在一個解決方案中創建多個項目,並在主項目中添加對DbConfig項目的引用,DbConfig項目仍然作爲Windows應用程序輸出,可以在主程序輸出目錄中包含DbConfig項目的可執行文件。(作爲類庫項目只包含Dll文件)。
但很快發現,DbCofnig.Exe文件只能讀取和修改DbCofnig.Exe.Config文件的內容,你把他改成TestLib.Exe,是能讀取TestLib.Exe.Config文件的內容。但主項目TestLib的可執行文件也是TestLib.Exe呀。不可取。
怎麼能做到多項目都能讀取同一個Cofnig文件呢?考慮到ConfigurationManager.OpenExeConfiguration方法的另一個版本:
ConfigurationManager.OpenExeConfiguration(string exePath),它可以指定具體哪個文件。結合Application.ExecutablePath可以獲得可執行文件對應的Config文件。但仍然不行,DbConfig.Exe仍然只能讀取DbConfig.Exe.Config文件。
那就使用Application.StartupPath+@"/Db.config",只讓它讀取指定的Db.Config文件。
調試了n遍,仍然是“未將對象引用設置到對象的實例”。
鬱悶ing...,再到網上去找!
在“若我爲上帝,誰爲衆生”的博客上,找到了這篇文章“再談額外的配置文件讀取和ConfigrationManager.OpenExeConfiguration(exePath)的誤導性錯誤”(http://www.cnblogs.com/telephoner/archive/2008/07/15/1243260.html).
暈!居然是微軟的Bug。
----------------------------
首先說ConfigrationManager.OpenExeConfiguration(exePath)的問題:
1.此處是一個bug,exePath在msdn的說明中是要讀取的配置文件的路徑,而在生成System.Configuration.Configuration a = System.Configuration.ConfigurationManager.OpenExeConfiguration(exepath)的時候,實際在生成的a對象中,可以看到它的FilePath屬性,讓人大吃一驚,它顯示的路徑是原exePath路徑+.config.
所以a對象中永遠爲空,因爲你的X.config是存在的,但它讀取的卻是X.config.config.
這是否是我們的理解有誤而非Bug呢?
不,在試驗在exePath中填寫.config前面的部分後,提示錯誤,無法讀取該配置文件,即它的ConfigurationManager.OpenExeConfiguration()方法要求exepath必須是一個.config文件!!!
2.這個Bug可能的原因
我猜想,它原來的讀取的方法和類都是針對的配置文件的形式爲:可執行文件文件名+.exe+.config的形式,或者是Machine.config.而這時不需要識別.config的,而當在.net 2.0裏面時候,添加的這個讀取額外配置文件的方法,由於一些失誤,仍然是匹配的原來的老方法,導致它在讀取是自動加上了.config.
---------------------------------------------------------------------------------------------
解決方法
我參考了<Configuration類在網頁實現對web.config的修改>(http://tech.sina.com.cn/s/2008-06-30/1013712947.shtml)的方法
即真假config文件的方法:
1.先在項目的bin/debug目錄下建立一個額外的config文件,即X.config;
2.在同目錄下建立一個X.config.config文件;
3.所有信息都在X.config.config內,即appSettings節點等;
4.然後讀寫都可以了.
-----------------------------------------------------
於是按照他所提供的方法來,在可執行文件的文件夾下同時存放Db.Config和Db.Config.Config,果然可以,並且將Db.Config文件必須要有,哪怕是個空的都中,刪掉則不行。
OK!
2008年12月15日晚22:00