C# 动态修改配置文件
近期工作太忙了,都没有时间上上博客,生活所困,得工作呀,相信很多人都是这样。
近期由于项目对配置文件的操作多了,原来参考网络的同僚思想写了个读和写配置的类,但都是针对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的功能
获取连接字符串
///<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>
///<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项
///返回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的节点
/// 获取所有的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配置节增加一对键、值对。
///更新在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>
/// <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);
}
///更新在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值的集合,可用于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 键值对的值,可用于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>
/// <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>
/// <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>
/// <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);
整个文档就说到些,希望大家有新的想法就回复,多谢!
后续增加对 SingleTagSection 的访问
/// <summary>
/// 获取SingleTagSectionHandler某节点的值。
/// </summary>
/// <param name="config"></param>
/// <param name="sectionName"></param>
/// <param name="property"></param>
/// <returns></returns>
public static string GetSingleTagSectionItemValue(this Configuration config, string sectionName, string property)
{
Dictionary<string, string> dict = GetSingleTagSectionValues(config, sectionName);
if (dict != null && dict.Count > 0)
{
if (dict.ContainsKey(property))
return (string)dict[property];
}
return null;
}
/// <summary>
/// 获取SingleTagSectionHandler节点的值。
/// </summary>
/// <param name="config"></param>
/// <param name="sectionName"></param>
/// <returns></returns>
public static Dictionary<string, string> GetSingleTagSectionValues(this Configuration config, string sectionName)
{
var section = config.GetSection(sectionName);
if (section == null || section.SectionInformation == null)
return null;
ConfigXmlDocument xdoc = new ConfigXmlDocument();
xdoc.LoadXml(section.SectionInformation.GetRawXml());
System.Xml.XmlNode xnode = xdoc.ChildNodes[0];
Dictionary<string, string> result = new Dictionary<string, string>();
IDictionary dict = (IDictionary)(new SingleTagSectionHandler().Create(null, null, xnode));
foreach (string str in dict.Keys)
{
result[str] = (string)dict[str];
}
return result;
}
/// <summary>
/// 更新配置节,相同的就修改,没有的就增加。
/// </summary>
/// <param name="config"></param>
/// <param name="sectionName"></param>
/// <param name="items"></param>
public static void UpdateSingleTagSectionValues(this Configuration config, string sectionName, Dictionary<string, string> items)
{
Dictionary<string, string> orgItem = GetSingleTagSectionValues(config, sectionName);
if (orgItem == null)
orgItem = new Dictionary<string, string>();
foreach (string key in items.Keys)
{
orgItem[key] = items[key];
}
UpdateSingleTagSection(config, sectionName, orgItem);
}
/// <summary>
/// 删除配置点的一些配置。
/// </summary>
/// <param name="config"></param>
/// <param name="sectionName"></param>
/// <param name="items"></param>
public static void RemoveSingleTagSectionValues(this Configuration config, string sectionName, Dictionary<string, string> items)
{
Dictionary<string, string> orgItem = GetSingleTagSectionValues(config, sectionName);
if (orgItem != null)
{
foreach (string key in items.Keys)
{
orgItem.Remove(key);
}
UpdateSingleTagSection(config, sectionName, orgItem);
}
}
private static void UpdateSingleTagSection(Configuration config, string sectionName, Dictionary<string, string> items)
{
config.Sections.Remove(sectionName);
DefaultSection section = new DefaultSection();
config.Sections.Add(sectionName, section);
ConfigXmlDocument xdoc = new ConfigXmlDocument();
XmlNode secNode = xdoc.CreateNode(XmlNodeType.Element, sectionName, xdoc.NamespaceURI);
xdoc.AppendChild(secNode);
foreach (string key in items.Keys)
{
XmlAttribute attr = xdoc.CreateAttribute(key);
attr.Value = items[key];
secNode.Attributes.Append(attr);
}
section.SectionInformation.SetRawXml(xdoc.OuterXml);
section.SectionInformation.Type = typeof(SingleTagSectionHandler).AssemblyQualifiedName;
config.Save(ConfigurationSaveMode.Modified);
}
C# 动态修改配置文件 http://www.cnblogs.com/Yjianyong/archive/2011/10/27/2226429.html
C# 动态修改配置文件下篇:http://www.cnblogs.com/Yjianyong/archive/2011/10/28/2227924.html