Jarda Jirava

Vývojář a architekt řešení postavených na technologii .net framework. Zabývám se jak vývojem webových aplikací za pomoci asp.net, tak také desktopových aplikací winform. Při návrhu řešení a samotném vývoji pak využívám dlouholetých zkušeností se zpracováním obchodní logiky a pravidel aplikací získaných z vývoje komerčních aplikací pro finanční a bankovní instituce.

Microsoft MVP

Microsoft MVP - Client App dev

Silverlight minesweeper

Get Microsoft Silverlight

Navrhi COOL design a vyhraj zkušební let po Evropě!

Poslední příspěvky

13
XII

Web events - část 3.

Konkrétní příklad - web event

Jak už jsem naznačil v minulém článku, v tomto pokračování se budu věnovat konkrétnímu příkladu, který by měl objasnit použití a možnosti, které nám přináší healt monitoring.

Určitě i Vás, případně Vaše klienty, zajímají odpovědi na otázky, jak je využívána aplikace, nejsou na ní prováděny neoprávněné operace, a jistě spousta dalších, které by zaplnily velkou část tohoto příspěvku. Sám jsem byl ovšem velice zvědavý na to, jakým způsobem je tato aplikace využívána a jakým způsobem se po ní pohybujete. Stejně tak jistě i Váš klient tyto informace ocení.

Tvorba WebRequestAdvEvent

Pro sledování Vašeho pohybu na těchto stránkách jsem původně chtěl využít již vestavěný WebRequestEvent. Ovšem zde jsem narazil, a to hnedka na dvě nepříjemné věci. Jedna mě zamrzela poměrně hodně, ta druhá o něco méně, protože jsem věděl, jak jí odstranit. Pravda, nakonec jsem tím odstranil obě, ale budu rád, když mi zanecháte Vaše zkušenosti, a případně postup jak jste odstranili první vadu.

WebRequestEvent

Nejdříve jsem si myslel, že použiju tuto třídu ke sledování pohybu na stránkách, ovšem již při testování jsem narazil. Přestože jsem vše nakonfiguroval, a troufám si tvrdit že správně, události této třídy se ne a ne logovat. Prošel jsem několik možných konfigurací, ale ani s jednou se mi nepovedlo úspěšně zalogovat jedinou událost, pomocí mého oblíbeného vyhledávače jsem se snažil o tomto problému najít více informací, ale ani tady jsem příliš neuspěl. Jediné co jsem zjistil, že už v Beta 1 byl tento problém, bohužel bez odpovědi. Tudíž logování informací z této třídy odpadlo, ono stejně bych tento přístup zavrhl, protože informace, které obsahuje a shromažďuje, ne úplně odpovídali tomu, co jsem chtěl sledovat já navíc.

Vlastní trída poděděná z WebRequestEvent

Po zjištění výše uvedeného jsem se rozhodl implementovat vlastní třídu, která bude rozšiřovat shromažďované informace a navíc půjde logovat. Tudíž jsem vytvořil vlastní třídu a přepsal jsem metodu public override void FormatCustomEventDetails(WebEventFormatter formatter). Do této metody jsem doplnil následující část kódu, která zjišťuje informace o prohlížeči, který uživatel použil a také, ze které stránky se na ty mé dostal.

System.Web.HttpContext ctx = System.Web.HttpContext.Current;
formatter.IndentationLevel++;
if (ctx != null) {
	formatter.AppendLine(string.Format("User agent : {0}", ctx.Request.UserAgent));
	if (!string.IsNullOrEmpty(ctx.Request.UrlReferrer))
		formatter.AppendLine(string.Format("Referrer : {0}", ctx.Request.UrlReferrer.ToString()));
} else {
	formatter.AppendLine("You use this web event outside of web application. No data are provided.");
}
formatter.IndentationLevel--;

Zde si dovolím upozornit, že všechny uživatelské události, by měli mít hodnotu eventCode větší než WebEventCodes.WebExtendedBase

Měl jsem vytvořenou vlastní třídu pro sledování událostí, teď jí ještě umístit na správné místo ve stránkách a nastavit konfigurační soubor. A měl jsem hotovo, stačilo pár řádků kódu a vím o Vás všechno :-).

Používáme WebRequestAdvEvent

Proto, abych mohl použít logování vlastních událostí, musí se tyto události někde generovat. Tato aplikace využívá možností MasterPage, takže umístění vyvolání události bylo snadné, přímo do metody Page_Load a to následovně.

WebRequestAdvEvent evt = new WebRequestAdvEvent(this);
evt.Raise();

Události se nám vyvolávají a jediné co zbývalo, je nastavit jejich logování pomocí konfiguračního souboru. Není přeci nic snažšího, protože z první a druhé části víme, jak na to.

Zhodnocení místo závěru

Osobně si myslím, že používání událostí tímto způsobem je poměrně užitečná věc, která nám ušetří něco málo práce. Jen bych měl několik poznámek ke způsobu, jakým dochází k zápisu informací. V době, kdy je prosazován formát xml, by aspoň mohl existovat přepínač, který by umožnil rozšířené hodnoty logovat do tohoto formátu. Přeci jen mít data nestrukturovaná znamená jejich horší zpracování. Rozumím, že při použití některých providerů, není tento formát úplně optimální, ale přeci jen, jedná se převážně o systémové informace, které uvidí zkušení uživatelé a ti si s XML už ví rady.

A nakonec prosba na Vás, pokud víte, jak zprovoznit logování událostí pocházejících ze třídy WebRequestEvent, budu rád, když napíšete své postřehy do komentářů. Díky

Publikováno pod: asp.net providers
9
XII

Web events - část 2.

Tím vše nekončí - healthMonitoring ve web.config

Pokud si vezmeme ostatní providery, většinou tímto krokem končíme a jediné co musíme udělat, je korektně nastavit konfigurační soubor. Toto však až tak neplatí pro web events, i když vše je relativní a toho nastavování budeme moci provést o něco více, než v případě registrování ostatních provider patternů.

V konfiguračním souboru tak pod elementem nedefinujeme pouze podsekci providers, ale také říkáme, které události chceme sledovat, jakým způsobem budou sledovány, jaká pro ně existují pravidla a jak se seskupují, případně jaký chceme používat způsob cachování (bufferu). Jednotlivé sekce zkusím popsat

bufferModes

V této sekci definujeme možnosti bufferingu zvoleného providera, který zachytává a dále publikuje události. Nastavovat tímto způsobem můžeme providery, které jsou odvozeny od BufferedWebEventProvider. Tím, že zabezpečíme buffering, zvýšíme tak výkonnost naší aplikace, neboť nebudeme zapisovat okamžitě vzniklé události, ale tyto budou pozdrženy před jejich zápisem pomocí příslušného provideru, zároveň můžeme rozlišit mezi kritickými (urgentními) a standardními událostmi.

Ukázka


	

profiles

Přidáním této podsekce máme možnost ovlivnit profil zaznamenávání událostí. Nastavením vlastností tohoto profilu určíme, jaký je minimální počet instancí události, po kterých se má tato zalogovat, případně také její maximální počet (nic nám nebrání nastavit hodnotu Infinite), jakož i minimální časový interval mezi dvěma shodnými událostmi, které se mají logovat. Těchto profilů využijeme v okamžiku, kdy se dostáváme do kritických situací a potřebujeme kontrolovat počet zapisovaných dat a zátěž na systém.

Ukázka jaké je výchozí nastavení pro sekci profiles:


	
	

eventMappings

Předpokládám, že tato sekce nás bude zajímat více než ostatní, zejména v okamžiku, kdy budeme tvořit vlastní události. V této sekci můžeme přidávat vlastní seskupování událostí, nebo přidávat vlastní události do již předpřipravených skupin. Tyto připravené skupiny jsou dvě All Events a All Audits, které se pak ještě rozpadají na <All Errors a All Failure. Nic nám ovšem nebrání v tom, abychom si definovali vlastní skupiny a tyto skupiny si nechali zpracovávat vlastním providerem.

Ukázka se zařazením vlastní události do nové skupiny My Errors


	        

rules

Poslední z podsekcí, kterými můžeme nastovovat chování a zpracovávání událostí. Pomocí tohoto nastavení definujeme a vlastně tak seskupíme všechny výše naspecifikované hodnoty. Zapsáním pravidel tak říkáme, jakým providerem budou zpracovány jaké události a jakým způsobem profilem se tak bude dít.

Ani pro poslední podsekci nesmí chybět ukázka. Kdy si pro naši fiktivní událost definovanou v eventMapping zvolíme jeden ze standardních providerů a nastavíme jí critický profil.


  
  

Shrnutí konfigurace

Jak je vidět, můžeme díky konfiguraci sledovat a nastavovat nepřeberné množství vlastností a ovlivňovat tak způsob, kterým budeme sledovat naši aplikaci. Pokud nám stačí sledovat pouze frameworkem generované události, postačí nám k tomu jednoduché nastavení a povolení v konfiguračním souboru. Potom se použijí výchozí hodnoty a události vyskytující se ve skupinách All Errors a Failure Audits se budou zapisovat do Event logu.

Příště si na příkladu ukážeme, jak vytvořit vlastní událost a sledovat jí pomocí vlastního provideru.

Publikováno pod: asp.net providers
9
XII

Web events - část 1.

Pro dnešní příspěvek jsem si vybral jednu ze zajímavých, ale podle mého názoru, lehce opomíjených oblastí, jsou to Web events neboli také Health Monitoring. Ty slouží k monitorování webových aplikací a mohou tak pomoci administrátorům a vývojářům pomoci s výkonností aplikace a její sledování, rychlé diagnostice aplikace, ve které dochází k chybám a v neposlední řadě i sledování průběhu životního cyklu stránky.

Které všechny události můžeme sledovat

Samozřejmě že můžeme definovat i vlastní třídy, které budou sledovat události, ale aby nám vývojáři od Microsoftu ušetřili spoustu práce, máme ihned k dispozici několik tříd pro sledování událostí. Vrhneme se na jejich prozkoumání s chutí.

  • WebBaseEvent - základní třída pro všechny eventy, která obsahuje povinné vlastnosti, které musí mít každý web event. Mezi tyto vlastnosti patří, kód události, detailní kód události, datum a čas vzniku události, sekvenční číslo, text událost a detaily o události.
  • WebManagementEvent - je základní třídou pro události týkající se správy událostí, životního cyklu aplikace, zpracování požadavků a chyb, stejně jako auditních událostí.
  • WebHeartbeatEvent - je třída pro zpracování událostí, které jsou generovány v pravidelných časových intervalech pro zachycení stavových informací aplikace.
  • WebAuditEvent - základní třída pro evidování bezpečnostních událostí, používá se pro audit při zpracování autorizace, a to jak provedených tak i chybných. A nejen týkající se bezpečnosti, ale i kryptování a dalších ...
  • WebRequestEvent - základní třída pro informace zpracovávající události o požadavcích [requestech].
  • WebBaseErrorEvent - jak už název napovídá, jedná se o základní třídu pro všechny události týkající se chyb.

Dobrá, známe tedy třídy, které budeme moci používat, ale jakým způsobem je použít a jak to vše zakomponovat do našich stránek, aby to přineslo kýžený efekt. Po jakých informacích se nejspíše budeme dále shánět, jsou informace typu, kde se všechny ty informace budou shromažďovat, jak se k nim dostanu a co všechno budu muset dopsat. Nenapadá Vás to také? Mě ano a mám potěšující informaci, těch řádků, které se musí napsat není tolik, možná i méně něž kolik jsem jich již sepsal v tomto příspěvku. ;-) Ale zpátky od laškování k suchému konstatování.

Můžeme si vybrat hnedka z několika nabízených providerů, které zapisují informace o událostech do WMI, Event logu, posílají email používají SQL Server a další, případně si můžeme napsat vlastní úložiště ... po čem jsem viděl velký ohlas byl XmlWebEventProvider.

Publikováno pod: asp.net providers
7
XII

Vlastní .net provider - část 2.

Bázová třída pro RandomService

Tak abychom mohli vytvořit a dále i volat ze statické třídy RandomService konkrétní implementace, musíme ještě vytvořit abstraktní třídu, jejíž metody a případně vlastnosti budou poté implementovat konkrétní instance, které budeme tvořit, případně je vytvoří třetí strana.

Tato bázová třída má stejné metody jako statická třída, ovšem s tím rozdílem, že nejsou definovány jako statické, ale jako abstraktní. Tudíž interface takové třídy bude vypadat

public abstract class RandomBaseProvider: ProviderBase {
	public abstract int Random();
	public abstract int Random(int lowerBound, int upperBound);
	public abstract int Random(int lowerBound, int upperBound, int inicialization);
}
Samozřejmě nesmíme zapomenout na to, že tato třída musí být poděděna z ProviderBase, jinak by celé naše snažení nebylo na správné cestě a setkali bychom se s několika problémy.

Pojďme ale dále, máme vytvořeno rozhraní, výchozí třídy, které definuje přístup jakým způsobem budou volány konkrétní implementace z aplikace. Co nám tedy zbývá? Vedle napsání právě oné vlastní implementace ještě musíme zařídit, že budeme moci definovat a konfigurovat providery z konfiguračního souboru aplikace.
Je nutné říci, že abstraktní třída nemusí mít přesně stejný interface jako statická třída.

Konfigurační sekce pro vlastní provider

Již se blížíme k závěry celého našeho snažení, tato část je skutečně už jen tou pověstnou třešinkou na dortu. Zbývá nám totiž dodefinovat celkem dvě vlastnoti pro naši konfigurační třídu. Asi nemá význam se tady příliš rozepisovat, když pohled na kód řekne víc, než tisíce slov. Tady to je:

	public class RandomServiceSection: ConfigurationSection {
		[ConfigurationProperty("providers")]
		public ProviderSettingsCollection Providers {
			get {
				return (ProviderSettingsCollection)base["providers"];
			}
		}

		[StringValidator(MinLength = 1)]
		[ConfigurationProperty("defaultProvider",
				DefaultValue = "RandomProvider")]
		public string DefaultProvider {
			get {
				return (string)base["defaultProvider"];
			}
			set {
				base["defaultProvider"] = value;
			}
		}
	}

A máme vše připraveno.

Vlastně, ještě zbývá malá drobnost, samotná registrace do konfiguračního souboru a definice providerů. Toto již určitě znáte i z předchozích verzí, kdy jste si chtěli registrovat vlastní sekce v konfiguračním souboru. Tudíž nás budou v tuto chvíli zajímat oddíly configSections a především její podsekce kam přidáme definici našeho RandomServiceSection typu.

Poté už jen zaregistrovanou sekci uvedeme v život její definicí v sekci a to takto:

	
		
		
	

V této ukázce jsem zaregistroval dva providery, jeden generuje náhodná čísla pomocí třídy Random, ten druhý pak má seznam náhodných čísel uložených v databázi a vrací je postupně. Pro tento provider platí, že bude inicializován zároveń s předaným názvem connection stringu.

Závěr

Tvorba vlastního providera není příliš složitá, na co je důležité dát si pozor, aby rozhraní, které bude takový provider definovat byl pokud možno co nejvíce univerzální a nebyly do něj zahrnuty specifické - implementační - záležitosti, které by způsobily, že napíšeme pouze jednu implementaci takového provideru. Smyslem našeho snažení by měla být co největší nezávislost a možnost volby, jakým způsobem budeme implementovat požadovanou funkčnost.

Publikováno pod: asp.net providers
7
XII

Self promotion

Všechno dnes stojí na reklamě, důvtipném a neotřelém marketingu, propagaci. Tak si říkám, když už si píšu pár poznámek a něco málo vím, mohl bych toho využít a udělat si vlastní promotion.

http://providers.aspweb.cz

Tak jako několik desítek ostatních i já jsem se přihlásil do soutěže LCD za web se stránkami věnovanými Provider pattern. Snažím se na nich přiblížit popisem a příklady fungování i používání tohoto návrhového vzoru v prostředí .NET 2.0. Sám jsem tento návrhový vzor začal používat před nějakým tím časem, kdy byl k dispozici pouze .NET 1.1 a je pravda, že je dostatek situací, ve kterých se dá tohoto vzoru použít. Proto jsem si říkal, že nebude od věci zpřístupnit své znalosti i ostatním českým vývojářům. A doufat, že se mi třeba odvděčí posláním svého hlasu pod číslem 1312.

Jádrem celého webu je pak jednoduchý systém, založený na, jak jinak, provider patternu. Vlastní implementaci ContentProvideru, která umožňuje zobrazování příspěvků, jejich přidávání, stejně tak jako reakci na příspěvky. Zdrojové kódy pro tento provider budou k dispozici v blízké době. Přeci jen mé rozhodnutí přišlo takříkajíc na poslední chvíli a nerad bych dával v plén něco neodzkoušeného a neprověřeného více návštěvami.

Přeci jen jsou tyto stránky především informační, a nesnažím se myslet jen na sebe, dalšími kdo se přihlásil do soutěže byl i Tomáš Petříček, který postavil pěknou aplikaci. A přehled zajímavých řešení postavených na ASP.NET 2.0 přinesl B. Stanik T. v upoutávce Zajímavé projekty v soutěži LCDZAWEB.CZ (škoda, že jsem se do nich nevešel, že by to skutečně nikomu nic nepřineslo???).

Jenom malý povzdych na okraj

Škoda že můj poskytovatel webového prostoru zatím neumožňuje provozovat ASP.NET 2.0 stránky, určitě by to stálo za to. Navíc bych tak mohl využít a odzkoušet ten malý publikační systémek i zde.

Publikováno pod: asp.net providers , personal
7
XII

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)
, které budou vracet náhodné číslo. Vím, není to úplně originální případ, doufám však, že pro demonstraci toto bude dostačovat. Obzvláště v případech, kdy budeme chtít zajistit výpočet náhodného čísla různými algoritmy.
Každá tato metoda volá příslušné metody providera následujícím způsobem
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.

Publikováno pod: asp.net providers