Miroslav Holec
Premium

YAML jako nástupce JSON konfigurace v moderním .NETu

Miroslav Holec   12. února 2022

Tento článek je již velmi zastaralý. Článek nemusí popisovat aktuální stav technologie, ideální řešení a můj současný pohled na dané téma.

YAML je lidsky čitelný a snadno serializovatelný jazyk. Ačkoliv největší oblibě se těší u Python vývojářů, je velmi nepravděpodobné, že byste na něj ve světě .NETu ještě nenarazili. Prvního releasu se dočkal již před 20 lety, jeho duchovními otci jsou Clark Evans a Oren Ben-Kiki a v současné době je hojně používán pro účely nejrůznějších konfigurací. A má velký potenciál nahradit JSON konfigurace v .NETu.

Tímto článkem bych chtěl doporučit YAML jako čitelnější alternativu k JSON konfiguračním souborům v .NET aplikacích. Pokusím se ve vás vzbudit k YAMLu důvěru, vypíchnout výhody a ukázat, jak lze YAML v .NET aplikacích používat.

Pár slov o YAMLu

Velmi jednoduchý a přehledný rozcestník nabízí webová stránka yaml.org. Samotný text webové stránky je napsaný v jazyce YAML, takže po první návštěvě můžete zhodnotit, jak se vám tento formát líbí. V době vynalezení, před 20 lety, se jednalo jen o další značkovací jazyk vedle HTML či SGML, z čehož také vznikl název „yet another markup language”. Příliš nadčasový ten název není, protože dnes je YAML používán pro vytváření konfiguračních souborů či specifikací. Jen namátkou zmíním:

YAML je specifický svou syntaxí, která vyhovuje Python vývojářům a právě na této platformě se těší velké oblibě. Díky 20 leté historii vzniklo pro YAML nespočetné množství knihoven i nástrojů na všech myslitelných platformách. Dobrá zpráva je, že podporu YAMLu najdeme i v dnešním .NETu.

Co je špatně s JSONem

Proč vůbec přemýšlet nad přechodem od JSON formátu k YAMLu? JSON je stabilní formát, který se nijak zásadně nerozvíjí. Pokud jste první JSON soubor otevřeli někdy před 15 lety a po této době se podíváte do současných JSON souborů, pravděpodobně vás nic nepřekvapí. Z pohledu konfiguračních souborů je JSON velmi otravný díky svým složeným závorkám. Lépe je na tom i formát INI, který můžete v současných .NET aplikacích také používat. Další velkou nevýhodou JSONu je chybějící podpora pro komentáře. To je u konfiguračních souborů velmi nepříjemné a řešitelné jedině přidáváním různých description vlastností. YAML je v těchto ohledech výhodnější.

Proč je YAML lepší volba

Už ve svém základu YAML nabízí syntaxi, která je mnohem čitelnější. YAML soubory lze snadno upravit i v obyčejném poznámkovém bloku, aniž by se vývojář bál, že někde zapomene na nějakou tu závorku. YAML soubory jsou v konečném důsledku kompaktnější. Díky podpoře komentářů lze konfigurační soubor dokonale popisovat. V neposlední řadě YAML obsahuje neustále se rozšiřující sadu funkcionalit, které mají smysl spíše v jiných scénářích, než v konfiguraci .NET aplikací. Příjemnou drobností může být například i ochrana proti duplicitním konfiguračním klíčům.

image-20220206105524853

Je vhodné doplnit, že YAML a JSON lze mezi sebou snadno převádět. Můžete tedy vzít existující JSON konfiguraci a během pár vteřin ji mít připravenou v YAMLu.

Základní syntaxe a pravidla

Naznačil jsem, že YAML toho umí mnohem více než JSON. Dobrá zpráva je, že pro účely vytvoření konfiguračního souboru pro .NET aplikaci si vystačíme jen se základní sadou pravidel. Až budete potřebovat používat YAML v jiných případech (docker, azure pipelines, ansible), můžete se doučit zbytek. Každý YAML soubor má typicky příponu yaml nebo yml a obsah začíná třemi pomlčkami.

Mezery

YAML je založen na odsazování pomocí mezer. Zdůrazňuji mezery, nikoliv TABy. Do VS Code můžete přidat plugin YAML od Red Hatu, Rider umí YAML nativně a velmi dobře. Microsoftí Visual Studio YAML trochu podporuje, byť asi bych sáhl po nějakém pomocníkovi typu Preview-YAML (nezkoušel jsem). Podpora v IDE většinou znamená jen obarvení kódu a zjednodušení odsazování. I bez pluginů tedy lze bez problémů YAML soubory spravovat. Základní pravidla jsou, že:

  • hierarchie (mapy) se vytváří odsazením dvěma mezerami na začátku řádku
  • klíč: hodnota u slovníků se vytváří mezerou za dvojtečkou

Pochopitelnější je vše z příkladů níže:

Slovník [ key value pairs ]

Nejjednodušší podoba YAMLu může být obyčejný slovník typu klíč: hodnota. Například:

---
Logging:LogLevel:Default: Warning
Logging:LogLevel:System: Warning

Na příkladu je též patrné, proč je důležitá mezera za dvojtečkou pro oddělení klíče a hodnoty.

Mapy [ directories, maps ]

Plochý slovník je ale příliš „ukecaný”, takže můžeme vytvořit hierarchii pomocí následující mapy:

---
Logging:
  LogLevel:
    Default: Warning
    System: Warning

Znamená to, že za dvojtečkou odřádkujeme, odsadíme o 2 mezery a píšeme další úroveň. Výsledek po přečtení YAMLu a převedení do konfigurace v .NETu je totožný jako u prvního příkladu.

Pole [ lists, arrays ]

Užitečná mohou být také pole. Například budeme chtít vytvořit systémové uživatele a jejich výchozí role.

---
accounts:
  mholec:
    roles:
      - admin
      - "editor"
  jnovak:
    roles:
      - reader

Všimněte si, že při definování hodnot můžu a nemusím použít dvojité uvozovky pro řetězce. Různá IDE často uvozené řetězce obarvují jinak, takže uvozovkám dost možná dáte přednost. Důležité je, aby za pomlčkou následovala vždy jedna mezera.

Skaláry a komentáře

Při nastavování hodnot klíčům potřebujeme různé skaláry. Obvykle je nemusíme uvozovat, ačkoliv u řetězců to vnáší dle mého názoru pořádek. Komentáře se uvádí před definované vlastnosti pomocí hashe:

---
celeCislo: 20
desetinneCislo: 90.87

# zde chci mít komentář
retezec: "100"
verteNeverte: true
hexa: 0xC
narozen: "2022-01-09"

Proti těmto hodnotám pak v .NETu máme properties v třídách, kterým přiřadíme odpovídající CLR typ. A to je celá magie. Chápete-li toto, nepotřebujete JSON.

Nástroje a podpora v .NET světě

Jak jsem zmínil, všechna IDE mají přirozenou podporu pro YAML. Je to nakonec jen texťák. Pomocí různých pluginů lze pak získat barvičky a automatické odsazování při psaní YAMLu. Naprosto úžasné je v tomto ohledu mé oblíbené IDE Rider od JetBrainsu.

image-20220206112922048

Když bych byl hodně líný, mohu použít vizuální editor YAMLů na macOS. Dost možná něco podobného bude existovat i pro Windows. Je to spíše hračka navíc, protože zase tak složité YAML konfigurace na mých hobby projektech nemám.

image-20220206115711329

👉 YamlDotNet

Více než 37 milionů stažení má za sebou NuGet balíček YamlDotNet, který je na platformě .NET dostupný od roku 2018. V současné době je venku již 11. verze tohoto balíčků a můžete ji používat v tradičním .NET Frameworku i moderním .NET 5/6/... Sám o sobě tento balíček zřejmě nepoužijete (pokud nechcete používat nějaké pokročilé YAML funkce) a tak se rovnou podíváme na ten důležitější.

👉 NetEscapades.Configuration.Yaml

Chcete-li YAML použít pro konfiguraci .NET 5/6/... aplikací, můžete použít NuGet balíček, který napsal již v roce 2016 britský vývojář Andrew Lock. I když balíček poslední rok neaktualizoval, je stále zcela aktuální a funkční. V současné verzi je postaven nad výše uvedeným YamlDotNet a přidává do aplikace nový Configuration Source. Zapojení do aplikace je stejné, jako v případě JSON souborů:

WebHost.CreateDefaultBuilder(args)
  .ConfigureAppConfiguration(builder => 
  {
    builder.AddYamlFile("appsettings.yml", optional: false);
  })
  .UseStartup<Startup>()
  .Build();

V praxi spíše budete budete chtít YAML soubor umístit mezi ostatní konfigurace. Na mém webu to mám pro představu tak, že:

  • nejprve si odložím host configuration chain
  • poté všechnu konfiguraci smažu přes Sources.Clear()
  • a následně nastavím dle priority co potřebuji

![image-20220206113957366](https://cdn.miroslavholec.cz/articles/upic/b4f306c7-8349-4846-ad00-e645b4dcbed4.png)

User Secrets

Na mých přednáškách doporučuji neukládat si různá tajemství (hesla, klíče) do běžných appsettings souborů, ale zvolit raději User Secrets. Ty jsou postaveny na JSON formátu, takže jsem si musel napsat rozšíření, která mi přidají podporu pro User Secrets v YAMLu. Kód si můžete stáhnout a použít dle potřeby.

Trochu nepříjemné je, že Visual Studio a další IDE předpokládají, že user secrets jsou v JSONu a vytváří je jako náhodný GUID. To jsem nezlomil a zkrátka mám nalinkovanou složku se všemi User Secrets, kam si v případě potřeby vlezu. Abych se v tom vyznal, místo GUIDů používám smysluplnější řetězec.

Takže můj csproj vypadá takto:

image-20220206114631957

A složka s User Secrets takto:

image-20220206114723816

Toto je ale spíše něco navíc. Microsoft dlouhodobě umožňuje zapojit do .NET aplikací konfiguraci ve formátech JSON, XML nebo INI a přesto User Secrets navrhl tak, že mohou být jen v podobě JSON.

Závěrem

Přechod od JSONu k YAMLu provádím aktuálně na všech projektech. Není to zatím standardní řešení a mnoho vývojářů může mít pocit, že je to z jakéhokoliv důvodu riskantní cesta. Přál bych si, aby se .NET opět posunul dál a hodil JSONy za hlavu. Jsou sice skvělé v HTTP komunikaci, ale naprosto nevyhovující pro konfiguraci aplikací.

Můžete použít nebo forknout NuGet balíček od Andrew Locka a uložit si ho jako součást code base. Je napsaný zcela standardně (mrkněte na jednoduchý kód) a pouze umožňuje zapojení sady ConfigurationSource + ConfigurationProvider. Podkladový balíček YamlDotNet je léta ověřený a samotný YAML též. Z mého pohledu mi vadí pouze špatná podpora User Secrets.

Nakonec ještě jeden tip. Pokud vás JSONy koušou a chcete jít úplně standardní cestou, zkuste INI soubory. Podpora je součástí webového frameworku, takže jen místo AddJsonFile() použijte AddIniFile() a máte život o něco lehčí.