Tworzenie własnej ConfigurationSection

wlasna konfiguracja 2

Chce z poziomu kodu czytać konfigurację z pliku app.config (projekty desktopowe) lub Web.config (projekty webowe). Na przykład kolekcję zaufanych applikacji, które mogą korzystać z naszego serwisu.

Poniżej app.config dla dzisiejszego przykładu. Sekcja configSections jest obowiązkowa i musi pojawić się jako pierwsza. Informuje ona jakich configuracji spodziewać się w całym pliku (czasem jest on bardzo duży).

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="mySection" type="KMorcinek.Examples.CustomConfigSection.MySection, Examples.CustomConfigSection"/>
  </configSections>
  <mySection>
    <trustedApplications>
      <application name="win7"/>
      <application name="vista"/>
    </trustedApplications>
  </mySection>
</configuration>

Chcę wybrać nazwę pierwszej applikacji. Przykładowo:

        static void Main()
        {
            var section = (MySection)ConfigurationManager.GetSection("mySection");

            string firstApplication = section.TrustedApplications[0].Name;

            Console.WriteLine(firstApplication);
            Console.ReadLine();
        }

Nudny kod do wygenerowania

Do tego trzeba stworzyć 3 poniższe klasy dziedziczące po ConfigurationSection, ConfigurationElementCollection oraz ConfigurationElement.

Klasa MySection:

    public class MySection : ConfigurationSection
    {
        [ConfigurationProperty("trustedApplications")]
        [ConfigurationCollection(typeof(TrustedApplications), AddItemName = "application")]
        public TrustedApplications TrustedApplications
        {
            get
            {
                return this["trustedApplications"] as TrustedApplications;
            }
        }
    }

Klasa TrustedApplications:

    public class TrustedApplications : ConfigurationElementCollection
    {
        public ApplicationSectionElement this[int index]
        {
            get
            {
                return base.BaseGet(index) as ApplicationSectionElement;
            }
        }

        // implementacja abstrakcyjnej ConfigurationElementCollection
        protected override ConfigurationElement CreateNewElement()
        {
            return new ApplicationSectionElement();
        }

        // implementacja abstrakcyjnej ConfigurationElementCollection
        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((ApplicationSectionElement)element).Name;
        }
    }

Klasa ApplicationSectionElement:

    public class ApplicationSectionElement : ConfigurationElement
    {
        [ConfigurationProperty("name", IsRequired = true)]
        public string Name
        {
            get
            {
                return this["name"] as string;
            }
        }
    }

Moje dodatki

Całkiem dobrze jest to wytłumaczone na stronie MSDN How to: Create Custom Configuration Sections Using ConfigurationSection. Brakowało mi jednak dwóch rzeczy, których się trochę naszukałem.

  1. Zawsze lepiej dodać biblioteke w której należy szukać typu, czyli zamiast
    <section name="mySection" type="KMorcinek.Examples.CustomConfigSection.MySection"/>
    

    można sprecyzować:

    <section name="mySection" type="KMorcinek.Examples.CustomConfigSection.MySection, Examples.CustomConfigSection"/>
    
  2. Aby poprawnie tworzyła się kolekcja applikacji, dodaję AddItemName do deklaracji pola TrustedApplications, gdzie przypisuję jak nazywa się dany element w pliku konfiguracji.
            [ConfigurationProperty("trustedApplications")]
            [ConfigurationCollection(typeof(TrustedApplications), AddItemName = "application")]
            public TrustedApplications TrustedApplications
            {
                //
            }
    

Nazwy, które zastosowałem dla klas, nie są spójne. ApplicationSectionElement obędzie się bez przyrostka SectionElement, z kolei do TrustedApplications pasowałby przyrostek ConfigurationElementCollection. Nie wiem, która konwencja jest lepsza (poprawcie mnie w komentarzu), pamiętajcie jednak, żeby trzymać się jednej.

Sekcja mySection powinna być zastąpiona nazwą applikacji którą rozwijamy. Nie umieszczam od razu trustedApplications, ponieważ w mySection mogą być dodane w przyszłości inne rzeczy, na przykład someInterval:

<mySection>
    <trustedApplications>
      <application name="win7"/>
    </trustedApplications>
    <someInterval seconds="2" enabled="true">
  </mySection>

Sekcja trustedApplications jest tylko od przechywania kolekcji applications.

Źródła

Download Examples.CustomConfigSection.zip

Edit:

@burczu w komentarzu wspomniał, że żmudne jest generowanie tego typu kod. Mam takie małe uproszczenie, czyli klasę generyczną ExtendedConfigurationElementCollection. Implementuje ona abstrakcyjne metody CreateNewElement() i GetElementKey(…), które są powtarzalne. Poniżej także nowa definicja klasy AllowedApplications.

    public abstract class ExtendedConfigurationElementCollection<T> : ConfigurationElementCollection where T : ConfigurationElement , new()
    {
        public T this[int index]
        {
            get
            {
                return BaseGet(index) as T;
            }
        }

        // Taki helper
        public T[] ToArray()
        {
            var array = new T[Count];

            for (int i = 0; i < array.Length; i++)
                array[i] = this[i];

            return array;
        }

        // konieczna implementacja abstrakcyjnej metody
        protected override ConfigurationElement CreateNewElement()
        {
            return new T();
        }

        // konieczna implementacja abstrakcyjnej metody
        protected override object GetElementKey(ConfigurationElement element)
        {
            return element;
        }
    }

    public class AllowedApplications : ExtendedConfigurationElementCollection<ApplicationSectionElement>
    {
    }

Trochę nie jestem pewien, czy tak trywialna implementacja GetElementKey(…) nic nie zepsuje, ale pobieżne zerknięcie w źródła powiedziało, że raczej nie.

Reklamy
Ten wpis został opublikowany w kategorii Uncategorized i oznaczony tagami , . Dodaj zakładkę do bezpośredniego odnośnika.

4 odpowiedzi na „Tworzenie własnej ConfigurationSection

  1. Pingback: dotnetomaniak.pl

  2. burczu pisze:

    Moim zdaniem lepsze jest podejście z dodawanie przyrostków – od razu wiadomo do czego klasa służy, łatwiej znaleźć.
    Btw, strasznie nie lubie tworzyć tego czytania konfiguracji – żmudna robota… 😉

    • Co do „żmudności” to dodałem do posta małe rozszerzenie.
      Co do nazewnictwa to ja zamiast przedrostków wrzucam te klasy do jednego folderu (np. ConfigSections). IMHO lepsze są tutaj przedrostki, brzmią bardziej po angielsku 😉

  3. Pingback: ConfigurationSection nie tylko read-only | Show me the code

Możliwość komentowania jest wyłączona.