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

Poslední příspěvky

výzva

7
X

Výzva - šablonový systém

Pomalu se dostáváme do finální části, kdy již máme vše připraveno a stačí nám jednotlivé produkty (knihy) vypublikovat na web.

XSL jako šablona - zavrženo

Jak jsem se již zmínil v prvních krocích, kdy jsem vytvářel doménové objekty a ty naplnil vstupními daty, xsl pro prezentaci dat bylo zavrženo. Přitom by se dalo říct, že jako šablonový systém, kdy na vstupní straně je xml, je toto řešení přímo ideální a též jsem jej v první chvíli doporučoval.

Jenže jak se říká, zákazník je náš pán a já jsem si svoji práci nechtěl ulehčit tím, že bych xsl použil. Přitom jsem chtěl nabídnout takové možnosti, aby bylo jednoduché vkládat statické texty okolo dynamických polí a to vše s možností plně ovlivnit výstupní HTML.

Chvíli jsem nad tím přemýšlel a uvažoval jsem jak něco tak jednoduchého zabezpečit, když v tom mě to napadlo, jednu takovou věc již používám a její implementace nebude náročná. Stejně tak věřím, že by nebylo náročné pro zkušenějšího uživatele znalého HTML syntaxe naučit se i těch několik málo příkazů. Navíc se tím vyvaruji i dalšího strašáka a to je použití PHP, které bylo taktéž zavrženo.

NVelocity

Přesně tak, onou spásnou knihovnou se stala NVelocity a to po úpravách z projektu Castle. Domnívám se totiž, že je to velice jednoduše uchopitelný šablonovací systém, přesně splňující základní potřeby pro publikaci potřebných informací a v případě potřeby též snadno rozšiřitelný.

Jelikož mám tuto knihovnu použitou například na tomto webu, kde si pomocí ní generuji emailové notifikace, nebyl problém ji vzít a použít i v tomto systému.

Právě z tohoto důvodu jsem se také v prvních krocích ujal vytvářet doménový model, protože objekty a především jejich vlastnosti jsou základním předpokladem a pomocí nich se zobrazují získaná data.

Jak tedy potom vypadá vygenerování výstupu z takové šablony je vidět na ukázce níže:

IPathLocatorService pathLocatorService = new DesktopPathLocatorService();
ITemplateProcessor templateProcessor = new NVelocityTemplateProcessor(pathLocatorService);
Hashtable data = new Hashtable();
data["book"] = book;
post.description = templateProcessor.RenderView("description", data);

kdy právě instance třídy Book je předána jako parametr s názvem book do transformační metody a za pomocí definice šablony je vytvořen na výstupu HTML kód.

Šablona

Definování šablony je potom již otázkou vkusu a zručnosti. V mém případě tedy otázkou trošku delší, ale věřím, že pro schopného html kodéra by tato práce nebyla vůbec těžká. Já se rozhodl pro jednoduchý výpis informací a v případě generování description jsem použil následující:

<div class="book">
    <h4>Authors:</h4>
    <ul>
#foreach ($author in $book.Authors)
    <li>$author.FullName</li>
#end
    </ul>
    <dl class="metainfo">
        <dt>ISBN</dt>
        <dd>$book.ISBN</dd>
        <dt>Pages</dt>
        <dd>$book.NumberOfPages</dd>
        <dt>Publication date</dt>
        <dd>$book.PublicationDate.ToString("dd.MM.yyyy")</dd>
    </dl>
</div>

Samozřejmě není nutné, aby výstupem transformace byl HTML kód, ale v tomto případě je to očekávané.

Jak by to probíhalo

Zde již opět přichází na řadu součinnost s případným zadavatelem zakázky. Záleží na tom, zda by měl již připravené HTML šablony, do kterých by se umisťovali jednotlivé atributy nebo by si šablony chtěl tvořit sám. V případě prvním bych nejspíše zasedl a začal jednu šablonu za druhou přepisovat a doplňovat řídící značky. V případě druhém by potom došlo k vysvětlení významu jednotlivých řídících značek a popsání doménového modelu.

Časový odhad

Vzhledem k tomu, že jsem měl připraveno a zaobaleno volání NVelocity v samostatné assembly bylo napojení do systému velice rychlé. Určitě delší čas jsem strávil nad tím, jak vhodně vygenerovat výstup a jaké informace zobrazit a předat do kterého vstupního pole třídy Post - viz napojení na WordPress pomocí XML-RPC. Celkový čas pro tento krok tedy byl 40 minut. Zde musím upozornit, že v případě předání šablon pro Petru by především definice šablon a jejich úprava mohla zabrat nepoměrně delší dobu.

Publikováno pod: .net technology , výzva
2
X

Výzva - lokální databáze

V tuto chvíli by se mohlo zdát, že naše aplikace je hotova. Postačující bude ji jen poskládat a předat k užívání.

Aktualizace dat

Co je však třeba si uvědomit, že toto nemá sloužit jako jednorázové naplnění webu a bude třeba přidávat nové produkty, případně si maličko pohrát s rozvržením a úpravou statických textů, které budou přidávány ke každému produktu.

Je tedy nutné zajistit, aby se nové položky do publikačního systému vložily a položky již jednou vložené pouze aktualizovaly. Pro zajištění tohoto úkolu jsem si vybral lokální datový soubor a využil jsem tak možností SQL Server Compact Edition v. 3.5. Za atributy, které je nutné sledovat jsem si stanovil Id, které je každému příspěvku přiděleno publikačním systémem WordPress a také ASIN, který představuje identifikátor na straně vstupních dat. Dále jsem se rozhodl též ukládat si atribut Title a Publisher a pro informaci též datum vystavení (publikace).

Tyto všechny atributy se mi vešly do jedné tabulky, kterou jsem nadefinoval z prostředí Visual Studio. Pro přístup a manipulaci s daty jsem si potom vybral LINQ to SQL, který dokáže pracovat právě i s touto lokální databází. Podpora v designeru Visual Studia však v současné chvíli chybí a tak je třeba použít nástroje sqlmetal.exe. Mě se v těchto případech osvědčilo použití .bat souboru, který obsahuje následující definice:

"c:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\sqlmetal.exe" /dbml:ArchiveModel.dbml ArchiveDb.sdf
"c:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\sqlmetal.exe" /namespace:Vyzva.Data.Archive /serialization:Unidirectional /context:ArchiveDataContext /language:csharp /pluralize /code:ArchiveModel.cs /map:ArchiveModel.config ArchiveModel.dbml

Samozřejmě můžete vynechat vytvoření mapovacího souboru, osobně však tomu dávám přednost mít jej vygenerovaný znovu a s koncovou .config

Takto vygenerované soubory tedy postačuje vložit do projektu, u .config souboru, kde jsou uloženy mapovací informace nastavit jeho Build type na Embedded resource, tak aby došlo ke vložení souboru do assembly a začít používat DataContext objekt. V tomto případě, kdy se negenerují atributy nad třídou a vlastnotmi, je třeba při vytváření instance DataContextu předat též odkaz na mapovací schéma a connection string.

if (_mappingSource == null) {
  using (Stream st = Assembly.GetExecutingAssembly().GetManifestResourceStream("Vyzva.Data.Archive.ArchiveModel.config")) {
    _mappingSource = XmlMappingSource.FromStream(st);
  }
}
string conn = ConfigurationManager.ConnectionStrings["DbMainConn"].ConnectionString;
context = new ArchivDataContext(conn, _mappingSource);

Proměnnou _mappingSource mám v tomto případě definovanou v mé Factory třídě jako statickou, neboť není nutné při každém požadavku na DataContext vytvářet a parsovat znovu mapovací schéma.

Tímto mám zaručenu základní funkcionalitu a umožněnu práci s lokální databází.

Jak by to probíhalo

Ani tento krok se zdá, že by nemusel být učiněn v součinnosti s Petřinými požadavky. Co by však stálo za úvahu je definovat si seznam atributů, které budou v této lokální databázi uchovávány a případně další požadavky. Docela dobře si dokáži představit, že by mohl být učiněn požadavek na změnu kategorie, případně její hromadné doplnění k vybraným produktům, případně jiná úprava, která nelze zajistit v exportu xml souboru.

Časový odhad

Definice struktury databáze, vygenerování souborů pomocí sqlmetal.exe a práce s tím spojené zabrali přibližně 30 minut. Ani zde, obdobně jako v předchozím kroku se nedají očekávat nějaká větší časová zdržení.

Publikováno pod: .net technology , výzva
30
IX

Výzva - napojení na XML-RPC wordpressu

Pro toho, kdo si píše svůj blog a používá k tomu některý z offline klientů, jako třeba Windows Live Writer tomu nemůže být cizí, že každý rozumný publikační systém má svoje API rozhraní.

Publikační API rozhraní

Většina API rozhraní, která se v současné době používají u publikačních systémů je založena na XML-RPC volání. Těchto API je definováno hned několik a není výjimkou, že se i vzájemně doplňují. Mezi ty známější tak patří:

  • blogger API
  • MovableType API
  • MetaWeblog API
  • a samozřejmě, své API má i WordPress, který rozšiřuje možnosti MetaWeblog API o definici svých metod

XML-RPC v .net

.net framework neobsahuje ve svých assembly třídu, která by umožňovala volání pomocí specifikace XML-RPC. To ovšem nevadí v případě, že znáte knihovnu XML-RPC.net. Tato knihovna umožňuje velice elegantně a rychle vytvořit nejen klienta, ale také server pro vzdálená volání.

V mém případě bylo plně dostačující vytvoření klienta služby a napojení se na vytvořený účet. A že vytvoření klienta je velice jednoduché může demonstrovat následující postup.

Zároveň se stažením knihovny získáváte i zdrojové kódy a to nejen pro samotnou assembly, ale také s definovanými interface pro výše zmíněné publikační API a to i s definicí struktur parametrů.

Po nareferencování knihovny CookComputing.XmlRpcV2.dll jsem tak do projektu přidal i definici interface pro MetaWeblog API a rozšíril jsem jej o implementaci interface IXmlRpcProxy, tak abych mohl vytvořit proxy klienta. Jelikož jsem však potřeboval ještě vytvářet nové kategorie, bylo potřebné doplnit definici metody pro vytvoření nové kategorie. Na stránkách WordPressu jsem v dokumentaci pro vývojáře zjistil, jaký předpis má takové volání a doplnil strukturu a interface metody.

[XmlRpcMethod("wp.newCategory", Description = "Create a new category.")]
object newCategory(string blogid, string username, string password, Category category);
public struct Category
{
  public string name;
  public string slug;
  public int parent_id;
  public string description;
}

Poté již stačí jen vytvořit instanci proxy třídy, a nastavit ji správně Url adresu na servisní stranu publikačního systému. Tím jsme hotovy a můžeme volat vzdálené metody a publikovat tak naše produkty, v mém případě knihy.

IMetaWeblog proxy = XmlRpcProxyGen.Create<IMetaWeblog>();
proxy.Url = URL;
// zde již následuje volání metod nad proxy

Jak by to probíhalo

Tento krok je plně v mé režii. Co vás případně může zaskočit a co je dobré vědět, že jednotlivá volání je možné trasovat. Což pomohlo i mě, kdy definice pro kategorie nebyla přesná a bylo ji třeba upravit dle skutečného stavu, který posílal nainstalovaný WordPress. Jak zajistit možnost odladit jednotlivá volání:

RequestResponseLogger logger = new RequestResponseLogger();
logger.Attach(proxy);

Poté bude již veškerá komunikace logována do samostatných souborů.

Časový odhad

V případě že víte, kam "sáhnout" a nemusíte znovu vynalézat kolo, potom je zprovoznění XML-RPC volání velice jednoduché a rychlé. Mě proklikání se k dokumentaci WordPressu pro jeho rozšířené API, dodefinování metody a odladění volání zabralo asi 35 minut.

Publikováno pod: .net technology , výzva
25
IX

Výzva - publikační systém WordPress

Nyní se přesunu z prostředí .net frameworku někam hodně daleko, do míst, která jsem ještě před několika málo týdny téměř vůbec neznal a které je třeba alespoň částečně prozkoumat.

Je to systém WordPress, který byl zmíněn, že je vhodným kandidátem na prezentaci dat o produktech, v mém případě i knih.

Hosting WordPressu

Jelikož jsem v tomto odvětví nováček a hosting, který mám je určen pro .net aplikace, jal jsem se hledat způsob, jak rozchodit systém WordPress, abych na něm mohl otestovat možnosti publikace informací získaných v předchozích krocích. Je příjemné, že přímo na stránkách, kde je možné stáhnout si zdrojové kódy pro tento publikační systém je i odkaz na možnost hostovat své příspěvky na již funkčním řešení. Proto jsem neváhal a zřídil jsem si účet.

V tuto chvíli se musím omluvit všem, kteří čekali odkaz, avšak nebudu jej zatím zveřejňovat, ten kdo má zájem jistě stránky dokáže najít, pro ostatní potom nezbyde, než dočíst tento seriál a odkaz najít v průběhu čtení.

Prostor s publikačním systémem tedy mám, je nakonfigurován a já jsem zkusil vytvořit jednu stránku a jeden příspěvek, abych zjistil jak se zobrazují a co vše je třeba nastavit.

Tady jsem si také definoval, že vhodné bude používat kategorie pro příspěvky a do nich řadit jednotlivé knihy, za kategorii jsem si potom vybral vydavatele dané knihy. Samozřejmě ono členění může být různé a dle možností by se mohl specifikovat třeba autor a vydavatel, případně zvolit jiná kriteria, která je možné získat ze vstupního xml souboru.

Musím říct, že ovládání a administrace WordPressu mě velice mile překvapila a v případě, že bych měl k dispozici pouze PHP hosting s podporou MySQL databáze, byl by mojí volbou pro publikační činnost.

Nakonec jsem si ještě pohrál s tím, abych si vybral nějakou pěknou šablonu a přidal několik widgetů do postraní lišty.

Jak by to vypadalo

Tady si myslím, že při spolupráci s Petrou bych se nechal spíše vést, protože věřím, že má více zkušeností s provozem tohoto publikačního systému. Předpokládám též, že by bylo nutné dořešit provázání jednotlivých produktů mezi sebou a vytvoření stromu první úrovně pro následné kategorie.

Časový odhad

Mě hledání a zkoumání WordPress publikačního systému zabralo necelou hodinku času.

Publikováno pod: .net technology , výzva
23
IX

Výzva - doménové objekty a jejich naplnění

Pokračování výzvy z webtrhu pokračuje, tentokráte povídáním o tom, jak jsem si vytvořil doménové objekty pro uchování dat a provedl jejich naplnění.

Doménové objekty

V příspěvku věnovaném definici zdroje dat jsem končil v okamžiku, kdy jsem byl schopen pomocí REST volání získat xml zdroj dat. Z následné diskuze na webtrhu vyplynulo, že Petra zrovna neholduje XSL šablonám a přesto by byla ráda, pokud by si mohla v případě potřeby upravit výsledné HTML, které bude publikovat na web. O tom, jak jsem se tohoto problému zhostil v jednom z příštích článků. Co jsem však potřeboval, bylo mít naplněné objekty, které budou sloužit pro držení dat.

Ze vstupního xml souboru jsem si tak definoval několik elementů, které stojí za to mít uchované, a které se budou moci následně zobrazovat a publikovat na webu. Obdobně bych postupoval i se vstupním xml souborem produktů, zde jsem se tedy zaměřil na knihy. Mnou vytvořené třídy tedy představovaly primitivní POCO (Plain Old CLR Object) objekty s definicí vlastností, které odpovídaly dostupným elementům.

  • Book - ASIN, ISBN, NumberOfPages, PublicationDate, Publisher, Title, Authors, Reviews
  • Author - FullName
  • Review - Source, Content

Linq to Xml

Poté, co jsem měl nadefinovány tyto jednoduché objekty bylo je třeba vytvořit a naplnit daty. K tomu jsem s úspěchem použil nových objektů, které nabízí verze .net frameworku 3.5. A to konkrétně objektů XElement ve spojení s LINQ to XML.

Stažení dat tak bylo otázkou jednoho jediného řádku:

XElement x = XElement.Load(url);

kde proměnná url představovala doplněnou adresu o proměnné parametry, které jsem představil v minulém článku.

Pokud si nyní říkáte, jak složité je naplnit POCO objekty vstupnímy daty a získat tak seznam dostupných knih poskytovaných webovou službou amazonu, je to přesně 23 řádků kódu, z čehož je ještě několik řádků věci vizuálního formátování.

A zde je celé kouzlo, kterým se provede instancování objektů a jejich naplnění

var result = from book in x.Descendants(ns + "Item")
  let attrs = book.Element(ns + "ItemAttributes")
  let revs = book.Element(ns + "EditorialReviews")
  select new Book()
  {
    ASIN = (string)book.Element(ns + "ASIN"),
    ISBN = attrs.Element(ns + "ISBN") != null ? (string)attrs.Element(ns + "ISBN") : string.Empty,
    NumberOfPages = (int?)attrs.Element(ns + "NumberOfPages") ?? 0,
    PublicationDate = (DateTime)attrs.Element(ns + "PublicationDate"),
    Publisher = (string)attrs.Element(ns + "Publisher"),
    Title = (string)attrs.Element(ns + "Title"),
    Authors = new List<Author>(from a in attrs.Elements(ns + "Author")
      select new Author()
      {
        FullName = (string)a
      }),
    Reviews = revs == null ? new List<Review>() : new List<Review>(from r in revs.Descendants(ns + "EditorialReview")
      select new Review()
      {
        Content = (string)r.Element(ns + "Content"),
        Source = (string)r.Element(ns + "Source")
      })
};

Přítelem je let

Teď to možná zní velice divně, ale pokud se blíže podíváte na zdrojový kód uvedený výše zjistíte, že jsem použil magické slůvko let, kterým jsem si vložil do dotazu další proměnné, které používám. První proměnná attrs je pouze pro usnadnění práce, u druhé to také tak může vypadat, ale má to i hlubší význam. Jak se můžete u některých knih přesvědčit, ne všechny obsahují recenzi. Pokud bych poté chtěl naplnit vlastnost Reviews přímo a to odkazem na element EditorialReviews obdržel bych výjimku, konkrétně NullReferenceException, a to se mi zrovna nehodí. Proto jsem si odkaz na tento element uschoval do proměnné a v okamžiku potřeby přirazení do vlastnosti Reviews jej kontroluji a případně vytvořím pouze prázdný generický List<T>.

Scházející elementy

Do obdobné situace jsem se potom dostal v případě, že jsem se snažil naplnit vlastnosti, avšak ve zdrojovém xml scházel požadovaný element. Příkladem budiž třeba scházející ISBN kód nebo nevyplněný počet stránek knihy. V případě ISBN jsem toto vyřešil pomocí ternárního operátoru, v případě počtu stránek jsem potom opět využil možností přetypovat výsledek na nullable type typu int a pomocí operátoru ?? případně vrátit hodnotu 0.

Jak by to vypadalo

Tento krok by se nejspíše odehrál společně s krokem prvním a to při definici zdroje dat. Určili bychom si, které atributy ze vstupního souboru nás budou zajímat, jakým způsobem jsou tyto atributy provázány, stejně tak si řekli, které atributy jsou povinné a které volitelné. Pokud by k vstupnímu xml souboru bylo definováno xsd schéma bylo by to jistě jednodušší.

Časový odhad

Definice doménových objektů a jejich naplnění byl již poměrně rychlý krok. Co bylo spíše nepříjemné je definování vlastností, v čemž jsem s radostí uvítal automatické property. Dalším krokem pak bylo poskládání LINQ dotazu na zdrojové xml. Celkový čas byl odhadem 25 minut + 10 minut testování na vzorku několika stovek záznamů. V případě produktů, které chtěla Petra sledovat by byl čas závislý na tom, kolik atributů by bylo nutné sledovat a mít k nim uložená data.

Publikováno pod: .net technology , výzva
18
IX

Výzva - definice zdroje dat

Jednou z těch obtížnějších překážek na cestě k aplikaci, která ve výsledku vybuduje web z xml exportu bylo najít vhodný zdroj dat.

Jak jsem již v úvodním příspěvku naznačil, Petra se se mnou nespojila a tak její xml export, ze kterého se měl web vytvořit jsem neměl k dispozici. Co bylo řečeno, že dané xml bude obsahovat přibližně 500 produktů s atributy.

AWSE

Když jsem tedy přemýšlel nad tím, jaký zdroj dat použít, vzpoměl jsem si na ukázkový příklad tangerine od Infragistics. Ten pracoval nad veřejnou částí služeb poskytovaných Amazon.com, konkrétně nad AWSE. Po bližším prozkoumání se dá zjistit, že je možné vytvořit si v .net webovou referenci s použitím wsdl a vytvořit si tak proxy na tuto službu.

Úkolem však nebylo takto jednoduše přistupovat k datům, v daném požadavku přeci bylo, že je třeba vytvořit web z xml exportu. A tak jsem našel odkaz na dokumentaci a z ní zjistil, že je možné k webové službě přistupovat i pomocí RESTu (Representational State Transfer) a získat tak výstup v xml.

Poté již stačilo vhodně nakombinovat parametry a vytvořit volání pro získání potřebných zdrojových dat.

Výsledná URL, pomocí níž tedy získávám data o knihách je následující

http://ecs.amazonaws.com/onca/xml?Service=AWSECommerceService&AWSAccessKeyId={0}&Operation=ItemSearch&Version=2007-07-16&ResponseGroup=Medium&SearchIndex=Books&Keywords={1}&ItemPage={2}

Prvním parametrem, který doplňuji za běhu aplikace je tak AWSAccessKeyId, které je uloženo v konfiguračním souboru aplikace. Tento klíč je přidělen každému, kdo se zaregistruje na stránkách amazon.com pro využívání jejich služeb.

Dále je možné si všimnout, že volám operaci ItemSearch a požaduji zaslání středního výpisu všech dat, což je pro můj vzorový případ dostačující. Dále je uvedeno, jak jsem se již zmínil, že chci získat pouze knihy a to s mnou definovaným klíčovým slovem, což jsem zvolil jako parametr závislý na uživatelově volbě. Posledním parametrem je potom hodnota ItemPage, která získá i další stránky výsledků.

Výhodou tohoto zdroje dat je, že je poměrně obsáhlý, velice dobře zdokumentovaný a přístupný téměř všem, kteří mají touhu projít si se mnou touto výzvou.

Jak by to vypadalo

Zde by se slušelo upozornit, že takto jednoduché by to nejspíše s Petrou nebylo. A i při získání takové zakázky by právě definice dat byla jednou z těch obtížnějších překážek. Právě tento krok by hodně určoval, jak dlouhou dobu bude tento projekt trvat. Také se zde může nejvíce projevit rozdíl mezi začátečníkem, nebo ne příliš zkušeným analytikem.

Časový odhad

Dohledání zdroje dat, nastudování dokumentace a prostudování výstupních xml souborů trvalo přibližně 90 minut. Myslím si, že sezení se zákazníkem typu Petra, který ví co chce a očekává za výsledek, by nemělo zabrat u obdobného projektu více jak 120 minut. Samozřejmě zde hodně záleží na složitosti vstupního xml souboru.

Publikováno pod: .net technology , výzva