neděle 25. května 2014

Prodloužený víkend v Německu - zábava pro kluky

Tenhle výlet jsme několikrát odkládali, než se nám ho konečně podařilo uskutečnit. Původně byl plánován na čtyři dny začátkem května, konkrétně na 8 až 11.května 2014, ale díky předchozí akci na Baťově kanále  jsme byli trochu nemocní a ani počasí nevypadalo dobře. Takže se nakonec jelo o týden později a místo čtyř dnů jen na tři - na naši  „klučičí“ cestu jsme vyrazili ve čtvrtek večer a mimo obou našich kluků jsme brali i jednoho jejich kamaráda. 

Cílem byla návštěva Heide parku a malý okruh severním Německem, kde jsme chtěli využít slevové Merlin karty a kromě Heide parku se podívat i do Oberhausenu, kde jsou hned tři Merlin atrakce a do Hamburku, kde mimo domu hrůzy čekaly i vláčky.

Navíc se mi podařilo sehnat poměrné levné ubytování v řetězci  Holiday Inn Express - za cenu mezi 50-60 eur na noc pro čtyři lidi jsme dostali navíc i připojení k internetu, parkování zdarma a snídani formou švédského stolu. Za tu cenu naprostá paráda.

Na krátké zastávce v Ústí nad Labem jsme povečeřeli McBox v McDonalds ve středu města, pokochali se pěkným výhledem na Větruši a takto posilněni přejeli německé hranice a dojeli až k Halle, kde jsme strávili první noc v hotelu Ibis Budget.



 Ráno jsme po snídani vyjeli směr Soltau a Heide park, kam jsme podle plánu dorazili po otevření krátce po desáté hodině - po cestě nás zdrželo jen mé špatné zařazení se do pruhu na dálnici v rekonstrukci poblíž Hannoveru, takže jsme si trochu zajeli. 



Celý den jsme si užívali všech atrakcí - největším důvodem, proč jet do Heide Parku (kromě hezkého prostředí), je Colossos, nejvyšší dřevěná horská dráha v Evropě, dále Desert Race, zatím jediná německá vystřelovačka a také Scream, volný pád z výšky 71 metrů. Kromě dalších horských drah (Kraken, Let démonů, Limit, Big Loop) disponuje Heide Park také vším ostatním, co je v podobných parcích obvyklé, takže zde najdeme hned několik vodních drah, různá show, část pro děti a také klidnější a spíše relaxační záležitosti, jako třeba různé projížďky atd.


Nám se nejvíce líbily vodní atrakce - skluzavka na vodní dráze, projížďka na nafukovacím kole, vodní bitva apod. Prostřední člen výpravy si dokonce vyzkoušel i Desert Race - vystřelovací horskou dráhu, kde za 2.4 sekundy dosáhne vozík rychlosti 100 km/h s přetížením 5G (moc tomu nevěřím, je to spíše asi marketingový tahák).

Jednoznačně nejoblíbenější dráhou pak byla švýcarská bobová dráha, ale vyzkoušeli jsme i ostatní - třeba Big Loop. Užili jsme si i na ostatních atrakcích  a  to včetně těch určených pro ty nejmenší - projížďka autem Oldtimer je jedna z nejstarších v parku a je zde od jeho otevření na konci sedmdesatých let.



 Po zavření parku v 17:00 jsme jen přejeli několik desítek kilometrů do Velké zahrady v Hannoveru.  Tato zahrada v barokním stylu patří údajně k nejkrásnějším v Evropě. Řada fontán, jezírek i upravených záhonů lákala k proběhnutí a prozkoumání.—strávili jsme zde téměř dvě hodiny. Část zahrady ale byla uzavřena, protože hned následující večer se zde měla konat velká přehlídka ohňostrojů zahajována skupinou z České republiky.



 Na večer jsme pak dojeli k hotelu Express Holiday Inn, po cestě jsme si dali i německý Hot Dog v  obchodním domě Ikea a v sobotu ráno nás pak čekal zábavní komplex v Oberhausenu - Adventure Park, Legoland Discovery Center a Sea Life.


CentrO (velké O na konci není překlep) je  jeden z největších  nákupních a zábavních  komplexů v Evropě. Vzniklo na místě  bývalé ocelárny Thyssen. Mimo Legoland Discovery Center, SeaLife a Adventure Parku je zde kino, multifunkční sportovní aréna a spousta obchodů. Adventure park by však potřeboval trochu obnovit - novotou zářila jen vodní skluzavka s tučňáky, zato na druhém konci parku byly atrakce jako vláček a skluzavková věž zavřeny a celý park byl tak spíše zklamáním. 



Věděl jsem dopředu, že to není klasický zábavní park, spíše jen klasický zahradní park s atrakcemi, ale takový stav nestav jsem vážně nečekal a ani jsem se moc nedivil, že park byl prakticky prázdný. Ani zahradní úprava nebyla nijak zvláštní. My měli vstup v ceně Merlin karty. 

Nefunkční Adventure park ale vynahradila návštěva dalších dvou atrakcí - Sea Life s rybičkami a hlavně Legoland Discovery Center. To se ke konci pěkně vyprázdnilo a dalo by se říci, že počet zaměstnanců začal převyšovat počet návštěvníků. A tak jsme se pustili do stavby věže—tedy vlastně Jeník stavěl svoji a my ostatní  také svoji. Podařilo se nám ji dostavět pěkně do vysoka a dokonce vydržela i simulované zemětřesení.



Na žádost zaměstnanců jsme ji před odchodem bohužel museli rozebrat—což tedy šlo rychleji než její stavění—škoda, převyšovala  všechny ostatní ukázkové budovy, co tam byly.
V obchodě jsme si pak koupili oblíbené Lego figurky a odcházeli jsme jako poslední návštěvníci—zamykali za námi dveře..



Naše cesta pak vedla směrem na Hamburg, cílem ale byl hotel Express Holiday Inn v Brémách. Před tím jsme ale povečeřeli vydatné menu v Burger Kingu. Jen škoda, že jsem si zvolili klasickou restauraci, tedy na parkovišti mimo dálnici. Mohli jsme si jídlo dát v restauraci přímo přes dálnici - takových moc není. Takže když jsme dojedli a vyrazili směr Brémy, tak hned po několika kilometrech byla další BK restaurace a to ve formě mostu přes dálnici. Škoda, už jen pro ten zážitek by to bylo určitě chutnější občerstvení. Třeba příště....je to tady.


Poslední den, neděli, jsme pak věnovali Hamburgu  - projeli jsme se metrem, vlakem i lodí (vše je v ceně velmi levné rodinné jízdenky na městskou dopravu), navštívili pár místních atrakcí . přístavní čtvť a  dům hrůzy - jsou zde podány dějiny města doplněné projížďkou po vodní dráze a sešupem po padací věži ve tmě. Ke vstupu nám opět posloužila Merlin karta.



A pak následovala hlavní atrakce - Miniatur Wunderland - největší modelová železnice na světě.  Pro železnici byly vybrány prostory v bývalém skladišti v městské části Speicherstadt (stará cihlová skladiště v přístavu, nyní kanceláře a zábavní areály), kde výstavní areál zabírá v bloku domů celé jedno patro. Začátkem Miniatur Wunderlandu byl rok 2001 a od té  doby se na celém modelu odpracovalo prý přes 70.000 hodin práce. Rozměry jsou vskutku impozantní, rozloha železnice přes 500 metrů čtverečních!, 6 km kolejí, přes 450 vlaků a více než 5000 vagónů! K osvětlení modelu bylo použito přes 20.000 světel, reálnou atmosféru dotváří přes 30.000 figurek lidí, 50.000 stromů a 3.000 budov (opsáno z průvodce, nepočítali jsme to - to bychom tam byli asi doteď). 


Krajina je velice povedená, vše se hýbe, někde dokonce jezdí i autíčka a létají letadla. Takže mimo vlaků jezdili po silnicích i  osobní auta a kamiony, hasiči hasili požár,  v lyžařském centru jezdila kabinová  i sedačková lanovka s lyžaři a tak. 



Na letišti bylo rušno a každou chvíli přistává čí vzlétává letadlo.  Navíc  se pravidelně střídá den a noc - večer se rozsvítí všechny domy, pouliční lampy, dokonce i autíčka, "ráno" vše zase zhasne. Prostě je se na co dívat.

Ještě jsme stihli návštěvu ruské ponorky a podívat se na tunel pod Labem, u kterého klasický vjezd nahrayují výtahy - i pro auta.




Pozdě odpoledne se vydali na cestu zpět domů do Brna s krátkou zastávkou u McDonalds na dálnici u Litoměřic.


úterý 8. dubna 2014

Jak si vyhledat ubytování

Tady je seznam míst na internetu, kde lze vyhledat ubytování pro cesty:

klasika pro ubytování, ale v poslední době se mi zdá, že nabídky nejsou často tak výhodné a na místě si lze domluvit lepší cenu. Ne vždy, ne všude. Dobré bývají nabídky na poslední volné pokoje.

(hlavně mobilní verze nabízí více možností pro hledání)


Nabízí "lepší" hotely, například z řetězce Holiday Inn Express. Mimo sezónu nabízejí zajímavé slevy na ubytování v rozmezí 40-80€ za čtyřlůžkový pokoj a to včetně snídaně. Express je umístěn především v blízkosti letišť a jiných dopravních uzlů, většinou se snadným napojením na střed města hromadnou dopravou. Parkování bývá zpoplatněno, ale jak je mi záhadou - v některých hotelech, i přes inzerovanou cenu, nic nechtěli s tím, že to mají proto, aby odradili od parkování lidi z okolních kancelářských budov. Jinde zase nabídli několik alternativ, od pár eur k cca patnácti eurům. Na webu byla uvedena vždy ta nejvyšší možná cena.

http://ibisbudgethotel.ibis.com/gb/home/index.shtml
(některá místa mají i s dobrou lokalitu - ale většinou spíše na okraji měst a u dálnic - provoz 24h - jsou to o třídu lepší než F1). Pokoje mají jen se základním vybavením, ale to je většinou nové a nepotřebované. Sociální zařízení je na každém pokoji. Najdou se negativní výjimky, ale není jich moc (moje statistika: 5 zařízení, 3 působící perfektním dojmem, jedno trochu horším a jedno trochu podprůměrné). Lze to shrnout tak, že pokud je ve městě cca 40 hotelů, bude se hodnocení F1 pohybovat někde mezi 35-40 místem, Ibid budget někde mezi 15-25 místem.


http://www.hotelf1.com/gb/home/index.shtml
Použitelné hlavně ve Francii. Hotely F1 nejsou obecně velmi kvalitní - mají sdílené sociální zařízení ve formě jakýchsi kóji a na vybavení je znát určitá opotřebovanost. Najdou se světlé vyjímky, ale obecně je to velmi základní forma ubytování (moje statistika: z pěti zařízení jedno slušné, tři nic moc a páté “už nikdy více”).


http://www.hotelbb.de/en/portal/index.html
Obvyklá cena za osobu a noc: 17-30 (4 lůžkový pokoj)Síť hotelu B&B nabízí obvykle ubytování blízko středu měst (ale ne přímo v centru) a slušný standard v ceně 60-120€ za čtyřlůžkový pokoj. Ale zařízení se dost liší, někde se přibližuje standardu Holiday/Express in, někde se zase naopak jedná o lepší Ibis Budget. V ceně není snídaně.

https://www.google.com/hotels/
vyhledavá v databázi Google, ale někdy stačí i mrknout do google map a obklikat si jejich možnosti ubytovani

pondělí 3. února 2014

Vylepšení střešního boxu Hakr MagicLine

U střešního boxu Hakr MagicLine 450 mi vadilo, že po vložení předmětů jsem musel vždy kdesi zezadu vydolovávat pásek ke stažení nákladu. Nakonec jsem to vyřešil takto:

V Lídlu jsem koupil sadu suchých zipů:


Na stahovací pásek jsem na část, směřující k sponě, přilepil jednu část suchého zipu, tu měkkou (navíc je dobré uchycení prošít černou nití, přece jen ta lepící páska nedrží na jiné umělohmotné textilií spolehlivě a po čase by se mohla uvolnit):

Na víko jsem pak nalepil několik kousků protikusu, každá o délce cca 5 cm.

Nyní lze mít stahovací pásek při nakládání pěkně dostupný po celou dobu a po naložení nákladu stačí jen odepnout ze zipu a je to - už žádné hledání.


Poznámka 1: na obrázku můžete vidět malé schůdky  - velmi praktické zejména pokud máte vyšší auto, lze z nich v pohodě dosáhnout na náklad v boxu:
Poznámka 2: střešní box je poměrně široký a při naložení trpěl tím, že přední část nebyla pořádně překryta - na obrázku je vidět, jak ještě na kraji boxu vrchní část překrývá spodní, ale vepředu uprostřed naopak spodní část mírně vystupuje z bílé překryvné - v praxi pak při jízdě touto mezerou pronikaly  nečistoty a voda.


Výrobce při reklamací vyztužil spodní víko profily, ale to moc nepomohlo. Nakonec jsem si udělal ze zbytku elektrikářské lišty malé plastové elko a nalepil pružným lepidlem ke spodní hraně  vrchní části :

Po zavření se tak přední vrchní část "zahákne" za spodní a tak jsou oba díly správně překryté - při otevírání stačí víko rukou jen trochu "vyklonit" a háček se uvolní.

neděle 8. ledna 2012

A opět do oblak …

Minulý rok v září uspořádal Microsoft konferenci BuildWindows. Zde mimo jiné zazněla i myšlenka, že budoucí vývoj pro Windows bude probíhat v HTML a javascriptu. Následovaly úvahy o budoucnosti .NETu, C#, jak budou aplikace vypadat apod. V tomto příspěvku nehodlám tyto úvahy rozvíjet – spíše ukážu, jak napsat aplikaci v HTML. I ta bude ale závislá na C# – web stránky jsou realizováný pomocí MVC technologie a celý backend generování kartiček je napsán v C#. Klientská část naproti tomu spoléhá zcela na javascript a vzhled stránkua je řešen pomocí CSS – samotná stránka tak obsahuje téměř čisté HTML.
Před pár týdny jsem zde popsal řešení pro tisk kartiček – nejprve jsem se věnoval tomu, jak generovat vlastní PDF dokumentu, v druhém pokračování pak přesunu tohoto generování do cloudu. Oba díly naleznete zde:
V tomto příspěvku popíši, jak vytvářet vlastní kartičky. Pomocí formuláře v prohlížeči se zadají jednotlivé hodnoty a ty se posléze odešlou na server a zpět dostanete PDF dokument. Podobných stránek jsou ale na webu mraky, takže zkusím odlišit se trochu funkčností – vytváření kartiček bude fungovat tak, že jen zadáte slovíčko a vyhledají se jak jeho překlad do češtiny, tak i přepis jeho výslovnosti a příklad použití. Tyto vyhledané údaje si budete moci upravit. Navíc se kartičky budou lokálně ukládat ve vašem prohlížeči, práci tedy budete moci kdykoliv přerušit  a opět v ní začít bez výslovného ukládání.

Jak získat údaje o slovíčku

Na webu je plno on line slovníků – já si vybral dva, WordReference EnCz Slovník a Oxford Advanced Learner’s Dictionary.  Pro jejich využíti je ale potřeba vyřešit tyto problémy:
  • jak je volat a předat jím slovo, které hledáme
  • jak je volat v rámci naší stránky – tedy cross-domain problém
  • jak vyhledat potřebné údaje v tom, co nám stránky vratí
                                          image    image

Volání

To je ta nejjednodušší část, v případě stránek Oxford slovníku stačí volat adresu  http://oald8.oxfordlearnersdictionaries.com/dictionary/ + dané slovo, v případě WordReference pak http://www.wordreference.com/encz/  + dané slovo;

Řešení Cross-domain omezení

Z jedné stránky není možné volat a získat obsah z jiné domény. Částečně je to řešeno tím, že lze volat a použít skript z jiné domény a pokud tedy dotyčný web umí vracet JSON data, není potřeba nic vymýšlet a lze použít přímo metod knihovny jQuery a Ajax volání. Nicméně  v našem případě žádná z vybraných stránek toto nepodporuje. Naštěstí i zde existuje řešení a to služba YQL společnosti Yahoo a knihovna jquery.xdomainajax.js.
YQL je vlastně web služba, která získá obsah stránky, upraví jej tak, aby jej bylo možné zaslat jako skript (rozuměj ve formátu Json) a tak jej pošle volajícímu:
image
Knihovna xdomainajax pak jen volání YQL obaluje tak, aby s ním bylo možné pracovat tak, jako s ajax voláním, takže skript, který slovník volá, vypadá stejně, jako pro normální ajax volání:
image

Vyhledání údajů

To je opět snadná část, využívám možností jQuery selektorů a vyhledám příslušné informace – vyhledávání pro oba zvolené slovníky lze najít v souboru search.js

Ukládání v prohlížeči

Zde si opět usnadním práci pomocí existující knihovny jStorage. Každou vytvořenou kartičku ukládám lokálně v prohlížeči.  Pro zobrazení je pak využíván formulář, který se případně, v případě že má uživatel zájem o PDF kartičky, odesílá na server. Využívá se zde tzv. nesouvislých indexů, které jsem popsal v příspěvku  ASP.NET MVC3–Binding příklad.

Možnosti exportu

Uživateli jsou nabízeny dvě možnosti, jak data dostat z prohlížeče “ven”. Buď si může data vyexportovat jako csv soubor a nebo je odeslat na server a získat PDF dokument. Řešení popsané v příspěvku Vzhůru do oblak bylo ještě rozšířeno o možnost přijímat data z formuláře.

Postup práce s aplikací

Prosím mějte na paměti, že aplikace je jen příklad, není to žádné mistrovské dílo a má spíše jen demonstrovat, že lze vyvinout v HTML aplikaci s komfortem desktopové aplikace. Základní rozložení je velmi jednoduché, aplikace má tři hlavní části – v horní se zadává hledané slovíčko, prostřední slouží pro náhled a editaci kartičky a dole je seznam kartiček:

image

Do horního políčka napíšete slovo, pro které chcete vytvořit kartičku a stisknete Enter – ikonky slovníků se změní na dobu, kdy se slovo vyhledává a signalizují tak probíhající činnost:
image
Jakmile jsou údaje nalezeny, vyplní se kartičky nalezenými údaji:
image
Je možné na kterýkoliv údaj kliknout a změnit jej:
image
Jakmile jste s kartičkou spokojeni, klikněte na tlačítko Ulož a slovíčko se objeví v seznamu:
image
  • Kliknutím na kterékoliv slovíčko v seznamu se kartička vyplní jeho údaji a je možné kartičku aktualizovat či odstranit.
  • Práci můžete kdykoliv přerušit a prohlížeč zavřít – všechna data jsou uložena automaticky a při opětovném zavolání stránky se tato obnoví i se seznamem.
  • Výsledky své práce můžete uložit jak ve formátu CSV, tak si i nechat zaslat slovíčka v PDF dokumentu jako kartičky.

Další zajímavosti a popis řešení

Pro správu skriptů a css soubory je použita knihovna Cassette, kterou jsem ve stručnosti popsal v příspěvku ASP.NET– kazeta stále žije…...
Každá část obrazovky má svůj vlastní css styl:
  • inputBox.css – styly pro vrchní vyhledávací box
  • card.css – styly pro kartičky
  • cards.css – styly pro seznam kartiček
  • basicLayout.css – styly pro obecný vzhled stránky, tj. umístnění hlavičky, patičky apod.
  • site.css – styl dodaný MS
Všimněte si, že dva poslední styly nejsou přímo odkazovány ani ve view, ano v layoutu – je na ne odkaz v prvních třech souborech:
image
Funkčnost na straně klienta je také rozdělena do několika javascriptů:
  • buttonEvents.js – co se provede po kliku na tlačítka a také co se má provést po načtení stránky a vytvoření nové kartičky v seznamu (createEntry)
  • flashcard.js – je zde metoda pro export do csv (exportData),  testování, zda podobná kartička již neexistuje (isCardAlreadyStored) , vypsání seznamu uložených kartiček (listCard), vyplnění kartičky (fillCard) a také seznam operací, které se provedou, pokud vyhledáváte nové slovíčko (submitEdit)
  • search.js – dvě metody pro vyhledávání ve zvolených slovnících, pro každý slovník jedna
Jak pro skripty, tak i pro styly je použit bundle.txt soubor, který upřesňuje řazení skriptu a stylů.
Mimo tito skripty jsou použity tyto knihovny:
  • jQuery – netřeba představovat
  • jQuery.editable.js – umožňuje editaci na stránce po kliknutí, použití je velmi jednoduché,
  • jQuery.xdomainajax.js – umožňuje snadné použíti YQL, volá se jako bežné Ajax volání
  • jStorage.js – sjednocuje práci s lokálním uložištěm (HTML 5)
Aplikace funguje správně jen v posledních verzích prohlížečů Chrome, Opera, Firefox a asi i v IE (zde nefunguje export do csv). Cílem nebylo ani tak nabídnout naprostou funkčnost, spíše ukázat, jak udělat funkční aplikaci čistě v prohlížeči – i serverová podpora je omezena na generování PDF dokumentů, které nelze z asi pochopitelných důvodů generovat v prohlížeči (a nebo o tom zatím nevím).

Zdrojový kód

Aplikace běží na adrese http://flashcard.apphb.com/ a zdrojové kódy jsou k prohlédnutí na CodePlex. Komentáře v kódu moc nejsou, snažil jsem se vše popsat v tomto článku.

sobota 7. ledna 2012

ASP.NET– kazeta stále žije…..

Nadpis je asi trochu matoucí  a  snad na vysvětlenou pro ty mladší  by bylo dobré zmínit, že kdysi dávno se hudba nekopírovala pomocí mp3, ale existovaly analogové kazety. Kopírování bylo zdlouhavé a s každou kopií klesala kvalita. Názvem tohoto média se inspiroval autor zajímavé knihovny(nepátral jsem proč a doufám, že to neznamená, že kvalita knihovny bude s každou verzí klesat).
Knihovnu  naleznete na stránkách http://getcassette.net/.  Může vám pomoci při vývoji WebForms a nebo MVC webů (já ji použil pro zatím jeden malý projekt v MVC).
Řeší problém se správou skriptů a stylů –pro snazší údržbu a vývoj je vhodné mít styly uložené ve více css souborech, podobně i skripty. Jenže čím více toho musí prohlížeč pro zobrazení stránek stáhnout, tím je celková odezva stránek pomalejší a zátěž serveru a využití internetového spojení vyšší. A přesně tento problém Cassette řeší – při vývoji a ladění webu  zachovává malé soubory – můžete tedy snadno využívat klientských ladících nástrojů například ve Firefoxu, ostrá verze pak obsahuje soubory jak sloučené, tak minimalizované.
V případě MVC pak navíc nemusí stránky(views) obsahovat spousty tagů se skript soubory či linky na css. Stačí jen deklarovat, které soubory jsou pro dané View potřeba:
  1. @{
  2.     ViewBag.Title = "Index";
  3.  
  4.     Bundles.Reference("Scripts/Cards/export.js");
  5.     Bundles.Reference("Scripts/Cards/flashcard.js");
  6.     Bundles.Reference("Scripts/Cards/search.js");
  7.     Bundles.Reference("Content/inputBox.css");
  8.     Bundles.Reference("Content/card.css");
  9.     Bundles.Reference("Content/cards.css");
  10. }
  11. <div id="inputBox">
V MasterView souboru pak stačí na příslušných místech, kde mají byt tagy, zavolat:
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4.     <title>@ViewBag.Title</title>
  5.     @Bundles.RenderScripts()
  6.     @Bundles.RenderStylesheets()
  7. </head>
  8. <body>
  9.     <div class="wrapper">
Všimněte si tak=, že nemusíte přímo odkazovat na jQuery knihovnu – ve skriptech, které si vytvoříte se stačí na tuto knihovnu odkázat a bude tak zahrnuta do vašich skriptů:
image
(ten odkaz by jste tam dávali asi tak jako tak, díky tomu vám začne fungovat intelliSense nápověda pro JQuery metody).
Totéž platí i o stylech, i  v nich můžete napsat odkaz na “nadřízený” styl:
image
Nyní můžeme v případě, že svůj web ladíme, získat všechny soubory:
image
Celková velikost jen skriptů je přes 600kB:
image
Naopak jakmile vývoj dokončíme a web nasadíme, začne nám Cassette soubory slučovat a minimalizovat:
image
Například JavaScripty jsou nyní jen v jednom souboru, který má velikost téměř sedmkrát menší:

image
Na webu autora knihovny  a nebo fórech pak lze nalézt další tipy, třeba jak vypnout minimalizaci:

  1. bundles.Add<ScriptBundle>("Scripts", b => b.Processor = new ScriptPipeline().Remove<MinifyAssets>());

Další informace o této knihovně jsou k dispozici na webu knihovny, popřípadě na tomto blogu. Instalace je jednoduchá, základní použití je popsáno na webu autora.

pondělí 26. prosince 2011

ASP.NET MVC3–Binding příklad

V tomto příspěvku popíši, jak namapovat data pomocí “nesouvislých indexů” – ony se ty anglické výrazy špatně překládají, respektive nejsem jazykový odborník.

Problém

Představte si, že máte k dispozici seznam telefonních čísle a jmen a chcete je zobrazit uživateli, který pomocí zaškrtávátka určí, které z nich chce vložit do svého seznamu kontaktů. Běžně se tento problém řeší tak, že se uvažuje, že každý záznam má své ID (identifkátor).
Ale zkusme vyřešit situaci, kdy prostě žádné ID není k dipozici a nebo ho použít nechceme, tedy třída vypadá takto:
  1. public class Contact
  2. {
  3.     public string Name { get; set; }
  4.     public string Phone { get; set; }
  5. }
Zdroj dat nám nahradí tento kód:
  1. public static IEnumerable<Contact> Get()
  2. {
  3.     return new Contact[] {
  4.         new Contact() {Name= "Pepa", Phone= "123456789"},
  5.         new Contact() {Name= "Petr", Phone=  "987654321"},
  6.         new Contact() {Name= "Lopuch", Phone= "456789123"}
  7.     }.AsEnumerable();
  8. }
Kontroler není složitý:

  1. public class HomeController : Controller
  2. {
  3.     [HttpGet]
  4.     public ActionResult Index()
  5.     {
  6.         return View(Contact.Get());
  7.     }
  8. }
A View Index pak vypadá takto:
  1. @model IEnumerable<Contact>
  2. @{
  3.     ViewBag.Title = "Index";
  4. }
  5. <h2>Import - contacts</h2>
  6.  
  7. @using (Html.BeginForm())
  8. {
  9.     foreach (var contact in Model)
  10.     {
  11.     <input type="checkbox" name="index" value="@contact.GetHashCode()" /> @string.Format("{0}-{1}", contact.Name, contact.Phone) <br />
  12.     <input type="hidden" name="@string.Format("[{0}].Name", contact.GetHashCode())" value="@contact.Name" />
  13.     <input type="hidden" name="@string.Format("[{0}].Phone", contact.GetHashCode())" value="@contact.Phone" />
  14.     }
  15.     <input type="submit" value="send" />
  16. }

Metoda kontrolleru, který bude zpracovávat přijímaná data, pak vypadá takto:
  1. [HttpPost]
  2. public ActionResult Index(Contact[] contacts)
  3. {
  4.     return View("IndexPosted", contacts);
  5. }

a ve View IndexPosted vypisujeme přijaté kontakty pomocí jednoduchého kódu:
  1. <h2>Posted contects</h2>
  2. @foreach (var contact in Model)
  3. {
  4.      @string.Format("{0}-{1}", contact.Name, contact.Phone) <br />
  5. }
A takto se to chová:
imagea po odeslání stlačením tlačítka Send: image

Závěr

Veškeré kouzlo spočívá v checkboxu pojmenovaném index. Hodnota checkboxu je na server odeslána pouze v případě, že je zaškrtnut. MVC3 framework na serveru se pak snaží vytvořit kolekci objektů třídy  Contact (viz cílová akce formuláře Index(Contact[]  contacts)) – a hodnutu index použivá pro nalezení hodnot jednotlivých objektů.
Samozřejmě by se dal tento jednoduchý příklad řešit i jinak, ale všimněte si některých výhod tohoto řešení:
  • uživateli neposíláme žádné ID a Hashcode, který ho do jisté míry nahrazuje, je naprosto umělá hodnota.
  • Metodu pro zpracování dat do formuláře můžeme použít i pro zpracování normálního formuláře
  • díky tomu, ze využíváme model zpracování MVC frameworku, došlo by i k oveření všech podmínek, které bychom pro model případně definovali.
Celý zdrojový kód projektu BindingExample je dostupný na CodePlex – ale prakticky vše je uvedeno v tomto článku.

Poznámka na konec – index se nemusí jmenovat jen index, ale můžeme používat i prefixů při řešení složitějších případů:

  1. @Html.CheckBox("phones.index", new { value = contact.GetHashCode() })
  2.     @Html.Hidden(string.Format("phones[{0}].Name", contact.GetHashCode()), contact.Name)

neděle 18. prosince 2011

Vzhůru do oblak!…..a stejně skončíme v přístavu

Minulý příspěvek popisoval jednoduchou konzolovou aplikaci, která z údajů ze sešitu programu Excel udělá PDF dokument s kartičkami. Takový dokument pak stačilo jen vytisknout, rozstříhat či rozřezat a papírové kartičky byly hotové.
Tento příspěvek popíše, jak tuto aplikaci upravit tak, že:
  • umožní načítat z libovolného zdroje dat (například místo Excel z CSV souboru)
  • zdrojový kód bude přístupný v aktuální podobě každému a nemusí se přidávat jako příloha ke stažení
  • aplikace bude dostupná přes webové stránky – tedy pošleme soubor a obdržíme zpět PDF dokument
A proč nadpis “Vzhůru do oblak!”? – výsledný web bude v cloudu. To je dnes takové moderní slovo – v prostředí .NET nejčastěji spojované s Azure. Ale Azure nepoužijeme – Microsoft sice nabízí trial verze, jenže ani u nich není zaručeno, že na konci za to nebude platit (zde si neodpustím poznámku, že MS na Azure a WP7 předvádí jak velká firma není schopna správných rozhodnutí a nechápe, co je pro masivnější používání daných produktů klíčové – ale to je jen můj povzdech a soukromý názor). Takže místo Azure použijeme služeb AppHarbor.
Aktualizace 18.12 17:00 – jak jsem se dočetl zde, MS konečně umožnil bezplatné zkoušení. I tak je krok za AppHarbor.

Úprava stávající aplikace

Nejprve změníme typ z konzolové aplikace na knihovnu. To je jednoduchá změna, klikneme pravým tlačítkem na název projektu a ve vlastnostech změním typ:
image
Nyní se musí upravit samotná aplikace. Nejprve upravíme načítání dat – nyní je v kódu napevno zakodóváno načítání přes ADO.NET z Excel souboru:
Stávající kód
  1. void ReadAndPrintExcelSheet(...)
  2.         {
  3.             ...
  4.             Action<DbCommand> read = (command) =>
  5.             {
  6.                 command.CommandText = "SELECT * FROM [Sheet1$]";
  7.  
  8.                 using (DbDataReader reader = command.ExecuteReader())
  9.                 {
  10.                     ...
  11.                     while (reader.Read())
  12.                     {
  13.                         ....
  14.                     }
  15.                 }
  16.                 ...
  17.             };
  18.  
  19.             Db.Work("Excel", read);
  20.         }
Tohoto provázání se zbavíme poměrně snadno – zavedeme tento interface ICardData:
public interface ICardData
{
    string Word { get; }
    string Pronunciation { get; }
    string Example { get;  }
    string Meaning { get;  }
    string ExampleTranslation { get; }
}
Do definice třídy pro generování PDF pak přidáme delegáta  Func<IEnumerable<ICardData>>, který bude ukazovat na metodu, která bude schopna poskytnout údaje o kartičkách – přičemž nyní naší třídy pro generování PDF už nebude zajímat, jak to tato metoda dělá (tedy jestli čte databázi, CSV soubor, google dokument atd.):
Upravený kód
  1. Func<IEnumerable<ICardData>> getCardData;
  2. ...
  3. void ReadAndPrintExcelSheet(...)
  4. {
  5.     ...
  6.  
  7.     foreach (var cardData in getCardData())
  8.     {
  9.         ....
  10.     }
  11.  
  12.     ...
  13. }
Pokud porovnáte nový a předešlý kód navzájem, došlo ke zjednodušení. Dle mého názoru je kód i přehlednější. Zbývá ještě udělat metodu pro delegáta getCardData :-).

Poznámka pro ICardData"

Interface ICardData je implementován abstraktní třídou CardData – tato abstraktní třída pak slouží jako předek pro třídy navázané na konkrétní zdroje dat (bude ukázáno dále):
  1. public abstract class CardData: ICardData
  2. {
  3.     public string Word { get; protected set; }
  4.     public string Pronunciation { get; protected set; }
  5.     public string Example { get; protected  set; }
  6.     public string Meaning { get; protected set; }
  7.     public string ExampleTranslation { get; protected set; }
  8. }
V zdrojovém kódu je implementována i původní  podpora pro čtení Excel souborů – ale tento kód není využit (budou se zpracovávat jen CSV soubory). Slouží tedy spíše jako ukázka, jak implementovat podporu dalších zdrojů údajů o kartičkách. Jedná se o třídy DbCardDataProvider.cs, DbDataReaderCardData.cs a Database.cs.

Čteme CSV soubor

Pro čtení CSV souboru jsem si “vypůjčil” kód od Janathana Wooda.  Provedl jsem jen pár úprav – zajímá mne jen čtení ze streamu, místo čárky jsem jako oddělovač definoval středník. Výsledek je v souboru CsvStreamReader.cs.
Kód této třídy je jednoduchý – umí vzít vstupní stream a postupně jej číst “po řádcích”, přičemž každý řádek načte do objektu třídy CsvRow. To dělá metoda ReadRow(CsvRow), která vrací true, dokud nedosáhneme konce dat a aktualizuje vlastnosti objektu CsvRow tak, aby obsahoval data právě načteného řádku.
Nyní ještě zbývá udělat pomocnou třídu CsvStreamReaderCardDataProvider, která nám poskytne metodu pro delegáta Func<IEnumerable<ICardData>> pro třídu generující PDF dokument. 






  1. public class CsvStreamReaderCardDataProvider : IDisposable

  2. {

  3.     CsvStreamReader reader = null;

  4.  

  5.     public CsvStreamReaderCardDataProvider(MemoryStream stream)

  6.     {

  7.         this.reader = new CsvStreamReader(stream);

  8.     }

  9.  

  10.     public IEnumerable<ICardData> GetCardData()

  11.     {

  12.  

  13.         CsvRow row = new CsvRow();

  14.  

  15.         while (reader.ReadRow(row))

  16.         {

  17.             if (row.Count < 4)

  18.                 continue;

  19.  

  20.             CsvStreamReaderCardData card = new CsvStreamReaderCardData(row);

  21.  

  22.             yield return card;

  23.         }

  24.     }

  25. }





Funkčnost třídy je jednoduchá, vytvoří si instanci CsvStreamReaderu a poté v metodě GetCarData čte řádky, převede CsvRow na objekt třídy implementující ICardData – v tomto případě na objekt třídy CsvStreamReaderCardData, která je potomkem abstraktní třídy CardData:






  1. public class CsvStreamReaderCardData : CardData

  2. {

  3.     public CsvStreamReaderCardData(CsvRow row)

  4.     {

  5.         this.Word = row[0];

  6.         this.Pronunciation = row[1];

  7.         this.Example = row[2];

  8.         this.Meaning = row[3];

  9.         if (row.Count > 4)

  10.             this.ExampleTranslation = row[4];

  11.         else

  12.             this.ExampleTranslation = string.Empty;

  13.     }

  14. }





 



Proč vlastně stream a ne soubor (aneb iTextSharp v paměti)?



Jak jsem nastínil již v úvodu, má celá aplikace bežet v cloudu. Tam ukládání a čtení souborů může představovat problém – a protože nepředpokládám velké soubory, tak se veškeré zpracování (upload od uživatele a čtení) odehraje jen v paměti.


Výše uvedené má ještě jeden dopad – při generování PDF souboru se tento vytvářel na disku. Nyní i tento dokument musíme vytvořit v paměti a poté poslat uživateli zpět, tedy místo tohoto kódu:






  1. PdfWriter writer = PdfWriter.GetInstance(pdfDocument,

  2.                         new FileStream(

  3.                         Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),

  4.                         "Flashcards.pdf"),

  5.                         FileMode.Create));





použijeme tento kód:






  1. var stream = new MemoryStream();

  2. PdfWriter writer = iTextSharp.text.pdf.PdfWriter.GetInstance(pdfDocument, stream);

  3. writer.CloseStream = false;








Souhrn změn původní aplikace



Mimo změny v typu aplikace (z konzolové na knihovnu) a způsobu načítání dat došlo i k dalším změnám:



  • Hlavní kód se přesunul ze souboru Program.cs do souboru Creator.cs, stejně se změnili i názvy tříd (program na Creator).


  • Třída Creator má jednu hlavní metodu CreatePdf, která vyžaduje dva vstupní paramatry – metodu pro získání údajů kartiček a třídu fontů, které se mají použít


  • správné umístnění kartičky na A4 je řešeno pomocí dvou statických funkcí BackNextPositionProvider a FrontNExtPositionProvider – zpřehlednil se tak tisk stránky, který se odehrává v metodě PrintFlashCardPage


  • kartičky se ze zdoje načítají do jediného pole, to se navíc při zpracování stránky neinicilizuje znovu, ale pouze se vyprázdní příkazem Array.Clear(pageCardData, 0, pageCardData.Length);



Zpracování je nyní toto:



  1. zavolá se metoda CreatePdf – inicilizuje se pdf dokument


  2. Načtou se kartičky pro stránku pomocí odkazu  na metodu getCardData


  3. Zavolá se metoda pro vložení stránky, které se mimo pole kartiček  předají  i odkazy na metodu vyrábějící kartičky pro rubovou stránku a odpovídají metoda pro výpočet polohy kartiček na stránce (tedy odkazy na metody CreateForeignFlashcard a FrontNextPositionProvider)


  4. Totéž se provede i pro lícovou stránku, jen se předávají metody CreateNativeFlashcard a BackNextPositionProvider


  5. Metoda CreatePdf vrátí vytvořený Pfd dokument jako stream


Mimo výše uvedené jsou v projektu třídy pro získání dat z CSV souborů a ze sešitů Excel.





Třída FlashcardFonts



Tato třída obsahuje fonty používané pro vypsání textů na kartičky. Protože má aplikace fungovat na webu, je nutné šetřit systémové prostředky a tedy stačí vytvořit tyto fonty jen jednou a poté je sdílet pro všechna volání objektů třídy Creator a jejich metody CreatePdf – pro všechna tato volání se použije stejná instance.


Protože jsou kartičky vykreslovány pomocí fontu Arial, je tento font přidán do AppData webovské aplikace a ve tříde FlashcardFonts pak slouží pro inicializaci základního fontu, ze kterého pak výchází ostatní.








Web aplikace



Web aplikace využívá knihovnu pro tvorbu Pdf dokumentů. Je to MVC3 aplikace vytvořená ze šablony visual studia, obsahuje jen jeden controller nazvaný Home, který zobrazí jednoduchý formulář umožňující upload souboru:









  1. @using (Html.BeginForm("UploadCsv", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))

  2. {

  3.     <input type="file" name="file" id="file" />

  4.     <input type="submit" value="submit" />

  5. }





Data odeslaná tímto formulářem na server jsou zpracována v metodě UploadCsv:






  1. MemoryStream downloadStream;

  2. string fileName;

  3.  

  4. using (MemoryStream uploadedStream = new MemoryStream())

  5. {

  6.     Request.Files[0].InputStream.CopyTo(uploadedStream);

  7.     fileName = Path.GetFileNameWithoutExtension(Request.Files[0].FileName);

  8.     uploadedStream.Position = 0;

  9.  

  10.     using (CsvStreamReaderCardDataProvider provider = new CsvStreamReaderCardDataProvider(uploadedStream))

  11.     {

  12.         

  13.         Creator creator = new Creator();

  14.         downloadStream = creator.CreatePdf(provider.GetCardData, fonts);

  15.     }

  16. }

  17.  

  18. downloadStream.Position = 0;

  19.  

  20. return new FileStreamResult(downloadStream, "application/pdf")

  21. {

  22.     FileDownloadName = fileName + "_flashcard.pdf"

  23. };





Obsah odeslaného souboru je vložen do streamu (Request.Files[0].InputStream.CopyTo(uploadedStream);) , následně je tento stream čten pomocí CsvReaderu (ten je skryt v objektu provider)  pomocí objektu provider . Následně je zavolán Creator, jako zdroj údajů o kartičkách mu slouží metoda GetCardData objektu provider – objekt creator pak  vytvoří stream obsahující Pdf dokument. Ten je následně odeslán zpět uživateli jako application/pdf s názvem odpovídajíc šabloně <jméno souboru>_flashcard.pdf.





Sdílíme zdrojový kód –CodePlex



V příloze k tomuto článku už nenaleznete zdrojový kód popisovaného řešení – ten je nyní umístněn na CodePlex serveru a to na adrese http://flashcardcreator.codeplex.com. Zdrojový kód si můžete volně procházet přímo v prohlížeči, popřípadě stáhnout a upravit jak chcete:


image


Poznámka – co je to CodePlex?



Dle wikipedie: CodePlex je internetový projekt společnosti Microsoft určený k hostování otevřeného softwaru. CodePlex byl založen v květnu 2009. K repozitářům lze přistupovat pomocí verzovacích systémů Team Foundation Server nebo Subversion. Uživatelé mají dále k dispozici nástroje pro sledování požadavků, chyb, podporu RSS, statistiky, diskuzní fóra,, vlastní Wiki atd. Ač se většina zdejších projektů týká .NET Frameworku, včetně ASP.NET a Microsoft SharePointu, jsou zde projekty zabývající se SQL, WPF a Windows Forms a další.





Jdeme do oblak



Náš projekt z CodePlex můžeme vystavit přímo na web díky službě AppHarbor. Základní verze služby je zdarma a zprovoznění je za normálních podmínek otázkou několika minut. V nápovědě AppHarbor naleznete i postup, jak spojit CodePlex s vaší aplikací – a při každém commitu/check-inu zdrojového kódu dojde i k aktualizace aplikace na AppHarbor.


Zatím jsem se ale setkal s těmito problémy:



  • ne každý commit zdrojového kódu na CodePlex se promítne do AppHarbor – AppHarbor dělá build jednou za cca 14-15 minut – i tak je mezi aktualizací zdrojových kódů na CodePlex a aktualizací AppHarbor občas několikaminutová prodleva:





    CodePlex:


    image


    AppHarbor:


    image


    image


  • Vložil jsem souboru arial.ttf do složky App_Data, ale zapomněl jsem nastavit (přenastavit) ve vlastnostech Build Action na Content.  Což vedlo k tomu, že při lokálním spuštění vše fungovalo, ale na AppHarbor soubor fyzicky nebyl – trvalo mi dost dlouho, než jsem přišel na to, kde je chyba – uznávám, je to školácká chyba. Kdybych použil svůj osvědčený postup spočívající v samostatném webu na lokálním IIS a deploymentu z VS, tak bych na to přišel dříve.






























Nepopisuji podrobně, jak s oběma bezplatnými službami pracovat – obě požadují vytvoření účtu, což by nikomu nemělo činit problém a založení projektu na obou z nich je velmi jednoduché a přímočaré – v případě problémů existují diskuzní fóra i nápovědy u obou služeb.


Služba běží na adrese http://flashcard.apphb.com a základní rozhraní je velmi jednoduché:


image


Stačí vybrat soubor (ukázka souboru ve formátu UTF-8 CSV je přiložena jako slovicka.txt) a odeslat na server. Zpět vám přijde PDF dokument.


Závěr



Prosím mějte na paměti, že kód je pouze demonstrační.  Řetez událostí vypadá při použití CodePlex a AppHarbor takto: vývojář udělá změny a provede check-in změn do CodePlex. CodePlex upozorní AppHarbor na změnu, AppHarbor získá z CodePlex zdrojové kódy, zbuilduje je a nasadí.