C# 动态修改配置文件

标签: 文件 | 发表时间:2011-10-27 14:42 | 作者:Lance Yang Xin
出处:http://www.cnblogs.com/

    近期工作太忙了,都没有时间上上博客,生活所困,得工作呀,相信很多人都是这样。

    近期由于项目对配置文件的操作多了,原来参考网络的同僚思想写了个读和写配置的类,但都是针对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的功能 

获取连接字符串

View Code
        ///<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;
        }

 

更新连接字符串

View Code
        ///<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项

View Code
        ///<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的节点

View Code
        /// <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配置节增加一对键、值对。

View Code
        ///<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<stringstring> 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<stringstring> GetKeyValueSectionValues(this Configuration config, string sectionName)
        {
            ////KeyValueConfigurationSection appSettings = (KeyValueConfigurationSection)config.GetSection(sectionName);
            var section = config.GetSection(sectionName);

            if (section == null)
                return null;

            Dictionary<stringstring> result = new Dictionary<stringstring>();

            XmlDocument xdoc = new XmlDocument();
            xdoc.LoadXml(section.SectionInformation.GetRawXml());
            System.Xml.XmlNode xnode = xdoc.ChildNodes[0];

            IDictionary dict = (IDictionary)(new DictionarySectionHandler().Create(nullnull, 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(nullnull, 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<stringstring> items)
        {
            Dictionary<stringstring> orgItem = GetKeyValueSectionValues(config, sectionName);
            if (orgItem == null)
                orgItem = new Dictionary<stringstring>();
            foreach (string key in items.Keys)
            {
                orgItem[key] = items[key];
            }
            UpdateKeyValueSection(config, sectionName, orgItem);
        }

        private static void UpdateKeyValueSection(Configuration config, string sectionName, Dictionary<stringstring> 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<stringstring> items)
        {
            Dictionary<stringstring> 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);

整个文档就说到些,希望大家有新的想法就回复,多谢!

 

后续增加对 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);
        }

 

 

 

作者: Lance Yang 发表于 2011-10-27 14:42 原文链接

评论: 3 查看评论 发表评论


最新新闻:
· 汉王科技发布第三季度财报 营收3.98亿元(2011-10-27 19:53)
· 尘埃落定,索尼爱立信将成为索尼的全资子公司(2011-10-27 19:48)
· 安全专家称Duqu是定制攻击框架(2011-10-27 19:43)
· 传AOL高级副总裁将跳槽至Spotify(2011-10-27 19:41)
· 索尼全资控股索爱反映出市场格局变化(2011-10-27 19:20)

编辑推荐:MVC演化

网站导航:博客园首页  我的园子  新闻  闪存  小组  博问  知识库

相关 [文件] 推荐:

python 下载文件

- Eric - python相关的python 教程和python 下载你可以在老王python里寻觅
之前给大家分享的python 多线程抓取网页,我觉的大家看了以后,应该会对python 抓取网页有个很好的认识,不过这个只能用python 来抓取到网页的源代码,如果你想用做python 下载文件的话,上面的可能就不适合你了,最近我在用python 做文件下载的时候就遇到这个问题了,不过最终得以解决,为了让大家以后碰过这个问题有更好的解决办法,我把代码发出来:.

Ext文件系统

- Haides - 博客园-首页原创精华区
  虽然从Ext2到Ext4,找数据的方式发生了变化,但是,磁盘的布局还是非常相似的. 其实这个东西也不需要变化,因为现在也没什么特别巧妙的方式,而且磁盘的吞吐量、效率的瓶颈也不在这里. 当然,这里排除那些根据自身文件特点设计的数据库,毕竟还是为了支持通用文件.   Boot在第一个块,放的应该是引导程序,超级块就放在了第二个块上,如果不是可以在mount的时候通过参数sb来设置.

Linux 文件结构

- Shiina Luce - OSMSG
想了解 Linux 文件系统树形结构,却又不愿翻阅 FHS 的朋友,可以参考 skill2die4 制作的这张简图. 此图算是 FHS 的图形化版本,简要的说明了 Linux 系统中各个目录的用途及层级关系,适合初学者使用参考. 不过其中较新的如 /run 目录并未在其中出现. 做为参考,这是 Fedora 16 Beta i686 上的文件结构:.

多文件上传

- - BlogJava-首页技术区
多文件上传 jquery的插件. 使用的方法  导入 jquery.js 及 jquery.MultiFile.js ,. 方式一: 后台是文件数组  .  private File[] upload; // 与jsp表单中的名称对应. 在 form 中加入 即可.

Zookeeper配置文件

- - 学着站在巨人的肩膀上
复制conf/zoo_sample.cfg文件为conf/zoo.cfg,修改其中的数据目录. tickTime:这个时间作为Zookeeper服务器之间或者服务器与客户端之间维护心跳的时间,时间单位毫秒. initLimit:选举leader的初始延时. 由于服务器启动加载数据需要一定的时间(尤其是配置数据非常多),因此在选举 Leader后立即同步数据前需要一定的时间来完成初始化.

读取 calss文件

- - zzm
System.out.println("解析失败. int length = 0; // 长度,字节,B. double kblength = 0.0D; // 长度,千字节,KB. System.out.println("文件大小(字节):" + length + "\n文件大小(KB):" + kblength);.

Flume监听文件夹中的文件变化_并把文件下沉到hdfs

- - 行业应用 - ITeye博客
摘要: 1、采集目录到HDFS 采集需求:某服务器的某特定目录下,会不断产生新的文件,每当有新文件出现,就需要把文件采集到HDFS中去 根据需求,首先定义以下3大要素 采集源,即source——监控文件目录 : spooldir 下沉目标,即sink——HDFS文件系统 : hdfs sink source和sink之间的传递通道——channel,可用file chann.

Marlin: Elementary 文件管理器

- 加州旅客 - LinuxTOY
如果您喜好 OS X Finder 风格的文件管理器,Marlin 必然适合您. Marlin 文件管理器作为 Elementary OS 项目的一部分由 ammonkey 开发. Marlin 拥有如同 Finder 的列表视图:. 以及小小的选择 + 号和单击启动模式:. 现在 Marlin 测试版本的 PPA 仓库已经上线,在 Ubuntu 11.04 中安装,请进行:.

Linux 2.6 中的文件锁

- Mountain - 小程序员的草稿箱
在多任务操作系统环境中,如果一个进程尝试对正在被其他进程读取的文件进行写操作,可能会导致正在进行读操作的进程读取到一些被破坏或者不完整的数据;如果两个进程并发对同一个文件进行写操作,可能会导致该文件遭到破坏. 因此,为了避免发生这种问题,必须要采用某种机制来解决多个进程并发访问同一个文件时所面临的同步问题,由此而产生了文件加锁方面的技术.