当前位置: 首页 > news >正文

配置文件强类型详细解析

          配置文件也可以做成强类型,配置文件的强类型其实就是使配置文件也具有int,DateTime也可以是其他自定义的类型,而不是普通的String类型,至于强类型和一般类型的区别与好处,再次不在叙述,此处只讲解详细的制作步骤。由于使用了强类型,任何时候只要发现配置文件不满足条件就会抛异常,保存时不满足条件的数据也是不能通过系统保存的。当然你可以通过记事本修改在保存,但读取时会抛异常。

    主要包括:1单个节点2复合节点,也就是有子节点的节点3配置节4读取配置文件。

      以下以一个配置文件为例详细讲解

      配置文件  

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
	<configSections>
		<section name="Mail" type="WindowsTestConfig.ClientConfiguration,WindowsTestConfig"/>
	</configSections>
	<Mail LengTh="8">
		<Services  ServicesPort="808" >
			<Service Address="127.0.0.1" Port="805"/>
			<Service Address="127.0.0.2" Port="804"/>
			<Service Address="127.0.0.3" Port="803" />
			<!--<Service Type="NMail.MetricsService.MetricsService, NMail.MetricsService" />-->
		</Services>	
	</Mail>
</configuration>
1单个节点

    Service可以认为是单个节点,应为里边没有包含子节点,只有属性。

<Service Address="127.0.0.1" Port="805"/>

     需要注意的是:

            1配置文件的属性名称是区分大小写的,ConfigurationProperty的第一个参数必须要和属性名称相同

            2需要继承自基类ConfigurationElement,并根据属性的多少添加不同的方法

            3对于每一种常见的类型都有对应的验证方法,例如int是IntegerValidator,字符是StringValidator,还有其他的,功能更强大的正则表达式验证类型RegexStringValidator,但个人试了试不知道RegexStringValidator好像不好用。

           4把string转化为其他类型,需要有一个继承自TypeConverter的子类的特性,可以看看 [TypeConverter(typeof(IPAddressTypeConverter))],而继承自TypeConverter也很简单,只需要重写两个方法而已。

  ConfigurationElement官网参考

对于此处代码为: 

/// <summary>
    /// A simple class for parsing an IP endpoint out of a configuration file.
    /// </summary>
    public class IPEndPointElement : ConfigurationElement
    {
        /// <summary>
        /// The endpoint's address.
        /// </summary>
        [ConfigurationProperty("Address", IsRequired = true)]//Address 需要与配置文件的属性名称相对应,是区分大小写的
        [TypeConverter(typeof(IPAddressTypeConverter))]//告诉系统,怎么把一个string类型转化为需要的IPAddress 类型,也就是强类型
    //    [StringValidator(InvalidCharacters = " ~!@#$%^&*()[]{}/;'\"|\\",MinLength = 7, MaxLength = 15)]//字符串验证属性
        //   [RegexStringValidator(@"^(\d{1,3}\.){3}\d{1,3}{1}quot;)]//正则表达式验证属性
        public IPAddress Address
        {
            get
            {
                return (IPAddress)this["Address"];
            }
            set
            {
                this["Address"] = value;
            }
        }

        /// <summary>
        /// The endpoint's port.
        /// </summary>
        [ConfigurationProperty("Port", IsRequired = true, DefaultValue = 80)]///Port 需要与配置文件的属性名称相对应,是区分大小写的
        [IntegerValidator(MinValue = 1, MaxValue = 65536)]//int 类型验证,设置区间
        public int Port
        {
            get
            {
                return (int)this["Port"];
            }
            set
            {
                this["Port"] = value;
            }
        }

        /// <summary>
        /// Converts this instance to an IPEndPoint.
        /// </summary>
        /// <returns>The endpoint.</returns>
        public IPEndPoint ToEndPoint()//返回强类型结果
        {
            return new IPEndPoint((IPAddress)this["Address"], (int)this["Port"]);
        }

        public override string ToString()
        {
            return this["Address"] + ":" + this["Port"];
        }
    }
    /// <summary>
    /// A type converter to convert strings to IP addresses.
    /// </summary>
    public class IPAddressTypeConverter : TypeConverter//把一个string怎样转化为IPAddress,需要继承TypeConverter,并重写一下的两个方法就可以了
    {
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            if (sourceType == typeof(string))
            {
                return true;
            }

            return base.CanConvertFrom(context, sourceType);
        }

        public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
        {
            if (value is string)
            {
                return IPAddress.Parse((string)value);
            }

            return base.ConvertFrom(context, culture, value);
        }
    }
2复合节点

Services 可以认为是一个复合节点,因为他包含了一个子节点集合

	<Services  ServicesPort="808" >
			<Service address="127.0.0.1" Port="805"/>
			<Service Address="127.0.0.2" Port="804"/>
			<Service Address="127.0.0.3" Port="803" />
			<!--<Service Type="NMail.MetricsService.MetricsService, NMail.MetricsService" />-->
		</Services>	

           1配置文件的属性名称是区分大小写的,ConfigurationProperty的第一个参数必须要和属性名称相同

            2需要继承自基类ConfigurationElementCollection,并根据属性的多少添加不同的方法

          3由于是集合多了几个方法需要重写
     ConfigurationElementCollection官网参考
  对应的代码为
 public class IPAddressCollection : ConfigurationElementCollection
    {
        protected override ConfigurationElement CreateNewElement()//创建一个写的子节点调用方法
        {
            return new IPEndPointElement();
        }
        /// <summary>
        /// The endpoint's port.
        /// </summary>
        [ConfigurationProperty("ServicesPort", IsRequired = true, DefaultValue = 80)]//需要与配置文件一致
        [IntegerValidator(MinValue = 1, MaxValue = 65535)]//int 类型的验证
        public int ServicesPort
        {
            get
            {
                return (int)this["ServicesPort"];
            }
            set
            {
                this["ServicesPort"] = value;
            }
        }
        protected override object GetElementKey(ConfigurationElement element)//其他的都是集合相关的操作,只需要很少的改变
        {
            IPEndPointElement address = (IPEndPointElement)element;

            return getKey(address);
        }

        /// <summary>
        /// Gets or sets the IP address element for the given index.
        /// </summary>
        /// <param name="index">The index of the address to get or set.</param>
        /// <returns>The address element.</returns>
        public IPEndPointElement this[int index]//
        {
            get
            {
                return (IPEndPointElement)BaseGet(index);
            }
            set
            {
                if (BaseGet(index) != null)
                {
                    BaseRemove(index);
                }
                BaseAdd(index, value);
            }
        }

        /// <summary>
        /// Gets the number of address in this instance.
        /// </summary>
        public new int Count
        {
            get { return base.Count; }
        }

        public int IndexOf(IPEndPointElement endPoint)
        {
            return BaseIndexOf(endPoint);
        }

        public void RemoveAt(int index)
        {
            BaseRemoveAt(index);
        }

        public void Add(IPEndPointElement item)
        {
            BaseAdd(item);
        }

        public void Clear()
        {
            BaseClear();
        }

        public bool Contains(IPEndPointElement item)
        {
            return BaseIndexOf(item) >= 0;
        }

        public void CopyTo(IPEndPointElement[] array, int arrayIndex)
        {
            base.CopyTo(array, arrayIndex);
        }

        public new bool IsReadOnly
        {
            get { return false; }
        }

        public bool Remove(IPEndPointElement item)
        {
            if (BaseIndexOf(item) >= 0)
            {
                BaseRemove(item);
                return true;
            }
            return false;
        }

        public IPAddress[] ToAddressArray()
        {
            List<IPAddress> addresses = new List<IPAddress>();
            for (int i = 0; i < this.Count; i++)
            {
                addresses.Add(((IPEndPointElement)this[i]).Address);
            }

            return addresses.ToArray();
        }

        /// <summary>
        /// Gets the key by which address are mapped in the base class.
        /// </summary>
        /// <param name="endPoint">The address to get the key from.</param>
        /// <returns>The key.</returns>
        private string getKey(IPEndPointElement address)
        {
            return address.Address.ToString();
        }
    }
3配置节

Mail可以认为是一个配置节,因为它外边在没有自定义的东西了           

<Mail LengTh="8">
</Mail>
            1配置文件的属性名称是区分大小写的,ConfigurationProperty的第一个参数必须要和属性名称相同

            2需要继承自基类ConfigurationSection,并根据属性的多少添加不同的方法

           3根据包含的子元素写一些方法

           4由于自己写的配置节,系统并不知道,所以需要在配置文件中注册。也就是在配置文件中添加如下代码,    name是这一配置节的名称,type用逗号分成两部分,前一部分是配置节的类名称包含命名空间,后一部分是配置节类所在的程序集名称。

<configSections>
		<section name="Mail" type="WindowsTestConfig.ClientConfiguration,WindowsTestConfig"/>
	</configSections>
            ConfigurationSection官网参考

    对应的代码为: 

class ClientConfiguration : ConfigurationSection 
    {

        public static readonly string SectionsName = "Mail";//配置节名称
        public static void AddToConfigFile()
        {
            if (ConfigFile.Current.Sections[SectionsName] == null)//添加配置节
            {
                ConfigFile.Current.Sections.Add(SectionsName, new ClientConfiguration());
            }
        }

        /// <summary>
        /// Returns true if a DNS client configuration section exists in the current
        /// configuration.
        /// </summary>
        public static bool ConfigurationPresent
        {
            get
            {
                return (ConfigFile.Current.Sections[SectionsName] != null);
            }
        }

        /// <summary>
        /// Returns the current DNS client configuration.
        /// </summary>
        public static ClientConfiguration Current//获取配置节
        {
            get
            {
                ClientConfiguration current;
                current = (ClientConfiguration)ConfigFile.Current.GetSection(SectionsName);
                if (current == null)
                {
                    throw new ConfigurationErrorsException("Mail configuration is missing");
                }
                return current;
            }
        }

        /// <summary>
        /// The list of DNS servers to attempt lookups on.
        /// </summary>
        [ConfigurationProperty("Services", IsDefaultCollection = false)]//Services需要与配置文件一致
        [ConfigurationCollection(typeof(IPEndPointElement), AddItemName = "Service",
               ClearItemsName = "ClearServer", RemoveItemName = "RemoveServer")]//对应集合的几个方法
        public IPAddressCollection DnsServers
        {
            get
            {
                return (IPAddressCollection)this["Services"];
            }
        }

        [ConfigurationProperty("LengTh", IsRequired = true)]//一个属性,名称需要与配置文件一致
        public int LengTh
        {
            get
            {
                return (int)this["LengTh"];
            }
            set
            {
                this["LengTh"] = value;
            }
        }
    }
4读取配置文件

自己写的配置节系统并不知道,所以需要进行一定处理,配置节类需要用到这个类

处理代码: 

 class ConfigFile
    {
        /// <summary>
		/// Opens the configuration files and sets up the shared instance of this config.
		/// </summary>
        static ConfigFile()
        { string path= Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName+".config";//获取配置文件路径包含名称
                  current = OpenConfig(path);
            
		}

		private static Configuration current;

		public static Configuration Current {//获取当前节
			get {
				return current;
			}
			set {
				current = value;
			}
		}

		public static Configuration OpenConfig(string configFilename) {
			ExeConfigurationFileMap cfm = new ExeConfigurationFileMap();
			cfm.ExeConfigFilename = configFilename;
			return ConfigurationManager.OpenMappedExeConfiguration(cfm, ConfigurationUserLevel.None);
		}
    }

测试:

  private void ReadBtn_Click(object sender, EventArgs e)//读取配置文件,如果配置文件不满足条件,读取时就会抛异常
        {
             Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
             ClientConfiguration data = config.Sections[ClientConfiguration.SectionsName] as ClientConfiguration;
            if (data == null)
            {

                return;
            }
           
               LengThBox.Text= data.LengTh+"";
               ServicesPort.Text = data.DnsServers.ServicesPort + "";
              if(data.DnsServers.Count>=1)
              {
              
                  Service1IPBox.Text = data.DnsServers[0].Address.ToString();
                  Service1PortBox.Text = data.DnsServers[0].Port  +"";
                  Service2IPBox.Text = data.DnsServers[1].Address.ToString();
                  Service2PortBox.Text = data.DnsServers[1].Port + "";
                  Service3IPBox.Text = data.DnsServers[2].Address.ToString();
                  Service3PortBox.Text = data.DnsServers[2].Port + "";
              }
        }

        private void SaveBtn_Click(object sender, EventArgs e)//修改配置文件,如果配置文件不满足条件,写入时时就会抛异常
        {
            Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            ClientConfiguration data = config.Sections[ClientConfiguration.SectionsName] as ClientConfiguration;
            if (data == null)
            {

                return;
            }
             data.LengTh=int.Parse(LengThBox.Text);
             data.DnsServers.ServicesPort = int.Parse(ServicesPort.Text);
            if (data.DnsServers.Count >= 1)
            {
                data.DnsServers[0].Address=IPAddress.Parse(Service1IPBox.Text);
                data.DnsServers[0].Port = int.Parse(Service1PortBox.Text); 
               
                data.DnsServers[1].Address = IPAddress.Parse(Service2IPBox.Text);
                data.DnsServers[1].Port = int.Parse(Service2PortBox.Text); 
            
                data.DnsServers[2].Address = IPAddress.Parse(Service3IPBox.Text);
                data.DnsServers[2].Port = int.Parse(Service3PortBox.Text); 
            }
            config.Save(ConfigurationSaveMode.Minimal);
        }
    }
源代码下载
作者:xuexiaodong2009 发表于2011-8-4 10:34:47 原文链接
阅读:111 评论:0 查看评论

相关文章:

  • 防御工事:星形要塞
  • Android系统匿名共享内存Ashmem(Anonymous Shared Memory)在进程间共享的原理分析
  • 利用WebUtil删除Cookies
  • 博客开通先自己恭喜
  • 咏码农[改]
  • 如何学习WordPress
  • 一个关于正则表达式的疑问
  • 当调用GetAuthorizationGroups() 的错误-“试图访问卸载的应用程序域“(Exception from HRESULT: 0x80131014)解决方案...
  • Windows XP 性能优化VDI
  • 理解IP前缀列表(转载)
  • Linq to SQL 多条件动态组合查询(实战篇)
  • KMaster知识管理平台功能简介
  • MVA虚拟化学院的奖品
  • 在RHEL5下构建Cacti监测系统
  • ASP.NET编程中的十大技巧
  • [PHP内核探索]PHP中的哈希表
  • python3.6+scrapy+mysql 爬虫实战
  • AWS实战 - 利用IAM对S3做访问控制
  • download使用浅析
  • IOS评论框不贴底(ios12新bug)
  • Python连接Oracle
  • Redux系列x:源码分析
  • Vue官网教程学习过程中值得记录的一些事情
  • 大主子表关联的性能优化方法
  • 关于使用markdown的方法(引自CSDN教程)
  • 理解IaaS, PaaS, SaaS等云模型 (Cloud Models)
  • 免费小说阅读小程序
  • 盘点那些不知名却常用的 Git 操作
  • Nginx实现动静分离
  • RDS-Mysql 物理备份恢复到本地数据库上
  • ​MySQL主从复制一致性检测
  • #我与Java虚拟机的故事#连载18:JAVA成长之路
  • ()、[]、{}、(())、[[]]等各种括号的使用
  • (Redis使用系列) Springboot 实现Redis 同数据源动态切换db 八
  • (一)基于IDEA的JAVA基础12
  • (转)AS3正则:元子符,元序列,标志,数量表达符
  • .[hudsonL@cock.li].mkp勒索病毒数据怎么处理|数据解密恢复
  • .gitattributes 文件
  • .NET Framework Client Profile - a Subset of the .NET Framework Redistribution
  • .net 发送邮件
  • .net 使用$.ajax实现从前台调用后台方法(包含静态方法和非静态方法调用)
  • .NET 中让 Task 支持带超时的异步等待
  • .NET程序员迈向卓越的必由之路
  • .Net语言中的StringBuilder:入门到精通
  • .pop ----remove 删除
  • @Service注解让spring找到你的Service bean
  • [ Linux ] git工具的基本使用(仓库的构建,提交)
  • [100天算法】-实现 strStr()(day 52)
  • [AMQP Connection 127.0.0.1:5672] An unexpected connection driver error occured
  • [CISCN2019 华东南赛区]Web4
  • [CSS3备忘] transform animation 等
  • [dart学习]第四篇:函数
  • [Err] 1055 - Expression #1 of ORDER BY clause is not in GROUP BY clause and contains nonaggregated c
  • [git]git命令如何取消先前的配置
  • [hdu 1247]Hat’s Words [Trie 图]