• 电子商务配置管理


       在大型项目开发中,我们需要配置各种各样的信息。比如:在线支付方式有支付宝,网银,财付通,快钱。我们需要配置支付宝账号信息,需要配置财付通账号信息,需要配置网银账号信息还有快钱账号信息。发邮件呢?我们需要配置邮件服务器信息。发短信呢?我们需要配置短息服务器信息。对于各种各样形形色色的配置信息,我们该如何配置呢?又该如何才能方便管理呢?我们当然希望有一个通用的配置管理模块来管理我们的配置信息,方便我们定位配置信息,方便修改,而且修改配置信息不会引起站点的重启等等。

          好了,我先介绍下.Net自带的配置管理,然后在使用反射技术定义一个通用配置模块。

      1)使用System.Configuration.AppSettingsSection类 

            .Net已经提供了AppSettingsSection类方便我们配置信息。我们可以把配置信息放在Web.confg或App.config的appSettings节点下。如下:

        <configuration>
            <appSettings>
                <!--支付宝合作身份者Id-->
                <add key="AlipayId" value="1234567890"/>
                <add key="AlipayKey" value="test1234567890"/>
                <add key="AlipayEmail" value="yangyanping0615@163.com"/>

                <!--财付通商户号-->
                <add key="TenpayId" value="1234567890"></add>
                <!--财付通密钥-->
                <add key="TenpayKey" value="test1234567890"/>

                <!--网银商户号-->
                <add key="ChinaBankId" value="1001"></add>
                <!--网银密钥-->
                <add key="ChinaBankKey" value="test"/>
            </appSettings>
        </configuration>

      这种配置方式是.Net最基本的配置方式,也是我们最常用的配置方式,但这样的配置方式显然不能让我们满意。因为大量的配置信息放在一起,即无法对信息进行分组,也不方便管理,时间一长,我们自己可能已经不记得配置信息的意思,而且修改任何的配置内容都会导致Asp.Net站点重新启动。

          2)使用System.Configuration.NameValueSectionHandler类 

             .Net在System下提供NameValueSectionHandler类可以对配置信息进行方便的分组。NameValueSectionHandler类的定义是这样的:

     public class NameValueSectionHandler : IConfigurationSectionHandler
        {
            // Fields
            private const string defaultKeyAttribute = "key";
            private const string defaultValueAttribute = "value";
    
            // Methods
            [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
            public NameValueSectionHandler();
            public object Create(object parent, object context, XmlNode section);
            internal static object CreateStatic(object parent, XmlNode section);
            internal static object CreateStatic(object parent, XmlNode section, string keyAttriuteName, string valueAttributeName);
    
            // Properties
            protected virtual string KeyAttributeName { get; }
            protected virtual string ValueAttributeName { get; }
        }
    View Code

        NameValueSectionHandler类实现了接口IConfigurationSectionHandler的Create方法,返回一个ReadOnlyNameValueCollection

    internal static object CreateStatic(object parent, XmlNode section, string keyAttriuteName, string valueAttributeName)
        {
            ReadOnlyNameValueCollection values;
            if (parent == null)
            {
                values = new ReadOnlyNameValueCollection(StringComparer.OrdinalIgnoreCase);
            }
            else
            {
                ReadOnlyNameValueCollection values2 = (ReadOnlyNameValueCollection) parent;
                values = new ReadOnlyNameValueCollection(values2);
            }
            HandlerBase.CheckForUnrecognizedAttributes(section);
            foreach (XmlNode node in section.ChildNodes)
            {
                if (!HandlerBase.IsIgnorableAlsoCheckForNonElement(node))
                {
                    if (node.Name == "add")
                    {
                        string str = HandlerBase.RemoveRequiredAttribute(node, keyAttriuteName);
                        string str2 = HandlerBase.RemoveRequiredAttribute(node, valueAttributeName, true);
                        HandlerBase.CheckForUnrecognizedAttributes(node);
                        values[str] = str2;
                    }
                  else
                  {
                       if (node.Name == "remove")
                        {
                            string name = HandlerBase.RemoveRequiredAttribute(node, keyAttriuteName);
                            HandlerBase.CheckForUnrecognizedAttributes(node);
                            values.Remove(name);
                            continue;
                        }
                      if (node.Name.Equals("clear"))
                        {
                            HandlerBase.CheckForUnrecognizedAttributes(node);
                            values.Clear();
                            continue;
                        }
                       HandlerBase.ThrowUnrecognizedElement(node);
                  }
              }
          }
          values.SetReadOnly();
          return values;
      }
    View Code

     从代码中,可以看出需要一个Add节点,该节点包含一个Key和Value的属性。我们可以这样配置各种信息。 

     <configuration>
            <configSections>
                <section name="Alipay" type="System.Configuration.NameValueSectionHandler"/>
                <section name="TenPay" type="System.Configuration.NameValueSectionHandler"/>
                <section name="WebBank" type="System.Configuration.NameValueSectionHandler"/>
          </configSections>
            <Alipay>
                <!--合作身份者ID-->
                <add key="Id"  value="1234567890" />
                <!--安全检验码-->
                <add key="key"  value="test1234567890" />
                <add key="email"  value="alipay-test03@alipay.com" />
            </Alipay>
          <TenPay>
                <!--合作身份者ID-->
                <add key="Id"  value="1234567890" />
                <!--安全检验码-->
                <add key="key"  value="test1234567890" />
          </TenPay>
          <WebBank>
                <!--合作身份者ID-->
                <add key="Id"  value="1001" />
                <!--安全检验码-->
                <add key="key"  value="test1234567890" />
              </WebBank>
      </configuration>  
    View Code

      可以这样读取配置信息:

       //支付宝配置信息
          var alipays = (NameValueCollection)ConfigurationManager.GetSection("Alipay");
          //支付宝Id
          string alipayId = alipays["Id"];
          //支付宝Key
          string alipaykey = alipays["key"];

      这种配置方式可以有效的对各种不同的配置信息进行分组,方便查看和修改。但不符合面向对象的开发,也无法对配置的信息进行类型检查,修改配置信息一样会导致Asp.Net站点重新启动。

      3)自定义配置节点

         我们可以仿照AppSettingsSection类的实现方式,自定义节点配置类。可以继承ConfigurationSection类实现自定义节点配置类。

       

    public class AlipaySetion : ConfigurationSection
        {
            [ConfigurationProperty("Id", IsKey = true)]
            public string Id
            {
                get { return (string)base["Id"]; }
                set { base["Id"] = value; }
            }
    
            [ConfigurationProperty("Key")]
            public string Key
            {
                get { return (string)base["Key"]; }
                set { base["Key"] = value; }
            }
    
            [ConfigurationProperty("Email")]
            public string Email
            {
                get { return (string)base["Email"]; }
                set { base["Email"] = value; }
            }
        }
    View Code

      节点配置如下:

      <configuration>
          <configSections>
              <section name="Alipay" type="ConsoleApplication2.AlipaySetion,ConsoleApplication2"/>
          </configSections>
          <Alipay Id="1234567890" Key="test1234567890" Email="alipay-test03@alipay.com"/>
      </configuration>

      读取方式:

          var alipays = (AlipaySetion)ConfigurationManager.GetSection("Alipay");
                  string id = alipays.Id;
                  string key = alipays.Key;

      自定义配置节点方便查看和管理,也符合面向对象开发和进行类型检查。但我们需要写很多ConfigurationSection类的实现,显然无法满足我们的需求。

         4)通用的配置模块

      .Net中使用反射技术可以动态的创建一个对象,可以调用对象的方法,可以给对象属性赋值。我们是不是可以根据这个特点动态的创建配置类,然后给配置类的属性赋值呢?那需要什么呢?需要2个基础文件,一个是对象的映射关系文件,另一个是对象属性映射文件,如图:

      首先来看看对象的映射关系文件(文件名:System.config),内容如下:

     

    <configuration>
      <configMappings>
        <mapping  AssemblyName="ConsoleApplication2" ClassName="ConsoleApplication2.AlipayConfiguration"
                 Name="AlipayConfiguration"
                 section="AlipayConfiguration"
                 fileName="Mapping.AlipayConfiguration.config">
            <field xmlName="Id" fieldName="Id" />
            <field xmlName="Key" fieldName="Key" />
            <field xmlName="Email" fieldName="Email" />
        </mapping>
        <mapping  AssemblyName="ConsoleApplication2" ClassName="ConsoleApplication2.TenpayConfiguration"
          Name="TenpayConfiguration"
                section="TenpayConfiguration"
                fileName="Mapping.TenpayConfiguration.config">
          <field xmlName="Id" fieldName="Id" />
          <field xmlName="Key" fieldName="Key" />
        </mapping>
      </configMappings>
    </configuration>
    View Code

       对象属性映射文件:

      支付宝配置类文件(Mapping.AlipayConfiguration.config)

      <?xml version="1.0" encoding="utf-8" ?>
        <AlipayConfiguration>
            <node name="Id" value="1234567890"/>
            <node name="Key" value="test1234567890"/>
            <node name="Email" value="alipay-test03@alipay.com" />
        </AlipayConfiguration>

      Tenpay配置类文件(Mapping.TenpayConfiguration.config)

      <?xml version="1.0" encoding="utf-8" ?>
        <TenpayConfiguration>
            <node name="Id" value="1234567890"/>
            <node name="Key" value="test1234567890"/>
        </TenpayConfiguration>

         xml文件我就不做过多说明了,很简单。看到节点名称基本就能猜出其意思。下面来设计映射类和配置管理类,配置管理类顾名思义就能知道是管理所有配置类的。那怎样才能管理所有的配置类呢?我们知道object是所有对象的基类。当然我们的配置类也是继承object的。我们可以设计一个键值对的集合来存放所有的配置信息。比如:private Dictionary<string, object> Mappings。其中的keyi就是配置的类名,value就是配置对象。我们先看看对象的映射类的定义:

       

    public class ConfigMapping
        {
            private Dictionary<string, string> fieldMappings;
    
            /// <summary>
            /// 配置名(唯一)
            /// </summary>
            public string Name
            {
                get;
                set;
            }
    
            /// <summary>
            /// 配置对象程序集名
            /// </summary>
            public string AssemblyName
            {
                get;
                set;
            }
    
            /// <summary>
            /// 配置对象类名
            /// </summary>
            public string ClassName
            {
                get;
                set;
            }
    
            /// <summary>
            /// 配置对象文件
            /// </summary>
            public string ConfigFile
            {
                get;
                set;
            }
    
            /// <summary>
            /// 类型
            /// </summary>
            private Type type;
    
            /// <summary>
            /// 配置对象类型
            /// </summary>
            public Type Type
            {
                get
                {
                    return Type.GetType(ClassName + "," + AssemblyName);
                }
                set
                {
                    type = value;
                    Instance = Activator.CreateInstance(Type.GetType(ClassName + "," + AssemblyName));
                }
            }
    
            /// <summary>
            /// 配置对象实例
            /// </summary>
            public object Instance
            {
                get;
                private set;
            }
    
            //域集合
            public Dictionary<string, string> FieldMappings
            {
                get
                {
                    return fieldMappings ?? (new Dictionary<string, string>());
                }
                set
                {
                    fieldMappings = value;
                }
            }
        }
    View Code

      配置管理类ConfigManager代码:

        

     public class ConfigManager
        {
            private static readonly object sync = new object();
            private static ConfigManager manager;
            private Dictionary<string, object> Mappings;
            private const string configFile = "Configuration/System.config";
    
            private ConfigManager()
            {
                Mappings = new Dictionary<string, object>();
            }
    
            public static ConfigManager Instance
            {
                get
                {
                    lock (sync)
                    {
                        if (manager == null)
                        {
                            lock (sync)
                            {
                                manager = new ConfigManager();
                                manager.Init();
                            }
                        }
                    }
    
                    return manager;
                }
            }
    
            /// <summary>
            /// 初始化配置管理
            /// </summary>
            privatevoid Init()
            {
                string path = AppDomain.CurrentDomain.BaseDirectory + configFile;
    
                var document = new XmlDocument();
                document.Load(path);
    
                var nodes = document.SelectNodes("configuration/configMappings/mapping");
    
                foreach (XmlNode node in nodes)
                {
                    var mapping = new ConfigMapping
                                      {
                                          Name = node.Attributes["Name"].InnerText,
                                          AssemblyName = node.Attributes["AssemblyName"].InnerText,
                                          ClassName = node.Attributes["ClassName"].InnerText,
                                          ConfigFile = node.Attributes["fileName"].InnerText,
                                          Type =
                                              Type.GetType(node.Attributes["ClassName"].InnerText + "," +
                                                           node.Attributes["AssemblyName"].InnerText)
                                      };
    
                    foreach (XmlNode childNode in node.SelectNodes("field"))
                    {
                        mapping.FieldMappings.Add(childNode.Attributes["xmlName"].InnerText,
                                                  childNode.Attributes["fieldName"].InnerText);
                    }
    
                    SetProperty(mapping);
    
                    Mappings.Add(mapping.Name, mapping.Instance);
                }
            }
    
            /// <summary>
            /// 设置对象属性值
            /// </summary>
            /// <param name="mapping"></param>
            private void SetProperty(ConfigMapping mapping)
            {
                var xml = new XmlDocument();
                xml.Load(AppDomain.CurrentDomain.BaseDirectory + "Configuration/" + mapping.ConfigFile);
                var ns = xml.SelectSingleNode(mapping.Name);
                var infos = mapping.Instance.GetType().GetProperties();
    
                foreach (var info in infos)
                {
                    foreach (XmlNode n in ns.ChildNodes)
                    {
                        if (n.Attributes["name"].Value == info.Name)
                        {
                            object value = Convert.ChangeType(n.Attributes["value"].Value, info.PropertyType);
                            info.SetValue(mapping.Instance, value, null);
                        }
                    }
                }
            }
    
            /// <summary>
            /// 获取配置类实例
            /// </summary>
            /// <param name="name"></param>
            /// <returns></returns>
            public object GetMappingByName(string name)
            {
                return Mappings[name];
            }
        }
    View Code

      读取配置信息很简单,代码如下:

       var alipay = (AlipayConfiguration) ConfigManager.Instance.GetMappingByName("AlipayConfiguration");
                long alipayId = alipay.Id;
                string alipayKey = alipay.Key;

                var tenpay = (TenpayConfiguration)ConfigManager.Instance.GetMappingByName("TenpayConfiguration");
                long tenpayId = tenpay.Id;
                string tenpayKey = tenpay.Key;

       总结:这篇文章主要是介绍了AppSettingsSection类,NameValueSectionHandler类,自定义节点类,和设计一个配置管理类,来配置我们的各种信息。各有优缺点。大家在实际的项目开发中,根据网站配置信息多少,选择适合自己的配置方式。

      好了,感谢阅读,希望这篇文章能给你带来帮助!

  • 相关阅读:
    Go入门笔记-22 访问sqlite3数据库
    Go入门笔记-21 访问consul
    Docker中sh提示符无法回退
    Go入门笔记-20 访问redis
    Docker进阶学习-1
    Musl-libc库编译
    修复 Could not find class [org.springframework.cloud.client.loadbalancer.LoadBalancerProperties]
    Oracle DBLINK 简单使用
    js几种escape()解码与unescape()编码
    解决浏览器图片缓存问题(图片不能及时变过来)
  • 原文地址:https://www.cnblogs.com/xiyangyang/p/3099114.html
Copyright © 2020-2023  润新知