Przejdź do treści

DevStyle - Strona Główna
Konfiguracja aplikacji rozbita na wiele sekcji i plików *.config

Konfiguracja aplikacji rozbita na wiele sekcji i plików *.config

Maciej Aniserowicz

27 sierpnia 2012

Backend

Tagi:

    Pisane przez nas "biblioteki wielokrotnego użytku" mogą (a nawet: powinny być?) konfigurowalne. Konfiguracja musi być oczywiście rozprowadzana wraz z aplikacją korzystającą z takich bibliotek, więc obowiązkiem programisty aplikacji jest dołączenie do *config odpowiednich wpisów.

    Swego czasu miałem krótki romans z tworzeniem własnych, dedykowanych "sekcji konfiguracji", ale długo on nie trwał. Toż to jakaś masakra!

    W 90% (albo i więcej) przypadków wystarczają zwykle wpisy w appSettings. Jednak sekcja ta bardzo szybko może stać się śmietnikiem zawierającym cały syf tego świata.

    Osobiście preferuję rozdzielanie konfiguracji między wiele plików, korzystając z bardzo przydatnego atrybutu configSource, który możemy nałożyć na każdą sekcję w *.config. Dzięki temu, dla przykładu, wszystkie connection stringi mogę wywalić do pliku conn.config:

    <?xml version="1.0" encoding="utf-8" ?>
    <connectionStrings>

        <!– conn str 1 –>

        <!– conn str 2 –>

        <!– ………….  –>

    </connectionStrings>

    a w "głównym" konfigu aplikacji tylko się do niego odwołać:

    <connectionStrings configSource="conn.config" />

    Tak samo chociażby z:

    <system.serviceModel>
         <bindings configSource="serviceModel_bindings.config" />
         <client configSource="serviceModel_client.config" />
    </system.serviceModel>

    Równie dobrze można wyrzucić na zewnątrz każdą inną sekcję, w tym appSettings. Niestety nie można wyrzucić tylko jej części – wszystko albo nic. Takie wpisy nie są mergowane. Jeśli więc pozbędziemy się całości appSettings z głównego pliku, to po prostu przenosimy syf gdzieś indziej.

    Chyba że… podzielimy appSettings na kilka części! A raczej: skorzystamy w naszej bibliotece z nowej sekcji, analogicznej do appSettings.

    Jest to bardzo proste, nawet bez grzebania się we własne sekcje. Wystarczy w <configSections> dodać coś takiego:

    <section name="myAppSettings" type="System.Configuration.AppSettingsSection, System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" restartOnExternalChanges="false" requirePermission="false"/>

    i już możemy korzystać z nowej sekcji tak jak z appSettings:

    <myAppSettings>

        <add key="somekey" value="somevalue"/>

        <!– setting 2  –>

        <!– setting 3  –>

        <!– …………  –>

    </myAppSettings>

    A co za tym idzie: możemy na tym poziomie użyć configSource!

    Czas na praktyczny przykład z życia wzięty…

    Pisałem niedawno bibliotekę do komunikacji z zewnętrznym systemem, nazwijmy go CCM. Do tej biblioteki (na poziomie projektu dll!) dodałem plik konfiguracyjny ccm_settings.config. A w nim wszystko co jest potrzebne bibliotece do działania:

    <?xml version="1.0" encoding="utf-8" ?>
    <ccmSettings>
        <add key="CCM.url" value="https://127.0.0.1:8443/axl/"/>

        <!– setting 2  –>

        <!– setting 3  –>

        <!– …………  –>

    </ccmSettings>

    I tyle. Biblioteka sama w sobie oczywiście nie potrzebuje "głównego" configa.

    Taki plik może służyć użytkownikowi biblioteki na kilka sposobów:

    Po pierwsze: służy jako template, wzorzec. Programista wie jakie wartości trzeba uzupełnić i w jaki mniej więcej sposób.

    Po drugie: programista może zdefiniować sobie w konfigu nową sekcję i umieścić wszystko co mojej bibliotece do szczęścia potrzebne nie syfiąc w appSettings.

    Po trzecie: może to zrobić w osobnym pliku poprzez configSource.

    Ale mało tego, jakże pomocne było mi to podczas tworzenia całego systemu! Równolegle z biblioteką implementowałem także jej klienta. I pisałem do niej oczywiście testy jednostkowe. Zarówno klient, jak i projekt z testami potrzebują konfiguracji. Aby nie mnożyć kopii tej samej konfiguracji, zdefiniowałem tą sekcję w konfiguracji klienta i testów, ustawiłem configSource:

    <ccmSettings configSource="ccmSettings.config" />

    , a właściwy plik dodałem do tych projektów jako link. Potem tylko "Copy to output directory" na "Copy always" lub "Copy if newer"… i tyle. Oczywiście to moje postępowanie bazuje na założeniu, że oryginalny plik zawiera poprawne wartości, działające w moim środowisku.

    Należy pamiętać jednak, że w przypadku aplikacji www modyfikacja takiego pliku nie jest automatycznie brana pod uwagę, tzn nie powoduje restartu aplikacji (w przeciwieństwie do modyfikacji web.config lub zawartości /bin czy /app_code).

    Zobacz również