Sunday, June 6, 2004
Synchronizace stavových automatů. Rozumíte návrhovému vzoru Mediator?
Návrhový vzor Mediator zamezuje těsným vztahům mezi objekty zavedením prostředníka (mediatora), který jejich interakci zapouzdří. Tak praví strohá, ale výstižná definice. Řečeno jinak, Mediator snižuje přímé i nepřímé zatížení třídy jinými třídami.
Vzor Mediator je většinou vykládán na příkladu interakce komponent v uživatelském rozhraní, které spolu komunikují přes prostředníka, jímž je formulář. Listbox se seznamem zemí neví nic o Listboxu se sezamem měst - po výběru jiné země je vyvolána událostní procedura formuláře, v níž je kód pro naplnění druhého Listboxu městy ve vybrané zemi. Každý ovládací prvek spolupracuje jen s formulářem, který notifikuje o změně ve svých vlastnostech, a na formuláří je kód propagující změny do dalších prvků. Na způsobu chování nezáleží, formulář může být u prvku zaregistrován jako Observer (v terminologii jazyka JAVA Listener), jehož metoda je zavolána po změně stavu prvku, nebo v .NET zaregistrujeme u ovládacího prvku delegáta s obslužnou metodou, jejíž signatura se shoduje se signaturou události. Komplexního chování prezentační vrstvy není dosaženo přímou spoluprací mnoha objektů, ale zavedením inteligentní mezivrstvy, která je recipientem heterogenních notifikačních zpráv objektů a současně autorem a distributorem nových aktualizačních zpráv pro další objekty, jež po jejich přijetí změní svůj stav a přitom mohou prostředníkovi odeslat další notifikační zprávy. Zdůraznil bych, že prostředník je autorem zpráv, takže informaci o notifikaci nemusí jen přeposlat, ale také dokáže argumenty původní notifikační zprávy před odesláním kreativně pozměnit, filtrovat, anebo dokonce rozešle události v jiném pořadí. Jak uvidíme, všechny tyto charakteristiky jsou klíčové pro mediatora koordinujícího synchronizaci stavových automatů business objektů.
Kdyby ovládací prvky mezi sebou komunikovaly přímo, tak i jednoduchá změna chování prezentační vrstvy roztočí spirálu sisyfovského dohledávání a ošetřování dopadů změny v kódu všech prvků.
Použití vzoru Mediator ale není omezeno na prezentační vrstvu a jeho kvality se plně projeví až při řízení složité interakce stavových automatů tříd v business vrstvě.
Představte si systém pro nábor zaměstnanců na různé pozice. V systému jsou evidovány nabízené pracovní pozice a uchazeči. Když uchazeč projeví zájem o pozici, je vytvořen nový objekt pro relaci mezi uchazečem a pozicí, v němž jsou uložena data o průběhu procesu výběru jednoho uchazeče. Platí pravidlo, že v jednom okamžiku může být Uchazeč přiřazen jen k jedné Pozici. Pozice, Uchazeč i Relace mají své stavové diagramy. Uveďme si příklady stavů.
Pozice může být ve stavu:
Nová - Zahájení životního cyklu pracovní pozice.
Přiřazen alespoň jeden uchazeč – O pozici se zajímá alespoň jeden uchazeč. Tento stav je důležitý pro manažery, kteří jsou odpovědni za obsazení pozice a zajímá je, zda například týden po vypsání místa je o pozici zájem, nebo je třeba investovat více peněz do propagace.
Přijat alespoň jeden uchazeč – K pozici se může vázat více volných míst, tento stav manažery náboru informuje, že již byl vybrán alespoň jeden vhodný zaměstnanec.
Obsazená – Pozice byla obsazena. Počet nabízených míst je roven počtu přijatých uchazečů.
Zrušená – Pozice byla zrušena. Pozici je možné kdykoli zrušit, což značí, že k ní již není možné dále přiřadit uchazeče a přiřazení uchazeči, kteří ještě nebyli přijati, jsou ihned odmítnuti.
Stavy uchazeče
Nový – Založení uchazeče.
Zajímá se o pozici –Uchazeč byl přiřazen k pozici a prochází různými zkouškami. Nelze mu přiřadit další pozici.
Přijat – Uchazeč byl přijat na pozici. Pozice musí být notifikována o přijetí uchazeče.
Odmítnut – Uchazeč byl odmítnut, to znamená, že je ho možné přiřadit k jiné pozici.
Propuštěn – Uchazeč (zaměstnanec) byl propuštěn. Opět ho je možné přiřadit k jiné pozici.
Zrušen – Uchazeč byl zrušen. Zrušit lze jen uchazeče ve stavu Nový, Odmítnutý a Propuštěný. Je nutné notifikovat aktivní relaci mezi Uchazečem a Pozicí.
Stavy relace mezi uchazečem a pozicí
Nová – Nová relace mezi uchazečem a pozicí založena. Je nutné notifikovat pozici i uchazeče, že byla mezi nimi vytvořena relace.
Uchazeč prošel psychotesty – Uchazeč úspěšně prošel psychotesty.
Uchazeč odmítnut po psychotestech –Uchazeč neprošel psychotesty, notifikovat pozici a uchazeče o odmítnutí.
Uchazeč splnil všechny požadavky – Notifikovat pozici o přijetí dalšího uchazeče, notifikovat uchazeče.
Zrušena – Došlo ke zrušení relace, důvodem může být to, že uchazeč o pozici ztrati zájem nebo je zrušena pozice. Notifikovat uchazeče a pozici o zrušení.
Jde sice jen o reprezentativní množinu tříd a jejich stavů, ale i mezi takto malým počtem tříd existuje poměrně složitá spolupráce.
Například při zrušení pozice musejí být notifikovány všechny aktivní Relace, ty přejdou do stavu zrušena . Je notifikován Uchazeč, že byl odmítnut. Relace zpětně notifikuje o svém zrušení i Pozici, protože důvodem zrušení může být jindy ztráta zájmu ze strany Uchazeče.
Další příklad. Když relace přejde do stavu Uchazeč splnil všechny požadavky, tak musí být notifikována pozice, u níž dojde ke změně stavu jen tehdy, když se jedná o prvního přiřazeného uchazeče. Dále je notifikován uchazeč, který přejde do stavu Přijat.
Představme si nyní, že třídy Uchazeč, Pracovní pozice a Relace informaci o změně svého stavu nabídnou okolí ve formě událostí. Každý objekt z jedné třídy si přihlásí odběr událostí asociovaných objektů z dalších tříd a pak všichni spustí divokou událostní přestřelku se zběsilými kulkami v podobě vzájemných notifikací.
Když Pozice přejde do stavu zrušena, informuje první relaci, ta změní svůj stav na zrušena, relace svoji změnu stavu zašle uchazeči, ten přejde do stavu „Odmítnut“ a vyvolá svoji událost „Změna stavu“, tu odchytí Relace, která na stav „Odmítnut“ u uchazeče nereaguje. Relace informaci o svém zrušení zasílá vždy recipročně objektu Pozice. Pozice pod dokončení kolečka s první Relací notifikuje další Relaci a kolečko s mírně obměněnými aktéry proběhne znovu. Všechny objekty jsou při tomto vzájemném přeřvávání kandidáty na slušivou svěrací kazajku.
V čem je ale hlavní problém? Události nemusí být zpracovány ve správném pořadí. Představme si, že u Pozice z nějakého důvodu zavedeme další tranzientní stavy „Vyžádáno zrušení pozice“, „Pozice je rušena“ a teprve finálním stavem je náš původní stav „Zrušena“. Do stavu „Vyžádáno zrušení pozice“ přejde pozice ihned po žádosti uživatelem (přesněji po volání metody Cancel), do stavu „Pozice je rušena“ , když je zpětně notifikována první Relací o jejím přechodu do stavu Zrušena. Pozice přejde do finálního stavu „Zrušena“ až po obdržení potvrzení o svém zrušení od všech dalších relací. Tady ale narazíme – když Pozice přejde do stavu „Pozice je rušena“, tak začne tuto událost rozesílat všem Relacím.
To znamená, že Relace2 a následující obdrží nejdříve informaci o přechodu Pozice do stavu „„Pozice je rušena“ a později o ( již nepravdivém) přechodu do stavu „Vyžádáno zrušení pozice“. Když se zkomplikují i stavové automaty dalších objektů, staneme se nechtěnými svědky rozhovoru bandy otrlých lhářů.:)
Pořadí při rozesílání událostí není sekvenční, a i když bychom mohli do objektu Pozice a dalších dopsat logiku, která se o sekvenční distribuci postará, nepůjde o šťastné řešení. Aby třída konvenovala svému okolí, dosadíme do ní znalost, jak si okolí komunikací představuje, a porušíme tak princip zapouzdření. Třída svému okolí sděluje, jaké změny v ní nastaly, ale nesmí se starat o reakce okolí. Třída musí být vždy nonkonformní a kašlat na své sousedy, jež ji nutí, aby se adaptovala na jejich způsob komunikace a chování. (BTW: Zjsitil jsem, že miluji OOP a návrhové vzory, protože k sousedům mám stejný postoj :) )
Odpovědnost za sekvenční rozesílání událostí přidělíme nové třídě Mediator. Po svém vytvoření budou objekty zaregistrovány v Mediatoru, který si přihlásí odběr jejich událostí. Třídám Pozice, Relace a Uchazeč přidáme metody, které budou volány mediátorem, když nastane událost. Například objekt Pozice bude mít metodu „NotifikujUchazečOdmítnut“, která bude mediátorem zavolána, když Relace přejde do stavu „Uchazeč odmítnut po psychotestech“ nebo do stavu „Zrušena“.
Aby mediátor nebyl příliš komplikovaný a nepřehledný, vytvoříme pro každou třídu jednoho zpracovatele události. Každý zpracovatel událost bude implementovat rozhraní s jedinou metodou „ZpracujUdálost“, které přijímá dva argumenty. Prvním argumentem je odkaz na objekt, který událost vyvolal, a druhým jsou parametry události. Zpracovatel „ví“, jaké metody musí u objektů volat pro každou jedinečnou kombinaci argumentů události. (Když zpracovatel objektu Relace obdrží událost „Přechod do stavu Zrušena“, tak zavolá u asociovaného objektu Pozice metodu NotifikujUchazečOdmítnut“ a u Uchazeče metodu „ZůstávášNezaměstnaným“:) )
Jak zajistíme sekvenční zpracování?
V událostních metodách mediátor odchytne událost a zavolá vždy jen obecnou metodu handleEvent, které kromě odesílatele a argumentů události přijímá odkaz na zpracovatele (m_JobHandler), jenž reaguje na danou událost. Objekt m_JobHandler zpracovává událost „StavZměněn“ třídy Pracovní pozice.
handleEvent(sender, e, m_JobHandler);
Metoda handleEvent
private void handleEvent(object sender, EventArgs e, BProcessEventHandlerBase processor)
{
EventStateHolder holder = new EventStateHolder(e, sender, processor);
m_eventsQueue.Enqueue(holder);
if (!m_inEventBubbling)
initEventBubbling();
}
Metoda handleEvent nejdříve uloží všechny informace o události do nové instance naší třídyEventStateHolder. Zde mimochodem vidíte kouzlo polymorfismu, protože naše třída EventStateHolder se nestará o detaily událostí, ale vyžaduje jen, aby argumenty události byly odvozeny z třídy EventArgs a zpracovatelé událostí z třídy (rozhraní) BProcessEventHandlerBase. Poté je událost zařazena do fronty (v .NET třída Queue) a jestliže se jedná o první událost, je zavolána metoda initEventBubbling, která se postará o předání události do zpracovatele. Tento kód je důležitý – bublání událostí je zahájeno jen při první události, všechny další události libovolných business objektů, které jsou přímou nebo nepřímou reakcí na první událost, jsou jen zařazeny do fronty a k novému spuštění distribuce událostí realizovaného metodou initEventBubbling nesmí dojít.
private void initEventBubbling()
{
Debug.Assert(m_eventsQueue.Count > 0, "BMediator events queue is empty!");
m_inEventBubbling = true;
while (m_eventsQueue.Count > 0)
{
EventStateHolder eh = (EventStateHolder) m_eventsQueue.Dequeue();
eh.Processor.ProcessEvent(eh.Sender, eh.EventArguments);
}
m_inEventBubbling = false;
}
V metodě initEventBubbling se nejdříve ujistíme, že fronta událostí není prázdná. Pak nastavíme privátní proměnnou m_inEventBubbling na true, aby metoda handleEvent již při zpracovávání návazných událostí metodu initEventBubbling nevolala. V jednoduchém cyklu while zpracujeme sekvenčně všechny události postupně přidávané do fronty po rozeslání každé události.
Mediatora můžete vylepšit. Ke každé události mohou být registrovány preprocesory, kteří například zalogují všechny události a postprocesory, odesílající manažerovi informaci o provedených změnách. Když budeme chtít rychle změnit chování aplikace bez zásahu do existujícího kódu, můžeme napsat nový preprocesor, který událost zpracuje zcela jinak, a protože z metody vrátí true (nepokračovat v distribuci událostí, již jsem vše udělal), tak se originální zpracovatel události nedostane ke slovu. Preprocesory načteme dynamicky při startu aplikace s využitím reflection API.
private void initEventBubbling()
{
Debug.Assert(m_eventsQueue.Count > 0, "BMediator events queue is empty!");
m_inEventBubbling = true;
while (m_eventsQueue.Count > 0)
{
EventStateHolder eh = (EventStateHolder) m_eventsQueue.Dequeue();
bool continueEventBubbling = distributeEventToPrePostProcessors(eh.Sender, eh.EventArguments, m_preProcessors);
if (continueEventBubbling)
{
eh.Processor.ProcessEvent(eh.Sender, eh.EventArguments); distributeEventToPrePostProcessors(eh.Sender, eh.EventArguments, m_postProcessors);
}
}
m_inEventBubbling = false;
}
private bool distributeEventToPrePostProcessors(object sender, EventArgs e, ProcessorCollection processors)
{
bool result = true;
foreach (IProcessor processor in processors)
{
if ((processor.ProcessEvent(sender, e)))
{
result = false;
break;
}
}
return result;
}
Také můžete přes mediátora řídit distribuci událostí transakčně s potvrzováním a vracením jednotlivých kroků a ukládat změny ve všech participujících objektech na konci úspěšné transakce do databáze.
Vzor Mediator je nepominutelnou dominantou každého návrhu aplikace, jež vyžaduje komplexní komunikaci mezi stavovými automaty různých tříd.
Sunday, June 6, 2004 7:53:00 PM (Central Europe Standard Time, UTC+01:00)
Analytické drobky | Návrhové vzory | UML
Wednesday, June 2, 2004
Hledají se vývojáři v .NET Frameworku aneb pojďte dělat kvalitní SW bez kompromisů:)
Jak stálí členové konference EMWAC vědí:), ve společnosti DIGI TRADE stále přijímáme vývojáře pro .NET Framework. Protože informace v emailovém podpisu je velmi strohá, chci v tomto spotu popsat, jak probíhá výběr vhodného kandidáta a co uchazečům nabízíme.
Samozřejmě, že konkrétní detaily smlouvy jsou individuální a odvíjejí se od pozice, na kterou je člověk zařazen.
Poté co mě kontaktujete na emailu rstein at digi-trade.cz,vám zašlu podrobný popis nabízené pracovní pozice. Ideální bude, když ke kontaktnímu emailu přiložíte životopis. Jestliže se vám bude pozice líbit, smluvíme si s vámi termín osobní schůzky. Můžete si vydechnout, s žádným personalistou se nesetkáte.:) Pohovoru je přítomen vedoucí týmu vývoje na platformě Microsoft Štěpán Krejcar a já. Nejdříve se dozvíte něco o nás a firmě, pak vás požádáme o shrnutí vašeho profesního životopisu. Následuje nejzajímavější část:), ve které prověřujeme odborné znalosti. Tu mám na starosti já, takže můžete být bez obav.:) Cílem není uchazeče potopit, ale diskutovat s ním o vývojářských tématech uvedených v odborném životopise. Na začátku je uchazeč dotázán, zda se vyzná v UML notaci. Když řekne, že ano, bavíme se s ním nad UML modelem. Když UML neznáte, tak si jeho pasivní čtení u nás rychle osvojíte, ale jeho neznalost neovlivňuje celkové hodnocení pohovoru. Preferujeme uchazeče, kteří rutinně ovládají ADO.NET, MSSQL, Web Forms a/nebo Windows Forms. Také předpokládáme perfektní znalost SQL, uchazeč má za úkol napsat složitější dotaz na základě předloženého schématu databáze. Zdůrazňuji, že se ptáme hlavně na témata, v nichž se cítíte sami silní. Smůlu mají uchazeči, kteří do životopisu uvedou, že znají .NET Remoting a pak si myslí, že MarshalByRefObject je jméno vysoce postaveného žoldáka z napoleonských válek:). Bez legrace, opravdu se mnoho uchazečů uváděním technologie, z níž znají jen název, vyřazuje samo.
Jestliže odbornou částí projdete bez vážných znalostních mezer, nabídneme vám ihned práci. Když se objeví více srovnatelných kandidátů nebo si nejsme jisti využitím znalostí konkrétního člověka v týmu, necháváme si nějakou dobu na rozmyšlenou. Nejpozději do jednoho týdne ale dostanete konečné vyjádření.
Proč byste měli jít právě k nám?
1) Chcete pracovat se mnou.:)
2) Nemáte rádi rutinní práci, ale milujete složité projekty z oblasti CRM, Document Managamentu, Integrace aplikací, intranetových aplikací...
3) Chcete pracovat ve firmě, kde se dělá vždy analýza a systémový design aplikací, takže odpovědnost za kvalitní aplikaci neleží jen na bedrech programátora.
4) Nejsme firma, která přijme lidi na jeden projekt s "žhavými" termíny, naslibuje jim všem nejméně modré z nebe a po dokončení projektu je bez skrupulí vyrazí. U nás chceme, aby se lidi neustále vzdělávali, aby odborně rostli – oboustranně výhodná symbioza zaměstnance a firmy, chcete-li.
5) Nebaví vás neustále před dokončením projektu kompletně přepisovat aplikaci, protože si zadavatel usmyslel, že je všechno jinak? U nás jsou zákaznící srozuměni s tím, co se objeví v každé verzi aplikace a co již ne, takže nemáte pocit, že vaše několikatýdenní práce je rozmetána rozmary zákazníka. Dohadování se zákazníkem je záležitostí projektových vedoucích a obchodníků, nikdy ne programátorů.
6) Jsme autorizované certifikační středisko, a proto přímo u nás můžete získat odborné certifikáty (MCP, MCAD, MCSD, IBM certifikáty atd.). Firma hradí veškeré náklady spojené se získáním certifikace, navíc dostanete po úspěšném složení zkoušky jednorázovou finanční odměnu a po dobu platnosti certifikátu máte speciální prémie k platu. Za složení a hrazení certifikace nechceme žádné „ďábelské“ úpisy jako jiné firmy, ve kterých byste se zavazovali, že budete pro nás určitou dobu pracovat nebo že při odchodu z firmy náklady na zkoušku zpětně doplatíte.
7) Samozřejmě vám nabídneme i dobré finanční ohodnocení (13. plat), stravenky a další maličkosti.:)
Jestliže tedy právě teď měníte zaměstnavatele, určitě se mi ozvěte na email rstein at digi-trade.cz. Pokud máte dotazy, nebojte se napsat do diskuze pod článkem.
Aktualizace: Adresa společnosti
DIGI TRADE
Vlkova 36, Praha 3
tel: +420 2 22722356
fax: +420 2 22722302
web:
http://www.digi-trade.cz
Wednesday, June 2, 2004 4:34:00 PM (Central Europe Standard Time, UTC+01:00)
Ostatní
Monday, May 31, 2004
"Některé věci mají k sobě nepopsatelně blízko" - příkaz switch v jazyce C# a metoda String.IsInterned
Jazyk C# povoluje konstrukci switch, v níž se podmíněná sekce kódu zvolí podle shody proměnné typu string s konstantním řetězcem v sekci case.
switch (myVariable1 + myVariable2)
{
case “sekce1”:
{
//Zpracuj
break;
}
case “sekce 2”:
{
//Zpracuj
break;
}
default:
{
//Nedelej nic
break;
}
}
I když napsání swich výrazu s řetězcem je pro vývojáře jednoduchou záležitostí, zpracování switch výrazu kompilátorem již tak triviální není. Představte si, že porovnání shody řetězců by bylo prováděno znak po znaku. S prodloužením řetězců by docházelo k lineárnímu nárůstu doby potřebné pro porovnání řetězců. Jak asi ze své zkušenosti víte, příkaz case je vždy stejně rychlý bez ohledu na délku řetězců a k žádnému neohrabanému porovnávání řetězců znak po znaku v žádném případě nedochází. Jak je tedy příkaz case kompilátorem zpracován a rozvinut?
Všechny literály (string someString = “Ja jsem literal“) jsou při JIT kompilaci aplikace přidány do speciální hashovací tabulky vytvářené a spravované běhovým prostředím, v níž klíčem je řetězec a hodnotou odkaz (reference, adresa v paměti) na tento řetězec. Podstatné je, že řetězec se stejnou sekvencí znaků se v tabulce vyskytuje nanejvýš jednou. Takže pokud nadeklaruji kromě výše uvedené proměnné someString proměnnou someString2 a inicializuji ji stejným řetězcem jako proměnnou someString ( string someString2 = “Ja jsem literal“)), tak běhové prostředí při JIT kompilaci zjistí, že v hashovací tabulce klíč Ja jsem literal již existuje a proto do proměnné someString2 přiřadí odkaz na objekt umístěný pod tímto klíčem. Proměnné someString a someString2 odkazují poté na stejné místo v paměti, což si lze snadno ověřit voláním metody ReferenceEquals.
Z umístění do hashovací tabulky jsou při JIT kompilaci vyloučeny řetězce, jež jsou konstruovány dynamicky za běhu programu. Takže řetězec v proměnné string someString3 = “Ja jsem literal“ + someString2 přidán nebude. Třída String má ale statickou metodu Intern, jejím účelem je dodatečné vložení řetězce a odkazu na něj do hashovací tabulky. Příkazem String.Intern(someString3) je do hashovací tabulky přidán obsah proměnné someString3.
Když nechceme řetězec do hashovací tabulky přidat, ale chceme se jen dotázat, zda je v hashovací tabulce již obsažen, použijeme další statickou metody String.IsInterned. Metoda IsInterned při nalezení řetězce v hashovací tabulce vrací odkaz na tento řetězec. Když řetězec v hashovací tabulce není, metoda IsInterned vrátí null.
Nyní si už můžete sami odvodit, jak kompilátor efektivně zpracuje příkaz switch s řetězci. Po přechodu na příkaz switch je zjištěn proměnný rozhodovací řetězec, podle jehož hodnoty mají být zvoleny sekce case (switch(myVariable1 +myVariable2) ). Poté je volána metoda String. IsInterned, jíž je předán jako argument rozhodovací řetězec. Když metoda vrátí null, je jisté, že žádná sekce case nevyhovuje rozhodovacímu řetězci, protože všechny řetězce u case sekcí byly přidány do hashovací tabulky při JIT kompilaci. Jestliže metoda vrátí odkaz na řetězec, je testována shoda vráceného odkazu s odkazy řetězců u jednotlivých sekcí case. Když se reference řetězců shodují, je zvolena daná sekce case. Porovnávány jsou jen adresy řetězců v paměti (odkazy, reference), nikdy ne jednotlivé znaky, a proto rychlost provedení příkazu switch není nijak determinována délkou řetězců.
Monday, May 31, 2004 8:39:00 PM (Central Europe Standard Time, UTC+01:00)
.NET Framework
Thursday, May 27, 2004
O MDA iniciativě, nerozhodných tazích Microsoftu a klukách na pískovišti
Dnes jsem se zúčastnil konference Vývoj celopodnikových aplikací v .NET pořádané Microsoftem a společností LBMS. Na konferenci jsem se přihlásil, protože v pozvánce byla zmínka o MDA (Model Driven Architecture) a já byl zvědavý, jestli na této přednášce bude upřesněn nebo vyjasněn z mého pohledu zdráhavý až macešský vztah Microsoftu k MDA iniciativě.
Protože konference nebyla zaměřena jen na vývojáře, Honza Šeda v úvodu shrnul hlavní výhody .Net platformy a vyzdvihl její přínosy pro segment „Enterprise aplikací". Termín „Enterprise aplikace“ je dnes chameleónskou nádobou, do které si každý s gustem naleje své myšlenky a sny o extra projektu. Já používám pracovní definici, že Enterprise aplikace jsou velmi složitá a drahá řešení, která se významně podílejí na podpoře kritických business procesů firmy a netolerují se u nich chyby ani výpadky:). Jinak řečeno, vývoj a podpora Enterprise aplikace je méně riskantní než kšeftování se zbraněmi, ale zase ne o tolik. :.) Na zbraních ale určitě vyděláte víc.:)
Dle zkušeností z jiných konferencí, kde přednášeli partneří Microsoftu, jsem měl obavu, že i tato konference bude jen zástěrkou pro propagaci produktů společnosti LBMS. Naštěstí tomu tak nebylo. Přednášející z LBMS shrnuli základní rysy a cíle MDA architektury a soustředili se na dominantní koncept PDA – rozvržení různých modelů jednoho systému na hypotetickém grafu, jehož jednou osou je míra izomorfie modelu s přirozenými pojmy z problémové domény a druhou stupeň připravenosti modelu na automatizované generování programového kódu. (Computation Independent Model, Platform Independent Model, Platform Specific Model, o Language Specific Modelu nic nezaznělo). Mapování mezi modely je řízeno exaktními pravidly, i když v přednášce jejich význam nebyl podle mě dostatečně zdůrazněn. MDA tedy nenechává například mapování z analýzy do systémového designu na naší intuici, ale vyžaduje, aby byla pravidla této „hry“ explicitně zachycena, a tím se stala kontrolovatelnými.
Firma LBMS prezentovala svůj produkt Select Component Architect podporující MDA. Hodnotit celou aplikaci zatím nemíním, protože jsme demo Select Component Studia dostali na osahání a reálná zkušenost je vždy věrohodnější než pozorování dobře drezúrovaného přednášejícího, který má instrukce, co z programu předvést, aby dychtivé publikum ohromil, a jaké nedostatky musí naopak taktně zamlčet.
Takže vztah Microsoftu k MDA je dost rozpačitý. Občas pronese silácké prohlášení o svém zklamání z UML a MDA, přičemž u MDA své zklamání spíše anticipuje nebo věští, protože mi uniká, jak se mohu zklamat v něčem, co si svoje místo ve světě softwaru teprve hledá, a jindy zase podpoří své partnery, kteří na MDA a UML vsázejí. Beru to tak, že Microsoft hraje přetahovanou se svým hlavním rivalem IBM a občas si holt umanutě dupne, aby IBM pochopila, že koupí Rational Rose nedeportuje Microsoft na periferii hlavních trendů ve vývoji softwaru. Přejme to oběma firmám, i malí vzteklí kluci na sebe silácky pořvávají, ti tvrdší s gustem přerazí o sebe i pár klacků, ale potom všichni svorně stavějí po celém pískovišti zvelebující bábovičky.
Thursday, May 27, 2004 7:43:00 PM (Central Europe Standard Time, UTC+01:00)
Analytické drobky
Wednesday, May 26, 2004
Svůdná asynchronní volání v ASP.NET 2.0
ASP.NET 2.0 ulehčí vývojářům práci nativní podporou asynchronních volání. V aktuální verzi 1.1 je prováděno pouze synchronní odesílání formuláře („postback“) Při větším množství „postbacků“, které musíme používat například proto, že plníme některé serverové ovládací prvky podle uživatelem zadaných hodnot v jiných ovládacích prvcích, rychle odhalíme méně příjemné aspekty „postbacků“. Uživatelé, zvláště ti s pomalejším připojením, takové aplikace nepoužívají rádi, protože jim obrazovka neustále nepříjemně problikává nebo musejí nezanedbatelnou dobu čekat na nové zobrazení stránky.
Řešení je mnoho. Ti troufalejší z nás na stránce uloží všechna data bez ohledu na to, že každý uživatel využije jen malý zlomek. Podmíněné plnění prvků je zajištěno JavaScriptem. Nevýhodou je, že uživatelé zbytečně stahují do svého prohlížeče i data, která nikdy nepoužijí. Při větším objemu dat je toto řešení nepřijatelné.
Lepším řešením je například asynchronní volání WWW služby z JavaScriptu nebo využití objektu XmlHttp. Uživatel pracuje a aplikace na pozadí stahuje potřebná data ze serveru.
Do ASP.NET 2.0 bylo přidáno nové API pro asynchronní volání, které vývojáře zbavuje nutnosti znát detailně principy a způsoby zajištění asynchronního volání. Interně ale toto API (alespoň v IE) stále pracuje s komponentou XmlHttp.
Jak nové API vypadá?
Serverový ovládací prvek musí implementovat rozhraní ICallBackEventHandler.
interface ICallBackEventHandler
{
string RaiseCallbackEvent(string eventArgument);
}
Metoda RaiseCallBackEvent přijímá jeden argument typu string s názvem eventArgument, který je zaslán z klientské funkce na stránce v prohlížeči. Může se jednat například o identifikátor kategorie, jejíž výrobky mají být načteny. Metoda RaiseCallBackEvent načte data, ať už z databáze, XML souboru nebo jiného datového zdroje, a ve formě řetězce je vrátí. Návratová hodnota metody je zaslána do prohlížeče, který ji zobrazí nebo jinak zpracuje.
Serverový ovládací prvek si při svém renderování vyžádá od stránky kód v JavaScriptu, který z klienta asynchronně zavolá aplikační logiku na serveru. Do třídy Page byla přidána přetížená metoda GetCallbackEventReference. Zde je jedna z jejích verzí.
GetCallbackEventReference(Control control, string content, string callback, string context);
V argumentu control metoda dostane odkaz na serverový ovládací prvek, pro nějž chceme vygenerovat skript, argument content je názvem metody v JavaScriptu, která poskytne parametr (eventArgument), se kterým pracuje výše popsaná metoda RaiseCallBackEvent. V argumentu callback je název další funkce v JavaScriptu, které má být předán výsledek vrácený metodou RaiseCallBackEvent. Tato fukce se většinou postará o aktualizaci uživatelského rozhraní. V argumentu context je název proměnné v JavaScriptu, kterou používáme pro odlišení různých asynchronních volání. Hodnota proměnné context není nikdy zasílána na server, používají ji jen funkce na klientovi.
Naše funkce v JavaScriptu, jíž je předán výsledek asynchronního volání, musí mít tuto signaturu.
function NazevFunkce (raiseCallbackEventMethodResult, context)
Jak mnou zvolené názvy argumentů napovidaji, v prvnim argumentu je výsledek asynchronního volání a ve druhém obsah proměnné context v okamžiku zahájení asynchronního volání.
V jiné verzi metody GetCallbackEventReference lze zadat také název funkce v JavaScriptu, jež bude zavolána, když v metodě RaiseCallbackEvent dojde k výjimce.
A to je celý trik. V rychlosti zrekapitulujme, jak celý scénář probíhá. Metodou GetCallbackEventReference vygenerovaný klientský kód zavolá na klientovi metodu __doCallBack. Ta získá data z funkce „content“ a odešle je na server, kde běhové prostředí nalezne serverový ovládací prvek, jemuž jsou data určena, zavolá jeho metodu RaiseCallbackEvent a výsledná data zašle zpět na klienta metodě „callback“.
Do třídy HttpBrowserCapabilities byly přidány dvě vlastnosti, abychom si mohli při renderování ovládacího prvku ověřit, zda cílový prohlížeč asynchronní volání podporuje. Vlastnost SupportsCallback nese informaci o přítomnosti nebo absenci podpory asynchronního volání v prohlížeči, ale nesděluje nic o tom, jak jsou případná asynchronní volání realizována. Vlastnost SupportsXmlHttp sděluje, jestli prohlížeč pro asynchronní volání může použít objekt XmlHttp.
Wednesday, May 26, 2004 8:11:00 PM (Central Europe Standard Time, UTC+01:00)
ASP.NET
Monday, May 24, 2004
Katalog PDA zařízení na MobilManii
Na Mobilmanii přibližně před týdnem spustili testovací verzi katalogu PDA zařízení. K dnešnímu dni v něm najdete kolem 35 zařízení s operačním systémem Windows Mobile nebo Palm OS. Mimo běžného zobrazení všech důležitých parametrů jednoho zařízení si můžete pro detailní srovnání zobrazit vedle sebe až tři zařízení, takže ihned máte například informaci, jak se cenově srovnatelná PDA od sebe liší. Už nemusíme shánět informace o vysněném PDA prosíváním vylučujících se informací na netu nebo se se svými dotazy obracet na většinou ve svém oboru nekompetentní prodavače či infantilně žvatlající "kikiny" na různých infolinkách (bílým vránám v těchto povoláních se omlouvám), ani bastlit v Excelu vlastní srovnávací tabulky.:)
Jestliže si nejste jisti, jaké PDA byste si chtěli koupit, ale máte alespoň matnou představu, k čemu by vám mělo sloužit, a neděsí vás pojmy jako bluetooth nebo WI-FI, tak si po zadání svých nároků na funkce nechte PDA doporučit.
Katalogu se dá vytknout jen to, že v něm nejsou zahrnuty komunikátory, tedy zařízení, která umějí nejen plnit roli kapesního počítače, ale lze z nich i telefonovat. Pod komunikátory jsou řazena hlavně zařízení s operačním systémem Symbian (SE P900), Palm OS (Handspring Treo) a Windows Mobile Phone Edition (MDA II). Pro tyto přístroje je na MobilManii vyhrazen samostatný katalog. Hranice mezi mobilním telefonem, smartphonem, komunikátorem a "čistým" PDA je stále méně patrná, takže schopnost katalogu porovnávat zařízení všech typů by se hodila. I tak jde ale o velmi užitečnou službu MobilManie svým čtenářům.
Monday, May 24, 2004 8:29:00 PM (Central Europe Standard Time, UTC+01:00)
Mobilitky
Sunday, May 23, 2004
Bez lásky, naděje a ve vakuu víry - román Písečná kosa Vladimíra Körnera
Vladimír Körner (narozen 1939) je znám hlavně svými filmovými scénáři (Adelhaid, Lékař umírajícího času, Pramen života). Historický román Písečná kosa nezapře autorovo filmové vidění ani to, že historie je pro něj pouhou zástěrkou pro rozehrání dalšího deziluzivního traktátu o selhávajích lidských plánech, neukojených touhách a heroismu zbavených proher. I když Písečná kosa se k dějinám a roli jednotlivce v nich vyjadřuje naléhavým jazykem naplněném obrazností a metaforami, jež ale nejsou patetické ani glorifikující, jak jsme si zvykli u autorů naivní adorujících historické osobnosti (L. Vaňková, J. Loukotková), ale dotvářejí bezútěšnou scenérii, ve které není vítězů. Nanejvýš nevýznamných vítězných odkladů.
V předehře Písečné kosy je v náznacích vylíčena cesta křížové výpravy vedené Fridrichem II do Svaté země. Poutnící prahnoucí po pozemských rozkoších v mysticky pojímaném Jeruzalému-Edenu i v městech po cestě nejsou Boží armádou, ale její nepodařenou lidskou karikaturou. Pohané popírající svými skutky Krista jdou ve jménu své lačnosti osvobodit Jeruzalém od těch, kdo v Krista nevěří. Neúspěch výpravy je zakódován v chování poutníků na cestě, aniž by musel Körner další historická fakta dodávat.
"Oremus - křičeli marně mniši a spínali ruce.
Prosili o trest v samotě a odpovídal jim vzdálený hukot města a přístavu. V průjezdech se smály ženy, v zahradách a keřích rozevíraly svá hedvávná stehna, cítily závrať společného, zmnohonásobeného hříchu sobotní noci. Vyjdou za svítání s čelenkami na hlavách ke svým kostelům. Počkají v prachu, až se otevře brána, a budou se modlit bez stop lítosti nad uniklou nocí. Čím víc hřešily, tím se budou tvářit pyšněji a tím vroucněji budou toužit po spáse."
Již v předehře se setkávám se Sovincem, místem, odkud pochází hlavní hrdina knihy Alwin. Jak pochopíme, Alwina a jeho matku opustil otec, který se nechal zlákat Fridrichovou křížovou výpravou.Mladý Alwin vstoupí do řádu Bratrů svaté panny Marie Jeruzalémské, protože nesnesl, že jeho matka, kterou považoval za symbol čistoty, nevydržela čekat na návrat otce, a našla si milence. Banální událost v životě jeho matky se stane pro Alwina osudovou. Jak vidno, dle Körnera viny nepřecházejí do sedmého pokolení na syny jen z otců.
V řádu Alwin pozná, že za předstíranými ctnostmi vystavovanými na odiv venkovnímu světu je řád, jako každý lidský útvar, prolezlý zlobou, kariérismem, sobectvím a touhou po moci. Řád je jen bezpečnou ulitou pro nectnosti svých členů. Při tažení do Pruska je Alwin svědkem vraždy komtura řádu Rinna. Vrahy nejsou ale pohani, nýbrž skupinka ambiciozních řádových bratří, ve které je i Alwinův domnělý přítel Hanno z Losangenu. Když Hanno Alwina pozná, pokusí se jej zabít. Alwin je zachráněn pohanskou dívkou a ošetřován na hradě panny Amalbergy. Körner se vysmívá všem, kdo neochvějně tvrdí, že dokáží v životě rozeznat přítele od nepřítele. Tuší, že ideologické ani společenské vazby nejsou dostatečným důvodem pro přátelství nebo nepřátelství ani pro lidské nebo bestiální chování.
S Amalbergou se Alwin po svém zotavení spřátelí. Amalberga je pro něj symbolem čistoty. Sama Amalberga osciluje mezi chutí prožít život v lehkomyslném smyslném objetí, i když ví, že její tělo není pro muže přitažlivé, a pocitem, že celý její život patří Bohu, který nesnáší hřích. Událostí s ironií Körnerovi vlastní vyřeší její dilema za ní. Ještě před svým sňatkem s dalším řádovým bratrem Richaredem Clee, ji Richard znásilní. Odevzdání Bohu ani život pod egidou čistoty nás před záměry lidí z masa a krve neochrání.
Alwin se po rozloučení se zlomenou Amalbergou dostane k pohanské ženě Loně. Zde si prožije své nespoutané smyslné léto naplněné milováním bez zábran a bezstarostností. Bez zátěže minulosti a projekcí budoucnosti. Alwin prožije léto, o němž snila, i kterého se obávala Amalberga. Na Alwinovi Körner před čtenářem litujícím Amalbergu, že si nedovolila smyslové radosti a že se sama odsoudila k životu s nenáviděným manželem, rozehraje její druhý potenciální osud.
I hedonická hra smyslů je jen dalším mámením, protože pro Lonu Alwin představuje kratochvilné vyplnění času do doby, než se vrátí její muž. Léto smyslů je vystřídáno zimou, v níž si Alwin po příchodu Lonina muže, zachrání život s pomocí dítěte. Lonina dítěte, které ho po příchodu do vesnice nenávidělo...
Je jedno bezstarostné léto dostatečným smyslem celého života? Nevím, odpovídá po svém zvyku Körner. Jen nám v dalších kapitolách naznačuje (a myslím ze má pravdu), že přežít své smyslné léto je cestou do krajiny zoufalství, vzpomínek a nenaplněných návratů. A neprožít jej vůbec, znamená odsoudit se s grácií-harpyjí k zoufalství ihned.
Alwin se vrátí ke svým bratřím a v samotě se snaží na své zážitky zapomenout a žít podle řádových pravidel. Na řádovém hradě se setká znovu i s Hanem Losangenem a bezděčně se stane příčinou jeho odsouzení za vraždu komtura Rinna. Žádné zadostiučinění ale necítí. Po několika letech Alwin z hradu odchází a poznává, že dlouhý celibát jen vybičoval jeho touhu po ženách a a dlouhé odloučení od světa chuť urvat si z něj co nejvíce. Alwin poznává, že nařízení řádu jsou v rozporu s jeho přirozeností, tužbami i svobodným myšlením. Byť i později zmoudřelý jedinec, který si dovede zachovat dočasně potlačené svobodné myšlení, vždy odhodí kazajku řádu.
Řádem není míněn jen vojensko-církevní útvar, jehož součástí je Alwin, ale libovolná organizace, ať už čistě politická nebo jen agresivní sdružení stejně smýšlejících v nějakém spolku. Körner na tomto místě varuje jakoukoli totalitu, že její nehumánní a násilné nároky na celý soukromý intelektuální i emocionální život jedince nezadržitelně vedou k jejímu pádu, protože se vždy odštěpí skupina lidí – disidentů, kteří své právo na svobodný život a myšlení nesmění s prvním drzým vyvolávačem na trhu ideologií za pestrobarevné materiální cetky.
Jiný autor by se s tímto poselstvím spokojil, Alwina by nechal oženit a vrátil by ho zmoudřelého do Sovince vládnout. U Körnera optimismus na konci kapitoly nevyhnutelně střídá skepse na začátku další kapitoly. I když si Alwin uvědomí, jaké v řádu vládne pokrytectví, neumí nebo nemá sílu žít jinak a jinde. 9. srpna 1241 je Alwin společně se svými "bratry" poslán do bitvy proti Tatarům – apokalyptickému ale hmatatelnému přízraku děsícímu v té době celou Evropu. Bitva je prohrána a mezi padlými je i Alwin. Byl jeho život jen sledem událostí a poznání, jejichž význam Alwin nedokázal nebo nechtěl rozpoznat? Jako příliš mladý a plný ideálů neodpustil matce běžnou a pochopitelnou nevěru a tento morální imperativ se stal hlavním motivem jeho vstupu do řádu, jako starší a zmoudřelý se vrátil do řádu, jenž na svých válečných výpravách dokázal porušit snad všechna přikázání i ideály. I když Körner dává smysl jeho smrti i smrti dalších řádových rytířů, cítíme, ze je spíše přesvědčen, že jednu ztracenou generaci střídá jen předem z(a)tracená generace další. Je jedno, čím se rozměňujeme na drobné. Stejně budeme před Bohem shledání lehkými.
„V tom boji narazili Tataři ponejprv na železné rytíře
; jejich odpor otřásl nájezdníky natolik, že i přes své vítězství nepokračovali v dalších výbojích směrem na západ. Nečekaně se stočili k jihovýchodu, prošli moravskými úvaly a hledali spojení s chánem Batu v Uhřích.
Začínalo nové jaro.
„Zbylí lídé, kteří nebyli pobiti oněmi ranami, neodvrátili se pokáním od skutků svých rukou, nevzdali se klanění démonům a modlám zlatým, stříbrným, měděným, kamenným a dřevěným, které nemohou viděti ani slyšeti, ani choditi. Neodvrátili se pokáním od svých vražd a jedů, ani od svých necudností a krádeží.“ “
Sunday, May 23, 2004 5:18:00 PM (Central Europe Standard Time, UTC+01:00)
Literární a jiné humanitní úlety
Friday, May 21, 2004
Bezpečná změna verze assembly zveřejněné pro COM
Do konference Emwac VS.NET poslal dotaz pan V. Gazda, jenž se chtěl vyhnout opakované registraci .NET assembly pro COM klienty po změně verze assembly.
Zde je stručný postup vedoucí k eliminaci opakované registrace:
1) Napsal jsem jednoduchou knihovnu s názvem TestLibrary v C#. Rozhraní IType je označeno atributem InterfaceType, kterému je do konstruktoru předána hodnota ComInterfaceType.InterfaceIsDual - rozhraní podporuje brzkou (early) i pozdní (late) vazbu. Rozhraní ITest implementuje třída Test. Z třídy Test je pro Com klienty dostupná pouza metoda Test, protože jsem aplikoval atribut ClassInterface(ClassInterfaceType.None). Možnost None z enumerace ClassInterfaceType registračním nástrojům signalizuje, že z třídy mají být publikovány pouze metody z implementovaných rozhraní (tedy určitě ne zděděné metody).
using
System;
using
System.Runtime.InteropServices;
using
System.Reflection;
namespace
RStein
{
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public
interface ITest
{
void TestMethod();
}
[ClassInterface(ClassInterfaceType.None)]
public
class Test : ITest
{
public Test()
{
}
public
void TestMethod()
{
Console.WriteLine("Hello from COM " + Assembly.GetExecutingAssembly());
}
}
}
2) Vygeneroval jsem silné jméno (strong name), podepsal a zkompiloval verzi 1.0.0.0 assembly.
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyKeyFile(@"..\TestLibrary.snk")]
3) Assembly jsem zaregistroval pro COM spuštěním regasm.exe.
RegAsm.exe TestLibrary.dll /tlb:TestLibrary.tlb
4) Napsal jsem primitivního klienta v C++, který přes COM volá metodu TestMethod z rozhraní ITest. Dle očekávání žádný problém.
#include
"stdafx.h"
#include
<wtypes.h>
#import
"mscorlib.tlb"
#import
"TestLibrary.tlb" no_namespace named_guids
int
_tmain(int argc, _TCHAR* argv[])
{
CoInitialize(NULL);
ITest * pTest = NULL;
HRESULT hr = CoCreateInstance(CLSID_Test,
NULL,
CLSCTX_INPROC_SERVER,
IID_ITest,
reinterpret_cast<void**>(&pTest)
);
pTest->TestMethod();
pTest->Release();
CoUninitialize();
}
5) Změnil jsem verzi assembly TestLib.dll na 2.0.0.0, opět jsem kód zkompiloval a umístil do GAC. Verzi 1.0.0.0 jsem z GAC smazal. Po spuštění C++ klienta jsem dostal z metody CoCreateIntance HResult, že nelze nalézt požadovaný soubor.
[assembly: AssemblyVersion("2.0.0.0")]
6) V machine.config jsem instruoval runtime, že nyní mají všichni klienti používat verzi 2.0.0.0 assembly. C++ klient opět typy z assembly TestLib.dll nalezne a žádná opakovaná registrace přes regasm.exe není třeba.
<dependentAssembly>
<assemblyIdentity name="TestLibrary" publicKeyToken="12ba27c531641c01" />
<bindingRedirect oldVersion="1.0.0.0" newVersion="2.0.0.0" />
</dependentAssembly>
Friday, May 21, 2004 10:14:00 PM (Central Europe Standard Time, UTC+01:00)
.NET Framework
Wednesday, May 19, 2004
Interval - článek Vývoj sofistikovaných WWW služeb v .Net Frameworku
Na Intervalu mi dnes vyšel článek, který vysvětluje vytváření WWW služeb s použitím nového API pro příjem a zasílání zpráv ve Web Services Enhancements 2.0. Článek je úvodem do světa WSE, v dalších článcích se chci se zaměřit na vysvětlení jednotlivých standardů (ws:addressing, ws:security, DIME atd.). Standardy implementované ve WSE konečně začínají zbavovat WWW služby etikety sice důležité, ale zatím nezralé technologie, které chybí například životně důležité standardy pro bezpečnou komunikaci. WWW služby určené k překonání komunikačních bariér mezi různými operačními systémy i aplikacemi paradoxně nové proprietární berlínské zdi vytvářely, protože každý dodavatel WWW služeb byl nucen autentizaci uživatelů nebo kryptování dat řešit individuálně a jeho volba byla limitována dostupnými prostředky preferovaného vývojového prostředí. V .Net Frameworku jsme si za tímto účelem vyvíjeli rozličné SOAP extenze nebo http moduly.
Microsoft si také chytře vývojem WSE ověřuje životaschopnost, výhody a slabiny nových standardů, aby v Longhornu mohl představit zralou technologii bez (doufejme) zásadních problémů. Jak asi víte, v Longhornu budou WWW služby součástí nového komunikační platformy s kódovým názvem Indigo. Potěšující je, že Indigo by mělo být dostupné i pro starší operační systémy Windows XP a Windows 2003, takže ihned vyvíjet budeme moci i pro zákazníky, kteří jsou při přechodu na nové technologie laxnější.:)
Od vás, čtenářů, bych rád věděl, jestli chcete, abych se v článcích zaměřil jen na praktické použití nových standardů. To znamená hlavně na to, jaké třídy a metody použiji na klientovi a serveru, když chci poslat přílohy nebo co všechno musím udělat/nastavit, abych obsah zprávy zakryptoval atd.. Nebo byste byli raději za hlubší ponor do hlubin standardů, takže bych popisoval i strukturu SOAP zpráv vyměňovaných mezi klientem a serverem a vy byste tak získali lepší vhled do (alespoň pro mě :) ) mimořádně vzrušujícího infrastrukturního pozadí WWW služeb?
Wednesday, May 19, 2004 7:59:00 PM (Central Europe Standard Time, UTC+01:00)
Web Services
Tuesday, May 18, 2004
Další hrátky s Merge replikací
Tak dnes jsem si lál do příliš brzy zpychlých individuí, protože ve spotu z minulého týdne jsem se chlubil, jak se nám podařilo Merge replikaci zkrotit. Dnes za mnou přišel tester, který dostal za úkol vyzkoušet replikaci ve Virtual PC s Windows XP a souborovým systémem FAT. Uznávám, kombinace Windows XP a FAT zní nesmyslně, ale z mně neznámého důvodu ji na některých stanicích náš zákazník používá, a my jsme si chtěli být jisti, že nebudou při zítřejším releasu žádné problémy.
Tester přišel, že se mu nedaří založit subscription. Vždy nastala tato výjimka :
"System.Runtime.InteropServices.COMException(0x80004005). The subscription to publication <nazev publikace> is invalid.
Překvapilo mě, že k založení "subscription" přes tuto hlášku došlo, protože se zobrazila v sekci Subscriptions v Enterprise manageru. Vyzkoušel jsem založení "subscription" na třech dalších počítačích, virtuálních i hmotných.:) Vše proběhlo bez problémů. Po několika neúspěšných pokusech o založení "subscription" na stroji s XP a FAT, jsem se pokusil zaregistrovat inkriminovaný MS SQL server v mém Enterprise Manageru . Přitom jsem si všiml, že občas se název MSSQL serveru zobrazí, občas ne, registrace selže, ale za 10 sekund již proběhne bez problémů. Začal jsem mít podezření, že jde o síťový problém. Tester se mi až po mém přímém a přiznám už dost nevrle a neomaleně formulovaném dotazu, jaké že to koniny musel provádět s názvem stanice, přiznal, že po instalaci MSSQL změnil název počítače. Vrátit původní název stanici ale nestačilo. Bylo třeba znovu zaregistrovat jméno MSSQL serveru.
Musíte nejdříve zjistit, pod jakým jménem se MSSQL hlásí.
select @@SERVERNAME
Poté odregistrujete server ze seznamu známých serverů.
sp_dropserver <Současný název serveru>
Server znovu zaregistrujete se správným jménem a parametrem 'local'. Pouze jeden server může být registrován jako "local" Od této chvíle bude proměnná @@SERVERNAME vracet nový název.
sp_addserver <Nový název> , 'LOCAL'
Ještě můžete zkontrolovat, že procedura sp_addserver opravdu úspěšně proběhla. Lokální server musí mít ve sloupci Id nulu.
sp_helpserver
Poučení? Merge replikace je opravdu zkrocena, jen nad kreativními testery je třeba nestále práskat varovným bičem. Nemám rád kritickou podmínku úspěchu zvanou lidský faktor.:)
Tuesday, May 18, 2004 7:58:00 PM (Central Europe Standard Time, UTC+01:00)
(MS)SQL tipy a triky