Transformace konfiguračních souborů v .NET

Každý, kdo se aspoň trochu zabývá programováním, jistě někdy potřeboval uložit nějaké to nastavení mimo zdrojový kód. K tomu slouží právě konfigurační soubory jejichž formátů je nepřeberné množství. V .NET je to poměrně složitě vymyšleno (kdo nevěří, nechť si přečte Cracking the Mysteries of NET Configuration). Na druhou stranu použití konfiguračních souborů je v .NET velmi jednoduché a přímočaré. Stačí si přidat App.config nebo Web.config a jednoduše k němu přistupovat přes ConfigurationManager. Většina programátorů nad tím moc nepřemýšlí a dál to nějak neřeší. Problémy s konfiguračními soubory mohou nastat až o kus dál při sestavení a nasazení aplikace.

Řekněme, že vyvíjíte například servisně orientovanou aplikaci. Teď už máte konfigy dva. Jeden pro server a většinou druhý pro klienta. Navíc jsou ty servisy u každého zákazníka trochu jiné (host, porty apod.). Začne vám růst počet zákazníků. Přidejte si k tomu různé prostředí, kterými aplikace projde než se dostane na produkci (produkce, test, integrační, vývojová) běžně jsou to minimálně 3 instance. Navíc můžete mít pro jednoho zákazníka více klientů. Zakomponujte si k tomu různé verze aplikace atd. atd. Prostě se po čase můžete dostat do stavu, kdy máte stovky konfigů které je potřeba nějak spravovat. Když na to nemáte vymyšlený nějaký systém, a musíte ty konfigy porovnávat a upravovat ručně, tak je to na mašli.

Naštěstí existují nástroje, které nám pomůžou se s tím vypořádat. Jedním z nich je například XML Document Transform takzvaně XDT. Tato funkcionalita byla představena ve VS2010 pro transformaci souborů web.config při akcích publish, package nicméně umožňuje transformovat jakýkoliv XML soubor ne, jen web.config.

Skládání konfiguračních souborů

Než přejdu k samotným XDT transformacím a nástrojům, ještě bych se ve zkratce zmínil jednu z možností, jak konfigy strukturovat. Některé elementy totiž podporují atribut file případně configSource, ve kterých lze uvést cestu na soubor, a teprve v něm můžete mít obsah daného tagu. Toho lze využít například pro nastavení některých citlivých dat. Například connection string nemusíte mít přímo v konfigu který máte v source controlu a má k němu přístup kde kdo, ale stačí vám tam dát pouze odkaz na soubor, ve kterém se takový connection string nachází. Takový soubor je pak na nějakém místě u zákazníka kde k němu má přístup pouze omezená skupina lidí.

Rozdíl v atributu configSource a file spočívá v tom, že pokud použijete configSource, tak už nelze do tagu, ve kterém jste ho použili dát žádné další hodnoty. Oproti tomu hodnoty ze souboru v atributu file se přidají k hodnotám v tagu, ve kterém to použijete. Následující ukázka pak obsahuje obsah jednotlivých souborů ConnectionStrings.config a AppSettings.config.

Nevýhoda tohoto přístupu je v tom, že ne všechny tagy to podporují. Dají se ale implementovat i vlastní sekce, které tuto podporu mít budou.

XDT – Základní Transformace

Základní implementace XDT se nachází v Microsoft.Web.Xdt kterou lze z odkazu stáhnout jako NuGet balíček. Dokumetnace je pak tady – Web.config Transformation Syntax for Web Project Deployment Using Visual Studio není to teda nic moc, ale na základní věci to stačí.

Abychom mohli transformace použít potřebujeme nějaký konfigurační soubor. V projektu si tedy přidáme normální xml, které nazveme např MySettings.config. Záměrně zde nepoužívám App.config nebo Web.config. Startovací tag je taky jiný. Místo  standardního configuration začneme tagem Dictionary.

Následně si vytvoříme soubor s transformací např. MySettings.transform. Po aplikaci transformace na původní konfigurační soubor dostaneme výsledný konfig v požadovaném formátu.

Jak to tedy funguje? Zkusím polopatě popsat co která transformace dělá. Tak například transformace na řádku 4, zaměří v původním konfigu element Item podle jeho názvu (Name), které se musí rovnat hodnotě host a přepíše původní hodnotu ve value (localhost) novou hodnotou myhost. Podstatné jsou zde dvě hodnoty xdt:Transform a xdt:Locator, které zjednodušeně říkají co se má s tagem stát a na jakém přesně tagu se to má stát.

Na řádku 6 je transformace která přidá na konec konfiguračního souboru Element <Item Name=“xyz“ … ale jen v případě, že tam už takový element neexistuje. Přidání na konec konfiguračního souboru, může být někdy nežádoucí. Například proto, že logicky chcete seskupit nějaké hodnoty k sobě. To můžete samo o sobě zajistit použitím (řádek 11) InsertAfter, InsertBefore ale tyto elementy zase vkládají tag vždy a mohli byste tam pak mít duplicity. Pokud chcete vložit nějaký element na nějaké konkrétní místo bez duplicit, pak je nutné použít atribut Remove viz. řádek 10 a pak InsertAfter, InsertBefore.

Locator může nabývat několika hodnot. Condition, Match a XPath, díky kterým lze zaměřit jeden nebo více tagů z původního konfiguračního souboru. Atribut Transform potom říká, co se se zaměřenými tagy má stát. Může nabývat hodnot Replace, Insert, InsertBefore, InsertAfter, InsertIfMissing, Remove, RemoveAll, RemoveAttributes, SetAtributes. Jednotlivé hodnoty jsou celkem samo popisné a můžete si jednotlivé příklady omrknout v dokumentaci. Výsledný konfig po transformaci pak vypadá následovně.

Zdroje a odkazy