• C# 动态修改配置文件 (二)


    上篇http://www.cnblogs.com/Yjianyong/archive/2011/10/27/2226429.html

    说了对配置文件的修改,基本上都已经是全部了,后来也补充了SingleTagSectionHandler的访问,现在把对SingleTagSectionHandler的写以及一些能偷懒的方法一起说下,希望大家有好东西都能够分享下,有时用到了,就是好东西,不用到就当作是学习吧

    提供二个访问配置文件的静态方法
            /// <summary>
            
    /// 打开默认的配置文件.exe.config 
            
    /// </summary>
            
    /// <returns></returns>
            public static Configuration GetConfiguration()
            {
                return ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            }

            /// <summary>
            
    /// 获取指定的配置文件。
            
    /// </summary>
            
    /// <param name="configFullPath">配置文件的全名称</param>
            
    /// <returns></returns>
            public static Configuration GetConfiguration(string configFullPath)
            {
                ExeConfigurationFileMap configFile = new ExeConfigurationFileMap();
                configFile.ExeConfigFilename = configFullPath;
                Configuration config = ConfigurationManager.OpenMappedExeConfiguration(configFile, ConfigurationUserLevel.None);
                return config;
            }

    通过上两个静态方法可以获取到Configuration实例

     

    获取SingleTagSectionHandler节点的值的多个方法
            /// <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<stringstring> 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<stringstring> 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<stringstring> result = new Dictionary<stringstring>();
                IDictionary dict = (IDictionary)(new SingleTagSectionHandler().Create(nullnull, xnode));
                foreach (string str in dict.Keys)
                {
                    result[str] = (string)dict[str];
                }

                return result;
            }

    更新SingleTagSection只能通过Xml来实现,在些使用了ConfigXmlDocument类,通过更改DefaultSection的SectionInfomation的RawXml来完成,同时更改SectionInformation.Type为SingleTagSectionHandler的完全限定名。

    更新和删除
            /// <summary>
            
    /// 更新配置节,相同的就修改,没有的就增加。
            
    /// </summary>
            
    /// <param name="config"></param>
            
    /// <param name="sectionName"></param>
            
    /// <param name="items"></param>
            public static void UpdateSingleTagSectionValues(this Configuration config, string sectionName, Dictionary<stringstring> items)
            {
                Dictionary<stringstring> orgItem = GetSingleTagSectionValues(config, sectionName);
                if (orgItem == null)
                    orgItem = new Dictionary<stringstring>();
                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<stringstring> items)
            {
                Dictionary<stringstring> 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<stringstring> 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);
            }

    应该还得提供一个对自定义的配置节访问和读写的方法,以更好的扩充

    自定义配置节
            /// <summary>
            
    /// 获取自定义的配置节。
            
    /// </summary>
            
    /// <typeparam name="T"></typeparam>
            
    /// <param name="config"></param>
            
    /// <param name="sectionName"></param>
            
    /// <returns></returns>
            public static T GetCustomSection<T>(this Configuration config, string sectionName) where T : ConfigurationSection
            {
                return (T)config.GetSection(sectionName);
            }

            /// <summary>
            
    /// 保存自定义配置节。
            
    /// </summary>
            
    /// <typeparam name="T"></typeparam>
            
    /// <param name="config"></param>
            
    /// <param name="section"></param>
            
    /// <param name="sectionName"></param>
            public static void SaveCustomSection<T>(this Configuration config, T section, string sectionName) where T : ConfigurationSection
            {
                config.RemoveSection(sectionName);
                config.Sections.Add(sectionName, section);
                config.Save(ConfigurationSaveMode.Modified);
            }

        至于配置组,本人觉得用处不大,实现起来也很别扭,所在就不实现了,如果真的是很复杂的配置,建议自己定义一个配置节吧。

        下面一些懒人的方法,本人觉得还是很不错的,至少会省掉不少的开发时间。

    通过反射对实体或静态属性进行赋值,在此假设obj如果为null就使用静态属性。

    反射获取属性值
            private static void SetPropertiesValue(object obj, Dictionary<stringstring> items, Type cfgEtyType)
            {
                BindingFlags bf = BindingFlags.Public;
                if (obj == null)
                    bf |= BindingFlags.Static;
                else
                    bf |= BindingFlags.Instance;

                PropertyInfo[] pinfos = cfgEtyType.GetProperties(bf);

                foreach (PropertyInfo p in pinfos)
                {
                    try
                    {
                        if (items.ContainsKey(p.Name))
                        {
                            string val = items[p.Name];
                            if (!string.IsNullOrEmpty(val))
                            {
                                if (p.PropertyType.IsEnum)
                                {
                                    //判断是否为数字
                                    if (isDigital(val))
                                    {
                                        p.SetValue(obj, Enum.Parse(p.PropertyType, val, true), null);
                                    }
                                    else
                                    {
                                        //判断是否存在该名称
                                        if (isExistEnumKey(p.PropertyType, val))
                                            p.SetValue(obj, Enum.Parse(p.PropertyType, val, true), null);
                                    }
                                }
                                else if (p.PropertyType.IsValueType)   //值类型
                                {
                                    MethodInfo minfo = p.PropertyType.GetMethod("Parse"new Type[] { typeof(string) });
                                    if (minfo != null)
                                    {
                                        p.SetValue(obj, minfo.Invoke(nullnew object[] { val }), null);
                                    }
                                }
                                else
                                    p.SetValue(obj, val, null);
                            }
                            else if (!p.PropertyType.IsEnum && !p.PropertyType.IsValueType)
                                p.SetValue(obj, val, null);
                        }
                    }
                    catch (System.Exception ex)
                    {
                        Console.WriteLine(ex.Message + "\n" + ex.StackTrace);
                    }
                }
            }

            /// <summary>
            
    /// 判断枚举值是否为数字
            
    /// </summary>
            
    /// <param name="strValue"></param>
            
    /// <returns></returns>
            private static bool isDigital(string strValue)
            {
                return Regex.IsMatch(strValue, @"^(\d+)$");
            }

            /// <summary>
            
    /// 判断是否存在枚举的名称
            
    /// </summary>
            
    /// <param name="type"></param>
            
    /// <param name="keyName"></param>
            
    /// <returns></returns>
            private static bool isExistEnumKey(Type type, string keyName)
            {
                bool isExist = false;
                foreach (string key in Enum.GetNames(type))
                {
                    if (key.Equals(keyName, StringComparison.OrdinalIgnoreCase))
                    {
                        isExist = true;
                        break;
                    }
                }
                return isExist;
            }

    动态获取值,在此再次强调,属性值必需和配置节的Key等相同,包括大小写。

    使用抽象类的静态属性来取出配置节的值
            /// <summary>
            
    /// 使用反射获取实体配置节的值,实体的静态属性必需和配置的Key相同。
            
    /// </summary>
            
    /// <param name="config">打开的配置实例</param>
            
    /// <typeparam name="T">要取值的类,类的静态属性要和Key值对应</typeparam>
            
    /// <param name="sectionName">T 对就的配置节的名称</param>
            public static void GetKeyValueSectionConfigValue<T>(this Configuration config, string sectionName) where T : class
            {
                try
                {
                    Dictionary<stringstring> dict = GetKeyValueSectionValues(config, sectionName);
                    Type cfgEtyType = typeof(T);
                    SetPropertiesValue(null, dict, cfgEtyType);
                }
                catch (System.Exception ex)
                {
                    Console.WriteLine(ex.Message + "\n" + ex.StackTrace);
                }
            }

    提供几个和Configuration实例无关的辅助方法,但也作为扩展方法来实现,以方便操作,只要由实例和抽象类来获取到HashTable的值,和反过来取得实例的值

    辅助方法
            /// <summary>
            
    /// 由集合根据字段的属性生成实体。属性名为key,属性值为value。
            
    /// </summary>
            
    /// <typeparam name="T"></typeparam>
            
    /// <param name="config"></param>
            
    /// <param name="items"></param>
            
    /// <returns></returns>
            public static T GetConfigEntityByItems<T>(this Configuration config, Dictionary<stringstring> items) where T : class
            {
                Type etyType = typeof(T);
                Func<object> func = etyType.CreateInstanceDelegate();
                object ety = func.Invoke();

                SetPropertiesValue(ety, items, etyType);

                return (T)ety;
            }

            /// <summary>
            
    /// 由实例生成配置的项。
            
    /// </summary>
            
    /// <typeparam name="T"></typeparam>
            
    /// <param name="config">没有实际使用到</param>
            
    /// <param name="instance"></param>
            
    /// <returns></returns>
            public static Dictionary<stringstring> GetItemsByConfigEntity<T>(this Configuration config, T instance) where T : class
            {
                Type cfgEtyType = typeof(T);
                BindingFlags bf = BindingFlags.Public;
                if (instance == null)
                    bf |= BindingFlags.Static;
                else
                    bf |= BindingFlags.Instance;
                PropertyInfo[] pinfos = cfgEtyType.GetProperties(bf);
                Dictionary<stringstring> dict = new Dictionary<stringstring>();

                foreach (PropertyInfo p in pinfos)
                {
                    dict[p.Name] = "" + p.GetValue(instance, null);
                }
                return dict;
            }

            /// <summary>
            
    /// 由类的静态属性生成配置项。
            
    /// </summary>
            
    /// <typeparam name="T"></typeparam>
            
    /// <returns></returns>
            public static Dictionary<stringstring> GetItemsByClass<T>(this Configuration config) where T : class
            {
                return GetItemsByConfigEntity<T>(config, null);
            }
    从appSettings获取值
            /// <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值和属性的名称相同即可。
                ////Type cfgType = typeof(ConfigUtility);

                
    ////MethodInfo getAppConfigMethod = cfgType.GetMethod("GetAppConfig", BindingFlags.Static | BindingFlags.Public);
                Type etyType = typeof(T);

                Dictionary<stringstring> items = GetAppSettings(config);

                SetPropertiesValue(null, items, etyType);
            }

    配置节的保存

    保存配置节
            /// <summary>
            
    /// 保存 Section 配置的值。保存为DictionarySectionHandler配置节。
            
    /// </summary>
            
    /// <param name="config"></param>
            
    /// <typeparam name="T"></typeparam>
            
    /// <param name="sectionName"></param>
            public static void SaveKeyValueSectionConfig<T>(this Configuration config, string sectionName) where T : class
            {
                var orgsection = config.GetSection(sectionName);
                if (orgsection != null)
                    config.Sections.Remove(sectionName);

                AppSettingsSection section = new AppSettingsSection();
                config.Sections.Add(sectionName, section);

                Type etyType = typeof(T);
                foreach (PropertyInfo pinfo in etyType.GetProperties(BindingFlags.Static | BindingFlags.Public))
                {
                    string keyName = pinfo.Name;
                    object objValue = pinfo.GetValue(nullnull);
                    ////section.Settings.Remove(keyName);
                    section.Settings.Add(new KeyValueConfigurationElement(keyName, "" + objValue));
                }
                section.SectionInformation.Type = typeof(DictionarySectionHandler).AssemblyQualifiedName;
                config.Save(ConfigurationSaveMode.Modified);
            }

            /// <summary>
            
    /// 保存为 AppSettings 配置的值。
            
    /// </summary>
            
    /// <typeparam name="T"></typeparam>
            public static void SaveAppSettingsConfig<T>(this Configuration config) where T : class
            {
                try
                {
                    Type etyType = typeof(T);
                    foreach (PropertyInfo pinfo in etyType.GetProperties(BindingFlags.Static | BindingFlags.Public))
                    {
                        string keyName = pinfo.Name;

                        object objValue = pinfo.GetValue(nullnull);

                        UpdateAppSettingsItemNoSave(config, keyName, "" + objValue);
                    }

                    config.Save(ConfigurationSaveMode.Modified);
                }
                catch (System.Exception ex)
                {
                    Console.WriteLine(ex.Message + "\n" + ex.StackTrace);
                }
            }

    配置文件修改系列在此告一段落了,再附加上创建实体用到的Type的扩展,是从网络抄摘下来的,在本息用了代替Activator来创建实例,效率会快点。

    View Code
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Linq.Expressions;

    namespace System
    {
        public static class TypeExtensions
        {
            public static Func<object> CreateInstanceDelegate(this Type type)
            {
                NewExpression newExp = Expression.New(type);
                Expression<Func<object>> lambdaExp =
                    Expression.Lambda<Func<object>>(newExp, null);
                Func<object> func = lambdaExp.Compile();
                return func;
            }

            public static Func<T, object> CreateInstanceDelegate<T>(this Type type)
            {
                Type paramType = typeof(T);
                var construtor = type.GetConstructor(new Type[] { paramType });
                var param = new ParameterExpression[] { Expression.Parameter(paramType, "arg") };

                NewExpression newExp = Expression.New(construtor, param);
                Expression<Func<T, object>> lambdaExp =
                    Expression.Lambda<Func<T, object>>(newExp, param);
                Func<T, object> func = lambdaExp.Compile();
                return func;
            }


            public static Func<T1, T2, object> CreateInstanceDelegate<T1, T2>(this Type type)
            {
                var types = new Type[] { typeof(T1), typeof(T2) };
                var construtor = type.GetConstructor(types);
                int i = 0;
                var param = types.Select(t => Expression.Parameter(t, "arg" + (i++))).ToArray();
                NewExpression newExp = Expression.New(construtor, param);
                Expression<Func<T1, T2, object>> lambdaExp = Expression.Lambda<Func<T1, T2, object>>(newExp, param);
                Func<T1, T2, object> func = lambdaExp.Compile();
                return func;
            }

            //以下方法中的Lambda表达式“Expression<Func<object[], object>> ”已经定义参数是object[], 而构造函数的参数却不能自动转化。当使用以下代码作测试,


            //////以下代码有bug!
            
    ////public static Func<object[], object> CreateInstanceDelegate(this Type type, params  object[] args)
            
    ////{
            
    ////    var construtor = type.GetConstructor(args.Select(c => c.GetType()).ToArray());
            
    ////    var param = buildParameters(args);

            
    ////    NewExpression newExp = Expression.New(construtor, param);
            
    ////    Expression<Func<object[], object>> lambdaExp =
            
    ////        Expression.Lambda<Func<object[], object>>(newExp, param);
            
    ////    Func<object[], object> func = lambdaExp.Compile();
            
    ////    return func;
            
    ////}

            
    ////static ParameterExpression[] buildParameters(object[] args)
            
    ////{
            
    ////    int i = 0;
            
    ////    List<ParameterExpression> list = new List<ParameterExpression>();
            
    ////    foreach (object arg in args)
            
    ////    {
            
    ////        list.Add(Expression.Parameter(arg.GetType(), "arg" + (i++)));
            
    ////    }
            
    ////    return list.ToArray();
            
    ////}

        }
    }

    -----------------The End----------------

    谢谢大家!

     本文出自:http://www.cnblogs.com/Yjianyong/archive/2011/10/28/2227924.html

  • 相关阅读:
    WPF杂难解 图片模糊的暂时解决方案
    wpf学习笔记 NotifyPropertyChanged实现数据变化自动更新UI
    WPF杂难解 粘贴板复制GIF图片时丢失透明背景
    WPF杂难解 RichTextBox粘贴图片地址处理,并保存的问题
    wpf学习笔记 依赖属性
    WPF杂难解 中文字体显示模糊
    雪花型,支架型,和桥型 的区别
    BI工具对比
    关于javac不是内部命令的解决办法
    转载 android listview getview() 反复调用
  • 原文地址:https://www.cnblogs.com/Yjianyong/p/2227924.html
Copyright © 2020-2023  润新知