近期工作太忙了,都沒有時間上上博客,生活所困,得工作呀,相信很多人都是這樣。
近期由於項目對配置文件的操作多了,原來參考網絡的同僚思想寫了個讀和寫配置的類,但都是針對appSettings 節點,對配置節沒有更多的實現,但很多項目如果配置的內容多了,以配置節來分類比較清晰(有很多配置直接使用XML,但我還是偏好Frameword帶schema的config文件)。現在寫下自己的實現,以方便大家參考(此處的配置文件是指獨立的config文件,不是App.config文件)。
1、擴展Configuration類的功能。些功能使用Framework的擴展方法,使用起來更象是Configuration的功能一樣。擴展方法不是本文件要介紹的內容。
命名空間:namespace System.Configuration
和Configuration的命名空間相同,雖然有時忘記引入該擴展類所在的程序集,以導致擴展方法不知道在哪裡,但本人覺得使用相同的命名空間,更加似Configuration的功能。
類名:public static class ConfigurationExtensions 擴展方法得使用靜態類。
2、實現:在網上,有位仁兄使用自定義一個Section節來實現NameValue的做法,雖然的可行,但在配置節的設置上得帶有自己的程序集的限定名等,本人不喜歡,Framework都有NameValeElement 和KeyValueElement等的定義,相似的做法,我們又何必多些一番工作!不過還多謝哪位高手的代碼,做了不少參考。(本人發覺Microsoft隨著新版本的更新,以前很多可以直接操作其本框架的功能都被屏蔽了,不知道是否制約做IDE工具的開源框架,以減少對VS的競爭的原因吧)。還有位高手直接通過XMLDocumet來操作,應該也不是好的解決方案。
擴展Configuration的功能
獲取連接字符串
///<summary>依據連接串名字connectionName返回數據連接字符串</summary>
///<param name="connectionName">連接串的</param>
///<param name="config"></param>
///<returns></returns>
public static string GetConnectionStringsConfig(this Configuration config, string connectionName)
{
string connectionString = config.ConnectionStrings.ConnectionStrings[connectionName].ConnectionString;
////Console.WriteLine(connectionString);
return connectionString;
}
更新連接字符串
///<summary>
///更新連接字符串
///</summary>
///<param name="newName">連接字符串名稱</param>
///<param name="newConString">連接字符串內容</param>
///<param name="newProviderName">數據提供程序名稱</param>
///<param name="config">Configuration實例</param>
public static void UpdateConnectionStringsConfig(this Configuration config, string newName, string newConString, string newProviderName)
{
bool isModified = false;
//記錄該連接串是否已經存在
//如果要更改的連接串已經存在
if (config.ConnectionStrings.ConnectionStrings[newName] != null)
{ isModified = true; }
//新建一個連接字符串實例
ConnectionStringSettings mySettings = new ConnectionStringSettings(newName, newConString, newProviderName);
// 如果連接串已存在,首先刪除它
if (isModified)
{
config.ConnectionStrings.ConnectionStrings.Remove(newName);
}
// 將新的連接串添加到配置文件中.
config.ConnectionStrings.ConnectionStrings.Add(mySettings);
// 保存對配置文件所作的更改
config.Save(ConfigurationSaveMode.Modified);
}
獲取appSettings配置節的value項
///<summary>
///返回config文件中appSettings配置節的value項
///</summary>
///<param name="strKey"></param>
///<param name="config">Configuration實例</param>
///<returns></returns>
public static string GetAppSettingsItemValue(this Configuration config, string strKey)
{
foreach (KeyValueConfigurationElement key in config.AppSettings.Settings)
{
if (key.Key == strKey)
{
return config.AppSettings.Settings[strKey].Value;
}
}
return string.Empty;
}
獲取所有的appSettings的節點
/// <summary>
/// 獲取所有的appSettings的節點。
/// </summary>
/// <param name="config"></param>
/// <returns></returns>
public static Dictionary<string,string> GetAppSettings(this Configuration config)
{
Dictionary<string,string> dict = new Dictionary<string,string>();
foreach (KeyValueConfigurationElement key in config.AppSettings.Settings)
{
dict[key.Key] = key.Value;
}
return dict;
}
更新或增加appSettings配置節增加一對鍵、值對。
///<summary>
///更新在config文件中appSettings配置節增加一對鍵、值對。
///</summary>
///<param name="newKey"></param>
///<param name="newValue"></param>
///<param name="config"></param>
public static void UpdateAppSettingsItemValue(this Configuration config, string newKey, string newValue)
{
UpdateAppSettingsItemNoSave(config, newKey, newValue);
////// Save the changes in App.config file.
config.Save(ConfigurationSaveMode.Modified);
////// Force a reload of a changed section.
////ConfigurationManager.RefreshSection("appSettings");
}
刪除appSettings的一個或多個節點
/// <summary>
/// 刪除appSettings的一個節點。
/// </summary>
/// <param name="config"></param>
/// <param name="key"></param>
public static void RemoveAppSettingsItemValue(this Configuration config, string key)
{
config.AppSettings.Settings.Remove(key);
config.Save(ConfigurationSaveMode.Modified);
}
/// <summary>
/// 刪除appSettings的多個節點
/// </summary>
/// <param name="config"></param>
/// <param name="keys"></param>
public static void RemoveAppSettingsItems(this Configuration config, string[] keys)
{
foreach(string key in keys)
config.AppSettings.Settings.Remove(key);
config.Save(ConfigurationSaveMode.Modified);
}
增加或appSettings配置節增加多對鍵、值對
/// <summary>
///更新在config文件中appSettings配置節增加多對鍵、值對。
/// </summary>
/// <param name="config"></param>
/// <param name="items"></param>
public static void UpdateAppSettings(this Configuration config, Dictionary<string, string> items)
{
foreach (string key in items.Keys)
{
UpdateAppSettingsItemNoSave(config, key, items[key]);
}
config.Save(ConfigurationSaveMode.Modified);
}
private static void UpdateAppSettingsItemNoSave(Configuration config, string newKey, string newValue)
{
bool isModified = false;
foreach (KeyValueConfigurationElement key in config.AppSettings.Settings)
{
if (key.Key == newKey)
{ isModified = true; }
}
// You need to remove the old settings object before you can replace it
if (isModified)
{ config.AppSettings.Settings.Remove(newKey); }
// Add an Application Setting.
config.AppSettings.Settings.Add(newKey, newValue);
}
以上是對connectionStrings 和appSetting配置節的一些操作,較多的參考網上資源。
對於DictionarySectionHandler 、NameValueFileSectionHandler 、SingleTagSectionHandler的實現真的不是很多操作,但還是實現了DictionarySectionHandler 、NameValueFileSectionHandler ,至於SingleTagSectionHandler有待進一步實現,或有哪位仁兄實現了,可以回復,謝謝!
通用獲取key-value 鍵值對Section值的集合
/// <summary>
/// 通用獲取key-value 鍵值對Section值的集合,可用於DictionarySectionHandler或NameValueSectionHandler 定義的配置節NameValueSectionHandler的Key值不能重復
/// </summary>
/// <param name="sectionName"></param>
/// <param name="config"></param>
/// <returns>沒有配置節時返回null</returns>
public static Dictionary<string, string> GetKeyValueSectionValues(this Configuration config, string sectionName)
{
////KeyValueConfigurationSection appSettings = (KeyValueConfigurationSection)config.GetSection(sectionName);
var section = config.GetSection(sectionName);
if (section == null)
return null;
Dictionary<string, string> result = new Dictionary<string, string>();
XmlDocument xdoc = new XmlDocument();
xdoc.LoadXml(section.SectionInformation.GetRawXml());
System.Xml.XmlNode xnode = xdoc.ChildNodes[0];
IDictionary dict = (IDictionary)(new DictionarySectionHandler().Create(null, null, xnode));
foreach (string str in dict.Keys)
{
result[str] = (string)dict[str];
}
return result;
}
由於Framework框架沒有提供DictionarySection的節點類,不能直接解釋出節點中的元素,因些只能使用XML,通過IConfigurationSectionHandler.Create接口,即DictionarySectionHandler().Create方法,實現了元素的集合。
獲取子節點為key-value 鍵值對的值
/// <summary>
/// 獲取子節點為key-value 鍵值對的值,可用於DictionarySectionHandler或NameValueSectionHandler 定義的配置節
///
/// </summary>
/// <param name="sectionName">定點名稱</param>
/// <param name="key">key 的值,不存在的Key值將返回空</param>
/// <param name="config">打開的配置文件。</param>
/// <returns></returns>
public static string GetKeyValueSectionItemValue(this Configuration config, string sectionName, string key)
{
var section = config.GetSection(sectionName).SectionInformation;
if (section == null)
return null;
XmlDocument xdoc = new XmlDocument();
xdoc.LoadXml(section.GetRawXml());
System.Xml.XmlNode xnode = xdoc.ChildNodes[0];
IDictionary dict = (IDictionary)(new DictionarySectionHandler().Create(null, null, xnode));
if (dict.Contains(key))
return (string)dict[key];
else
return null;
}
更新配置節,相同的就修改,沒有的就增加。
/// <summary>
/// 更新配置節,相同的就修改,沒有的就增加。
/// </summary>
/// <param name="config"></param>
/// <param name="sectionName"></param>
/// <param name="items"></param>
public static void UpdateKeyValueSectionValues(this Configuration config, string sectionName, Dictionary<string, string> items)
{
Dictionary<string, string> orgItem = GetKeyValueSectionValues(config, sectionName);
if (orgItem == null)
orgItem = new Dictionary<string, string>();
foreach (string key in items.Keys)
{
orgItem[key] = items[key];
}
UpdateKeyValueSection(config, sectionName, orgItem);
}
private static void UpdateKeyValueSection(Configuration config, string sectionName, Dictionary<string, string> items)
{
config.Sections.Remove(sectionName);
AppSettingsSection section = new AppSettingsSection();
config.Sections.Add(sectionName, section);
foreach (string key in items.Keys)
{
section.Settings.Add(new KeyValueConfigurationElement(key, items[key]));
}
section.SectionInformation.Type = typeof(DictionarySectionHandler).AssemblyQualifiedName;
config.Save(ConfigurationSaveMode.Modified);
}
更新配置節在這裡使用欺騙的做法,我們使用一個AppSettingsSection 配置節類,把Dictionary的鍵值對作為KeyValueConfigurationElement元素加入到AppSettingsSection 的Settings集合裡,在序列化到Config文件前,把section.SectionInformation.Type 更改為typeof(DictionarySectionHandler).AssemblyQualifiedName的字符串,保存後,我們就可以得到一個DictionarySectionHandler的配置節了,些方法很好地解決了序列化的問題。
刪除配置點的一些配置。
/// <summary>
/// 刪除配置點的一些配置。
/// </summary>
/// <param name="config"></param>
/// <param name="sectionName"></param>
/// <param name="items"></param>
public static void RemoveKeyValueSectionValues(this Configuration config, string sectionName, Dictionary<string, string> items)
{
Dictionary<string, string> orgItem = GetKeyValueSectionValues(config, sectionName);
if (orgItem != null)
{
foreach (string key in items.Keys)
{
orgItem.Remove(key);
}
UpdateKeyValueSection(config, sectionName, orgItem);
}
}
/// <summary>
/// 刪除配置節。
/// </summary>
/// <param name="config"></param>
/// <param name="sectionName"></param>
public static void RemoveSection(this Configuration config, string sectionName)
{
config.Sections.Remove(sectionName);
config.Save(ConfigurationSaveMode.Modified);
}
以上的方法全部完成了配置節的增刪改,對於配置節組,由於較少使用,暫時不想去完善了,而且一個組其實可以看作是多個單獨配置節的組合,意義不大。
下面提供一個懶人的方法,就是使用抽象類的靜態屬性,來自動獲取配置的方法(靜態屬性的名稱和配置的key值得相同),至於自動保存和自動取配置節的方法,大家就出點力吧,在些就不提供了。
/// <summary>
/// 獲取appSettings的配置值。Key值 和T 的靜態屬性相同才能取出來。
/// </summary>
/// <param name="config">打開的配置實例</param>
/// <typeparam name="T">要取值的類,類的靜態屬性要和Key值對應</typeparam>
public static void GetAppSettingsConfigValue<T>(this Configuration config) where T : class
{
//通過反射自動值,增加屬性只需把配置的key值和屬性的名稱相同即可。
try
{
////Type cfgType = typeof(ConfigUtility);
////MethodInfo getAppConfigMethod = cfgType.GetMethod("GetAppConfig", BindingFlags.Static | BindingFlags.Public);
Type etyType = typeof(T);
foreach (PropertyInfo pinfo in etyType.GetProperties(BindingFlags.Static | BindingFlags.Public))
{
string keyName = pinfo.Name;
string rslt = GetAppSettingsItemValue(config, keyName);
Type dType = pinfo.DeclaringType;
if (pinfo.PropertyType.IsValueType)
{
//類型轉換
if (!String.IsNullOrEmpty(rslt))
{
try
{
MethodInfo minfo = pinfo.PropertyType.GetMethod("Parse", new Type[] { typeof(string) });
if (minfo != null)
{
pinfo.SetValue(null, minfo.Invoke(null, new object[] { rslt }), null);
}
}
catch (System.Exception ex)
{
Console.WriteLine(ex.Message + "\n" + ex.StackTrace);
}
}
}
else
pinfo.SetValue(null, rslt, null);
}
}
catch (System.Exception ex)
{
Console.WriteLine(ex.Message + "\n" + ex.StackTrace);
}
}
獲取Configuration實例:
string m_curPath = AppDomain.CurrentDomain.BaseDirectory;
m_ConfigFullName = Path.Combine(m_curPath, "GlobalSetup.config");
ExeConfigurationFileMap configFile = new ExeConfigurationFileMap();
configFile.ExeConfigFilename = m_ConfigFullName;
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(configFile, ConfigurationUserLevel.None);
整個文檔就說到些,希望大家有新的想法就回復,多謝!
作者 Lance Yang