Как создать раздел конфигурации, содержащий коллекцию коллекций?

Мне нужен раздел конфигурации примерно так:

<myConfig>
    <mySubConfig1>
        <mySubSubConfig1 keyAttribute="value1">
            <mySubSubConfig1Element keyAttribute="value1"/>
            <mySubSubConfig1Element keyAttribute="value2"/>
        </mySubSubConfig1>
        <mySubSubConfig1 keyAttribute="value2">
            <mySubSubConfig1Element keyAttribute="value1"/>
        </mySubSubConfig1>
    </mySubConfig1>
    <mySubConfig2>
        <mySubSubConfig2 keyAttribute="value1">
            <mySubSubConfig2Element keyAttribute="value1"/>
            <mySubSubConfig2Element keyAttribute="value2"/>
        </mySubSubConfig2>
        <mySubSubConfig2 keyAttribute="value2">
            <mySubSubConfig2Element keyAttribute="value1"/>
        </mySubSubConfig2>
    </mySubConfig2>
    <mySubConfig3>
        <mySubSubConfig3 keyAttribute="value1">
            <mySubSubConfig3Element keyAttribute="value1"/>
            <mySubSubConfig3Element keyAttribute="value2"/>
        </mySubSubConfig3>
        <mySubSubConfig3 keyAttribute="value2">
            <mySubSubConfig3Element keyAttribute="value1"/>
        </mySubSubConfig3>
    </mySubConfig3>
</myConfig>

Я еще не нашел волшебства, которое позволило бы это сделать без использования старого интерфейса IConfigurationSectionHandler. кто нибудь знает как это сделать?

Я не против, если myConfig и mySubConfign равны ConfigurationSectionGroup или ConfigurationSection.

Кроме того, если это имеет значение, это будет использоваться из web.config.


person John Saunders    schedule 09.06.2012    source источник


Ответы (1)


В вашем примере файла конфигурации myConfig будет классом, который наследуется от ConfigurationSection с тремя свойствами с именами mySubConfig1, mySubConfig2 и mySubConfig3.

Типом свойства mySubConfig1 (а также 2 и 3) будет класс, наследуемый от ConfigurationElementCollection, реализующий IEnumerable<ConfigElement> и дополненный ConfigurationCollection (где для свойства "AddItemName" установлено значение "mySubSubConfig1").

Ниже приведен полный пример реализации подхода, который я использовал в производственном развертывании. Обязательно включите сборку System.Configuration. (Это немного сбивает с толку, поскольку пространство имен System.Configuration определено в других сборках, но вы должны включить сборку System.Configuration, чтобы использовать приведенный ниже код.)

Вот пользовательские классы конфигурации:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;

namespace ConfigTest {
    class CustomConfigSection : ConfigurationSection {

        [ConfigurationProperty( "ConfigElements", IsRequired = true )]
        public ConfigElementsCollection ConfigElements {
            get {
                return base["ConfigElements"] as ConfigElementsCollection;
            }
        }

    }

    [ConfigurationCollection( typeof( ConfigElement ), AddItemName = "ConfigElement" )]
    class ConfigElementsCollection : ConfigurationElementCollection, IEnumerable<ConfigElement> {

        protected override ConfigurationElement CreateNewElement() {
            return new ConfigElement();
        }

        protected override object GetElementKey( ConfigurationElement element ) {
            var l_configElement = element as ConfigElement;
            if ( l_configElement != null )
                return l_configElement.Key;
            else
                return null;
        }

        public ConfigElement this[int index] {
            get {
                return BaseGet( index ) as ConfigElement;
            }
        }

        #region IEnumerable<ConfigElement> Members

        IEnumerator<ConfigElement> IEnumerable<ConfigElement>.GetEnumerator() {
            return ( from i in Enumerable.Range( 0, this.Count )
                     select this[i] )
                    .GetEnumerator();
        }

        #endregion
    }

    class ConfigElement : ConfigurationElement {

        [ConfigurationProperty( "key", IsKey = true, IsRequired = true )]
        public string Key {
            get {
                return base["key"] as string;
            }
            set {
                base["key"] = value;
            }
        }

        [ConfigurationProperty( "SubElements" )]
        public ConfigSubElementsCollection SubElements {
            get {
                return base["SubElements"] as ConfigSubElementsCollection;
            }
        }

    }

    [ConfigurationCollection( typeof( ConfigSubElement ), AddItemName = "ConfigSubElement" )]
    class ConfigSubElementsCollection : ConfigurationElementCollection, IEnumerable<ConfigSubElement> {

        protected override ConfigurationElement CreateNewElement() {
            return new ConfigSubElement();
        }

        protected override object GetElementKey( ConfigurationElement element ) {
            var l_configElement = element as ConfigSubElement;
            if ( l_configElement != null )
                return l_configElement.Key;
            else
                return null;
        }

        public ConfigSubElement this[int index] {
            get {
                return BaseGet( index ) as ConfigSubElement;
            }
        }

        #region IEnumerable<ConfigSubElement> Members

        IEnumerator<ConfigSubElement> IEnumerable<ConfigSubElement>.GetEnumerator() {
            return ( from i in Enumerable.Range( 0, this.Count )
                     select this[i] )
                    .GetEnumerator();
        }

        #endregion
    }

    class ConfigSubElement : ConfigurationElement {

        [ConfigurationProperty( "key", IsKey = true, IsRequired = true )]
        public string Key {
            get {
                return base["key"] as string;
            }
            set {
                base["key"] = value;
            }
        }

    }


}

Вот файл App.config:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="CustomConfigSection" type="ConfigTest.CustomConfigSection,ConfigTest" />
  </configSections>

  <CustomConfigSection>
    <ConfigElements>
      <ConfigElement key="Test1">
        <SubElements>
          <ConfigSubElement key="-SubTest1.1" />
          <ConfigSubElement key="-SubTest1.2" />
        </SubElements>
      </ConfigElement>
      <ConfigElement key="Test2">
        <SubElements>
          <ConfigSubElement key="-SubTest2.1" />
          <ConfigSubElement key="-SubTest2.2" />
        </SubElements>
      </ConfigElement>
    </ConfigElements>
  </CustomConfigSection>

</configuration>

Наконец, вот код, который обращается к файлу конфигурации и использует его:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;

namespace ConfigTest {
    class Program {
        static void Main( string[] args ) {

            var l_configSettings = (CustomConfigSection) ConfigurationManager.GetSection( "CustomConfigSection" );

            foreach ( var l_element in l_configSettings.ConfigElements.AsEnumerable() ) {
                Console.WriteLine( l_element.Key );

                foreach ( var l_subElement in l_element.SubElements.AsEnumerable() ) {
                    Console.WriteLine( l_subElement.Key );
                }

            }

            Console.WriteLine( "Press any key..." );
            Console.ReadKey( true );

        }
    }
}

Более легкая альтернатива была написана Сунилом Сингхом в его блоге:
http://blogs.quovantis.com/net-creating-a-custom-configuration-section-that-contains-a-коллекция-коллекций/

person JDB still remembers Monica    schedule 06.11.2012