Vlastní .net provider - část 1.
Pojďme se přesunout na chvíli od vestavěných providerů k těm, které si vytvoříme podle obrazu svého. Jednotlivé kroky si předvedeme na jednoduchém příkladu.
Něco málo úvodem o ProviderBase třídě
ProviderBase třída je výchozí třídou, v případě, že chceme psát vlastní providery, stejně tak jako od ní dědí všechny dostupně providery v .NET Frameworku 2.0. Tato třída je tedy novou třídou v novém frameworku, vyznačuje se svojí jednoduchostí a obsahuje pouze minimum (jednu) metod s minimem vlastností (slovy dvě).
Nejdříve se podíváme na metodu virtual Initialize(string name, NameValueCollection config). Tato metoda nám umožňuje napsat vlastní inicializaci pro provider a to díky kolekci config ve které najdeme všechny parametry, které jsou definovány u definice providera v konfiguračním souboru. Tak jsme například získali odkaz na connectionString u prvního MsSqlSiteMapProvidera. Je nutné zdůraznit, že tato metoda, se volá pouze jedenkrát za životní cyklus a v případě vícenásobné inicializace je vyvolána výjimka InvalidOperationException. Pro všechny providery pak platí, že běhové prostředí .NETu zajišťuje (samozřejmě v případě správného použití), aby k instancování konkrétní implementace ProviderBase docházelo pouze v jednom Threadu.
Definujeme Interface našeho providera
Nyní již víme, jak budeme moci napsat vlastní implementaci pro vlastní provider, co je ovšem důležité, definovat rozhraní pro komunikaci, tak abychom mohli skutečně využít všech výhod, které nam tento návrhový vzor přináší. Pro tento účel definujeme dvě třídy.
Statická třída pro našeho providera
Statická třída představuje obecný interface, pomocí kterého budeme přistupovat ke konkrétní implementaci providera. Jak už jsem uvedl, jedná se o statickou třídu - taktéž novinku v .NET 2.0 - jejíž všechny metody a vlastnosti jsou statické.
Důležitou součástí takové třídy je inicializace providerů, kteří jsou definováni v konfiguračním souboru aplikace. Toto můžeme zajistit následující částí kódu (metodou)
private static void Initialize() { 1. if (provider == null) { 2. lock (lockObject) { 3. if (provider == null) { 4. RandomServiceSection section = (RandomServiceSection)WebConfigurationManager.GetSection("system.web/randomService"); 5. providers = new RandomProviderCollection(); 6. ProvidersHelper.InstantiateProviders(section.Providers, providers, typeof(RandomProviderBase)); 7. provider = providers[section.DefaultProvider]; 8. if (provider == null) 9. throw new ProviderException("Unable to load default RandomProviderBase"); 10. } 11. } 12.} }Projděme si jednotlivé řádky:1.-3. kontrolujeme, zda ještě není instancován žádný provider - pro znalé představují řádky 1-3 tzv. DoubleCheckedSingleton design pattern.4. načteme si příslušně označenou sekci z konfiguračního souboru, která obsahuje seznam dostupných providerů.5. instancování kolekce providerů, kterou budeme používat 6. volání této konstrukce nám zajistí nainstancování všech dostupných providerů - zároveň volá metodu Initialize 7. přiřazení výchozího providera, se kterým se bude momentálně pracovat 8.-9. ošetření případu, kdy neexistuje výchozí provider
Po inicializaci providera už nám zbývá jenom definovat rozhraní, pro tento vzorový případ jsem definoval pouze jednoduché rozhraní a to metodami
- public static int Random()
- public static int Random(int lowerBound, int upperBound)
- public static int Random(int lowerBound, int upperBound, int inicialization)
public static int Random() { RandomService.Initialize(); return RandomService.Provider.Random(); }
Máme tedy definováno rozhraní v naší tříde RandomService, nyní vytvoříme druhou třídu, která bude předkem pro naše konkrétní implementace.