首页 > 代码库 > 自定义app.config中的section节点以及在运行中的使用

自定义app.config中的section节点以及在运行中的使用

假如现在我们需要在app.config中定义一个如下的节点,我们需要进行怎样的操作?

<configSections>
    <section name="integration.config" type="UtilityComponent.WinService.Utilities.Config.Integration.IntegrationSection, UtilityComponent.WinService"/>
</configSections>

<integration.config>
    <listeners>
      <add queue="my_queue_Publish" service="PublishService"/>
      <add queue="my_queue_sub" service="SubscribeService"/>
    </listeners>
</integration.config>

那么这个节点的各个字段都代表什么意思?section中name指的是你自定义的这个section的名字,type指的是用于接收这个section中相应字段的类,在程序运行的时候CLR会通过反射将各个字段赋值给这个类的对应属性。在这里,listeners是一个集合,所以我们要用一个继承自ConfigurationElementCollection的类来进行接收。

   [NamedSection("integration.config")]
    public class IntegrationSection : ConfigurationSection
    {
	//这个属性是用来接收listeners这个节点集合。这个类继承自ConfigurationElementCollection. 需要在这个属性上边
	//用Attribute的方式表明对应的节点名称,这样在转换的时候,利用反射,才知道去哪个节点找这个值
        [ConfigurationProperty("listeners", IsRequired = false)]
        public EndpointCollection EndpointCollection
        {
            get { return (EndpointCollection)this["listeners"]; }
        }
    }



    public class EndpointCollection : ConfigurationElementCollection, IEnumerable<EndpointElement>
    {
        protected override ConfigurationElement CreateNewElement()
        {
            return new EndpointElement();
        }

        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((EndpointElement)element).Queue;
        }

        public new IEnumerator<EndpointElement> GetEnumerator()
        {
            int count = Count;
            for (var i = 0; i < count; i++)
            {
                yield return BaseGet(i) as EndpointElement;
            }
        }
    }


    public class EndpointElement : ConfigurationElement
    {
	//这里需要表明是哪个字段,运行时才能利用反射把相应字段对应的值放到这个属性中来
        [ConfigurationProperty("queue", IsKey = true)]
        public string Queue
        {
            get { return (string)this["queue"]; }
            set { this["queue"] = value; }
        }

        [ConfigurationProperty("service", IsKey = false, IsRequired = false)]
        public string Service
        {
            get { return (string)this["service"]; }
            set { this["service"] = value; }
        }

        public override bool IsReadOnly()
        {
            return false;
        }
    }
ConfigurationElement是最基本的类,ConfigurationElementCollection起到了协调的作用。通过ConfigurationElementCollection的Attribute才能找到对应的配置文件的节点。之后节点找到了,一切就简单了。这时候我们就对应节点中的单个节点,写ConfigurationElement这个类,把相应的字段对应到相应的属性上边就可以了。但是这里有另一种情况。

<configSections>
    <section name="integration.config" type="UtilityComponent.WinService.Utilities.Config.Integration.IntegrationSection, UtilityComponent.WinService"/>
</configSections>

<integration.config>
    <listeners>
      <add queue="my_queue_Publish" service="PublishService"/>
      <add queue="my_queue_sub" service="SubscribeService"/>
    </listeners>

    <service.info name="WMSScenarioService" description="WMS Use case implemented using NVS windows service."/>
</integration.config>

我们怎么去接收这个service.info?很显然这里我们需要在IntegrationSection增加一个属性,一个直接继承自ConfigurationElement的属性来接收。注意,这里我们也需要给这个属性增加一个Attribute来告诉CRL,在反射的时候,是把哪个字段来赋给这里的属性。那为什么在上一个的例子中,我们没有在EndpointCollection中特别指明节点名字呢?因为你可以看出,listeners下边,每个节点的名字都是add. 跟这个例子不同。我们可以这样理解,根据Collection的Atrribute找到了listners,然后我们就用相应的ConfigurationElement来接收就行了,但是我们写这个类的时候,就要用Attribute把每个属性写清楚。


ConfigurationManager.GetSection("integration.config") as IntegrationSection,这里CLR就会把相应的值给相应的属性。这一句代码是最为关键的代码,是CLR对配置文件进行读取解析,然后利用反射把每个字段值赋给相应属性的过程。