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

3

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).

Nie przegap kolejnych postów!

Dołącz do ponad 9000 programistów w devstyle newsletter!

Tym samym wyrażasz zgodę na otrzymanie informacji marketingowych z devstyle.pl (doh...). Powered by ConvertKit
Share.

About Author

Programista, trener, prelegent, pasjonat, blogger. Autor podcasta programistycznego: DevTalk.pl. Jeden z liderów Białostockiej Grupy .NET i współorganizator konferencji Programistok. Od 2008 Microsoft MVP w kategorii .NET. Więcej informacji znajdziesz na stronie O autorze. Napisz do mnie ze strony Kontakt. Dodatkowo: Twitter, Facebook, YouTube.

3 Comments

  1. Jak się odwołujesz do tych sekcji w kodzie? Identycznie jak do AppSettings?

  2. Tak, narzucam na to najwzyklejszą statyczna klasę i tam np: (int)ConfigurationManager.GetSection("….")["key"]