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

22
Jul

Entity framework a IN klauzule

V konferenci o .net na builder.cz se objevil dotaz, jak sestavit SQL dotaz pomocí Entity frameworku, který by vygeneroval na výstupu omezující podmínku IN.

Jelikož v Linq to SQL je toto poměrně triviální řešení a je možné použít extenzní metodu Contains, neváhal jsem a autorovi potvrdil, že obdobně to bude i v případě Entity frameworku. Jenže pak ve mě začal hlodat červík nedůvěřivosti, vždyť to autor dotazu měl správně, tak proč to nejde. Až jsem přišel na to, že v EFv1 nelze použít Contains metodu tak, aby se vygenerovala IN klauzule.

Samozřejmě existuje řešení, kdy je možné provést celý SQL dotaz a až následně v paměti aplikovat spojení, které zajistí omezující podmínku. Je to však řešení nepříliš praktické.

Zkusil jsem tedy chvilku bádat a tady je řešení. Jedná se o to, že klauzule IN je možné reprezentovat také jako spojení jednotlivých hodnot operátorem OR. Pro lepší možnost použití je pak vytvořena extenzní metoda s názvem In a přebírající dva parametry.

public static class EFExtensions {

    private static Expression<Func<TEntity, bool>> GetIn<TEntity, TValue>(
 Expression<Func<TEntity, TValue>> propertySelector,
 IEnumerable<TValue> values) {
        var property = propertySelector.Parameters.Single();
        if ((values == null) || (!values.Any()))
            return e => false;

        var parts = values.Select(value => Expression.Equal(
 propertySelector.Body, 
 Expression.Constant(value, typeof(TValue))));
        var body = parts.Aggregate(Expression.Or);

        return Expression.Lambda<Func<TEntity, bool>>(body, property);
    } 

    public static IQueryable<TE> In<TE, TV>(this IQueryable<TE> source, Expression<Func<TE, TV>> propertySelector, 
params TV[] values) {
        return source.Where(GetIn(propertySelector, values));
    }

    public static IQueryable<TE> In<TE, TV>(this IQueryable<TE> source, Expression<Func<TE, TV>> propertySelector, 
IEnumerable<TV> values) {
        return source.Where(GetIn(propertySelector, values));
    } 
}

Použití této extenzní metody je pak velice jednoduché a demonstruje ji následující případ:

var ids = new int[] {1, 2, 3};
var data = db.TestTable.In(e => e.IntValues, ids).OrderBy(e => e.StringValues);
Publikováno pod: builder.cz , code snippet
7
Jun

VI. neformální setkání .net builder.cz

Pojďme se přesunout od klávesnice ke stolům a popovídat si o vývojářských, ale také těch méně vývojářských tématech v příjemném prostředí některé z pražských restaurací.

Jestliže se chcete neformálně a přitom osobně potkat s některými z přispěvatelů konference o .net na serveru builder.cz, budete vítání v jednom z níže uvedených termínů. Jedná se o neformální společenské setkání vývojářů, se širokým záběrem témat, od těch ryze o vývoji software, ale stihneme probrat i témata jiná.

Pokud tedy máte chuť, náladu a hlavně čas, rád vás uvidím:

Kdy: 15. nebo 17.6.2009 (pondělí nebo středa)

V kolik: začátek je v 18:30

Kde: v některé z příjemných pražských restaurací, upřesním v potvrzovacím emailu

Registrace: poprosím o komentář s uvedením emailu a preferovaným termínem

Samozřejmě jsou vítání všichni, jak tváře známé, tak i zatím tváře neznámé – samozřejmě, že budete vítání i v případě, že nepříspíváte do konference, ale o .net se zajímáte.

Jelikož je akce již velice brzy, poprosím o registraci do čtvrteční půlnoci.

Publikováno pod: builder.cz , .net technology
5
Jun

asp.net MVC – když Model není Model

Tak jsem si ve svém shrnutí diskuze o asp.net MVC pěkně naběhl, když jsem vyřkl následující větu: “Model představuje data k zobrazení”.

Při tomto výroku jsem myslel především na skutečnost, že je častou chybou představit si Model jako databázi a jako takový je potom znám ve View. V takovém případě pak má View přímý přístup k databázi, což se mi nelíbí a určitě bych toto nedělal a ani nemohu doporučit (na čemž jsme se v diskuzi shodli). Už jsem však nemyslel na pokročilé vývojáře, kteří dle definic znají pod pojmem Model aplikaci/služby a přitom dokáží svůj model připravit k využití v Controlleru tak i k zobrazení bez následků ve View.

Poté, co jsem si vše nechal uležet mi vše docvaklo a zjistil jsem, že pojmenování nebylo z mé strany úplně vhodné. Tudíž je na čase se omluvit.

Takže Model, tak jak je pojímán v definici MVC není skutečně tím Modelem, který jsem vyřkl v oné větě. Pro toto mé označení by se více hodilo označení ViewModel, tak jak je pojímáno v jedné z implementací MVC a to MVVM.

Pro příště se tedy budu držet terminologie, že View zná svůj ViewModel, to samé pak platí pro komunikaci směrem od Controlleru k ViewModelu. Pouze ViewModel pak ví o Modelu. A nesmím ještě zapomenout na propojení z Controlleru na View.

To jak se právě uvedeného propojení dá využít v psaní asp.net MVC aplikace se pokusím naznačit v příštím článku. A možná se mi tak podaří ukázat, že ono pověstné přidání komentářů může znamenat změnu jen jednoho místa v … a poté změnu samotných View, tak jako by to bylo nutné udělat ve WebForms.

4
Jun

asp.net MVC Best practices – shrnutí

Ve středu večer proběhla diskuze v půlkulatém kruhu na téma asp.net MVC Best practices, kterou se mi povedlo uspořádat v prostorách Microsoftu a pozvat na ni zástupce různých technologií.

Něco málo k organizaci

Dřív než se dostanu k samotnému shrnutí získaných informací, dovolím si uvést několik málo informací k organizaci a průběhu samotné diskuze. Tato totiž dopadla nad očekávání dobře a dle reakcí účastníků to není jen můj osobní pocit, za což jsem velice rád a musím především zúčastněným poděkovat. Maličko jsem se totiž obával, když jsem sezval zástupce různých technologií, aby diskuze nesklouzla k flame-ování, ve výsledku z toho byla však konstruktivní debata trvající téměř 3 hodiny, a po ní ještě flám-ování. Je vidět, že pokud se sejdou lidé, kteří mají spoustu znalostí a zkušeností, dokáží být nad věcí a přistoupit k diskuzi konstutivně. Zároveň se pak velice snadno dokáží přizpůsobit a orientovat se i v jiné technologii, jelikož se zde řeší stejné úlohy, pomocí stejných vzorů, jen s odlišnou implementací.

Pro příště mám však jedno ponaučení, zúčastnění by se měli na takovéto diskuzi osobně představit. Přestože jsem připravil vizitky velikosti A4 se jménem a zastoupenou technologií, nebylo to dostačující. A tak David Grudl (Nette PHP) zjistil až někdy kolem půlnoci, že se zúčastnil také Michal Bláha (.NET WebForms). Zajímavá chvilka taktéž nastala při diskuzi, kdy Vlasta Vávrů (Java, PHP) se podivil nad komplexností deploymentu popisovaného Honzou Králem (Django). Zajímavé postřehy pak měli také Karel Minařík (Rails), Borek Bernard (Flex) a Daniel Kolman (.NET MVC). Musím též poděkovat Aleši Roubíčkovi a Michalu Augustýnovi za pomoc a podporu při organizaci. Samozřejmě patří dík i ostatním, kteří se zúčastnili a zapojili se do diskuze.

Ostatním, kteří měli zájem se diskuze zúčastnit, nebo mají zájem dozvědět se závěry z diskuze mám potěšující zprávu, v dohledné době proběhne přednáška na téma asp.net MVC, kde budou prezentovány závěry z uskutečněné diskuze vzešlé.

Pro nedočkavce – shrnutí MVC Best practices

Myslím, že velice detailní shrnutí již sepsal Borek Bernard v ohlédnutí z diskuze o MVC a svůj pohled na, asi jedinou flame diskuze, pak Tomáš Herzeg o rozdílech mezi WebForms a asp.net MVC.

Přidám tedy jen svůj pohled, který doufejme doplní výše uvedené články. Co jsem si odnesl z diskuze já a co mě velice potěšilo, že jsem se vesměs se svými předchozími články popisujícími použití MVVM v asp.net MVC celkem trefil do toho, jak uvažují i ostatní o přístupu k implementaci MVC principu pro webové aplikace. Právě David Grudl popisoval velice podobný scénář, který použil v Nette pomocí “plniče” Presenteru, jako jsem uvedl v článku jak vypadá ViewModel v asp.net MVC.

V hlavní roli Model

Co je třeba si uvědomit při využití jakékoliv implementace MVC je role Modelu. Jak zmínili téměř všichni přítomní, především u začínajících vývojářů je Model považován za databázi, což určitě není. Model představuje data, která jsou připravena k zobrazení. Na co určitě zapomeňte je předávání DataContextu do View, pokud chcete využít třeba LINQ2SQL nebo Entity Framework. Maličko lepší službu už uděláte v případě, že předáte jen vygenerované datové objekty, na mnoha malých webech to bude dostačující. Jestliže však uvažujete o něčem větším, vytvořte si vhodný view model, který bude respektovat potřeby pro zobrazování v aplikaci, nikoliv potřeby relační databáze. Do modelu se pak nebojte zahrnout i podpůrné vlastnoti vhodné při zobrazování dat.

Jednoduchý Controller

Citovat Davida si dovolil již Borek, já mohu jen souhlasit. Controller by měl být co nejjednodušší. Měl by se postarat jen o výběr vhodného ViewModelu (Presenteru), zvalidovat vstupní data a vybrat šablonu (View), která provede zobrazení dat. Případně se samozřejmě postará o přesměrování na jinou akci, což je jen o tom, že vybere jiný ViewModel a jinou šablonu, která se zobrazí.

Pasivní View

Přesně tak, nesnažte se do View vkládat složitější logiku než je jen vypsání dat na potřebná místa. Šablony v asp.net MVC mohou svádět k tomu je vytvořit aktivní a manipulovat zde s Modelem, obzvláště pak v případě, že si do View předáme potřebné objekty typu DataContext. Dobrým řešením by mohlo být použití takového ViewEngine, který dovoluje pouze deklarativní zápis, případně komponentové poskládání stránky – obdobně jako bylo představováno frameworkem Django.

Nenecháme si to pro sebe?!

Samozřejmě je toho víc a výše zmíněné je jen to hlavní co mi utkvělo v paměti. O další informace se budu chtít s vámi podělit. Kdy to konkrétně bude ještě nevím, ale určitě sledujte vypisované akce. A není to vše, jak jsem se již zmiňoval v úvodu, snad všichni pozvaní vývojáři byli uspořádáním takovéto akce nadšeni a rádi se zúčastní obdobných diskuzí. A jelikož se více jak půl hodinu taktéž diskutovalo o testování aplikací, předběžně jsme se domluvili na tomto tématu. Představa je formou panelové diskuze, tudíž pokud bude mít někdo zájem, určitě se bude moci zúčastnit.

Budu se tedy těšit na brzkou viděnou se všemi zájemci o vývoj pomocí asp.net MVC.

25
May

WPF Binding bez codebehind

Celkem zajímavý dotaz padl v konferenci o .net na serveru builder.cz. V krátkosti se jednalo o změnu datového zdroje nabindovaného na ListView při změně vybrané položky jiného ListView.

Varianta codebehind

V dotazu bylo poukazováno na obsluhu události SelectionChanged, ve které chtěl tazatel řešit změnu bindování na jiný deklarovaný zdroj ve Window.Resources, konkrétně různě naplněný XmlDataProvider.

Samozřejmě by toto provázání bylo taktéž možné, ale z vlastní zkušenosti a vývoje wpf aplikací jsem zjistil, že používání codebehind souboru není většinou nutné a je možné vše deklarovat pomocí XAML. Codebehind je tak ve větší míře využíván jen při tvorbě vlastních Control.

Varianta bez codebehind

Tazateli jsem tedy zaslal odkaz na příspěvek [Selecting the Detail Level to View at Runtime in WPF] publikovaný na CodeProject od Josh Smith, který se věnoval bindování různých deklarovaných template dle uživatelského výběru. Principiálně tedy velice podobný problém. Martin to tak neviděl a tak jsem se rozhodl konkrétní případ vytvořit a publikovat. Jelikož je však třeba bližšího komentáře, ponechal jsem si odpověď jako krátké povídání.

Postup vytvoření aplikace splňující zadání

Začal jsem s čistým projektem typu WPF aplikace. První na řadě tak byla deklarace datových zdrojů – XmlDataProviderů a naplnění daty.

Deklarace datových zdrojů

<XmlDataProvider x:Key="products" XPath="root/datas">
            <x:XData>
                <root xmlns="">
                    <datas>
                        <data id="a1">a</data>
                        <data id="a2">b</data>
                        <data id="a3">c</data>
                    </datas>
                </root>
            </x:XData>
        </XmlDataProvider>
        <XmlDataProvider x:Key="a1" XPath="root/datas">
            <x:XData>
                <root xmlns="">
                    <datas>
                    <data>1aa</data>
                    <data>1bb</data>
                    <data>1cc</data>
                    </datas>
                </root>
            </x:XData>
        </XmlDataProvider>
        <XmlDataProvider x:Key="a2" XPath="root/datas">
            <x:XData>
                <root xmlns="">
                    <datas>
                    <data>2aa</data>
                    <data>2bb</data>
                    <data>2cc</data>
                    </datas>
                </root>
            </x:XData>
        </XmlDataProvider>
        <XmlDataProvider x:Key="a3" XPath="root/datas">
            <x:XData>
                <root xmlns="">
                    <datas>
                    <data>3aa</data>
                    <data>3bb</data>
                    <data>3cc</data>
                    </datas>
                </root>
            </x:XData>
        </XmlDataProvider>

Deklaraci datových zdrojů a přiřazení jim příslušných identifíkátorů jsem vložil do Window.Resources elementu tak, aby tyto zdroje byly dostupné v celém objektu okna. Tady musím zmínit, že názvy datových zdrojů, které budou měněny po výběru jsem definoval shodné s hlavním zdrojem dat. Toto samozřejmě není nutné, jde jen o to, mít jasně definovaný převodní můstek pro výběr správného zdroje.

Vzhled aplikace

Následovala deklarace aplikace, zvolil jsem StackPanel, do kterého jsem postupně přidával jednotlivé prvky. Nesmí chybět nějaký nadpisek aplikace, abychom neměli jen holé okno. Následuje pak deklarace prvního ListBoxu – jakožto jednodušší varianty (předka) pro ListView. Tento ListBox je nabindován na hlavní datový zdroj. Zároveň definuje vlastní DataTemplate, který se stará o vizuální zobrazení dat v prvku.

        <ListBox Width="400" Height="200" Background="Honeydew" x:Name="prod">
            <ListBox.ItemsSource>
                <Binding Source="{StaticResource products}" XPath="*" />
            </ListBox.ItemsSource>
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock FontSize="12" Foreground="Red">
                      <TextBlock.Text>
                        <Binding XPath="." />
                      </TextBlock.Text>
                    </TextBlock>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

V tomto případě jsem použil expandovaný zápis pro binding i když by se samozřejmě dal použít i inline styl. Druhý deklarovaný ListBox je jen o něco málo složitější, ale ukrývá v sobě hlavní sílu WPF a to MultiBinding a využití IValueConverter resp. IMultiValueConverter.

IMultiValueConverter – srdce bindingu pro řešení zadání

Dříve než sem napíšu i deklaraci druhého ListBoxu, musím se zmínit o srdci celého řešení a to je vytvoření konverteru, který zajistí vyhledání datového zdroje v Resources a jeho navrácení. Pro vyhledání jakéhokoliv pojmenovaného zdroje je možné použít metodu FindResource, případně její rozšířenou variantu TryFindResource lišící se pouze v tom, že nevyvolá Exception v případě, že daný klíč není nalezen v Resources. Pro získání daného zdroje pak potřebujeme získat objekt, který tento zdroj vlastní v tomto případě objekt Window. Zároveň potřebujeme mít k dispozici i vybranou hodnotu prvního ListBoxu.

Jelikož potřebujeme dvě hodnoty, není možné využít jednoduchý IValueConverter, ale musíme použít IMultiValueConverter, který se liší pouze tím, že přebírá do metody Convert pole hodnot.

Jak tedy vypadá kód našeho konverteru:

    public class ResourceKeyConverter: IMultiValueConverter {

        #region Implementation of IMultiValueConverter

        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) {
            var fe = values[1] as FrameworkElement;
            var val = values[0] as XmlNode;
            if ((fe != null) && (val != null)) {
                var resource = fe.TryFindResource(val.Attributes["id"].Value) as XmlDataProvider;
                return resource;
            }
            return null;
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }

        #endregion
    }

Jak je vidět, je to velice jednoduché, samozřejmě je třeba si domyslet ještě i další kontroly, které by bylo vhodné provést.

Binding ListBoxu dle výběru

Nyní se tedy můžeme dostat k deklaraci ListBoxu, který bude obsahovat měněná data z různých datových zdrojů. Jedná se o stejný ListBox, který je definován v prvním případě, rozdílem je pouze zmíněný MultiBinding, který předává konverteru vybranou hodnotu prvního ListBoxu a zároveň i objekt, který drží Resources, tedy v tomto případě pojmenované hlavní okno.

        <ListBox Width="400" Background="AntiqueWhite" ItemsSource="{Binding XPath=*}">
            <ListBox.DataContext>
                <MultiBinding Converter="{StaticResource rsKey}">
                    <MultiBinding.Bindings>
                        <Binding ElementName="prod" Path="SelectedItem" />
                        <Binding RelativeSource="{RelativeSource  AncestorType={x:Type Window}}" />
                    </MultiBinding.Bindings>
                </MultiBinding>
            </ListBox.DataContext>
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock FontSize="12" Foreground="Red">
                      <TextBlock.Text>
                        <Binding XPath="." />
                      </TextBlock.Text>
                    </TextBlock>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

Důležitým krokem v tomto případě je, deklarace a registrace našeho konverteru do zdrojů tak, aby byl k dispozici pro použití v deklaracích u bindingu. To provedeme rovněž v elementu Window.Resources a specifikujeme pro něj klíč. Taktéž je nutné deklarovat namespace, ve kterém se náš konverter nachází.

<WpfBinding:ResourceKeyConverter x:Key="rsKey" />

Stačí jen spustit

Jsme u posledního kroku a to je spuštění aplikace, pokud jsme postupovali správně, dostaneme požadovaný výsledek. Z předchozího povídání je vidět, že pro toto zadání není nutné používat codebehind a je možné téměř všechnu logiku deklarovat za pomoci XAML a vhodně napsaného konverteru, který může být znovupoužit.

Navržené řešení nemusí být optimální a pouze reflektuje dané zadání. Osobně bych se k danému problému snažil postavit v jiném duchu a využil v hojné míře návrhového vzoru Model-View-ViewModel, který používám při tvorbě WPF aplikací. Na druhou stranu se mi toto řešení jeví jako vhodnější, než obsluhovat události jednotlivých prvků v codebehing a snažit se na ně reagovat.

Projekt ukázkové aplikace ke stažení:

Publikováno pod: builder.cz , code snippet , .net technology , wpf
24
May

asp.net MVC Best practices - pozvánka

Také se zajímáte o vývoj za pomoci MVC vzoru. Máte k tomuto přístupu k vývoji prezentační vrstvy nějaké otázky nebo si naopak myslíte, že byste mohli přispět svojí radou nebo zkušeností?

Potom budu rád, pokud se registrujete na akci asp.net MVC Best practices a svoji motivaci připíšete do poznámky.

Popis akce

K diskuzi jsou přizváni též vývojáři zastupující technologie nespadající pod .net, avšak jejich vývoj je též založen na principu návrhového vzoru MVC. Cílem diskuze je najít vhodné postupy při vývoji webových aplikací, které využívají principu MVC a odvozených návrhových vzorů tak, aby se dosáhlo efektivního vývoje aplikace, která dovoluje snadné úpravy a rozšiřitelnost. Závěry, rady a postřehy z této diskuze by měli sloužit nejen začátečníkům v orientaci při vývoji webových aplikací. Diskutující se též seznámí s implementací MVC v jiných technologiích než je asp.net. Důležitým předpokladem pro účast je tak znalost vývoje pomocí MVC návrhového vzoru, případně jeho odvozenin.

Přizvaní hosté

David Grudl, Jan Král, Vlastimil Vávrů, Michal Bláha, Borek Bernard, Aleš Roubíček, Michal Augustýn, Karel Minařík a další

10
May

.NET RIA Services – úvod

V okamžiku, kdy jsem začal přemýšlet nad obsahem přednášky o .NET RIA Services jsem měl velice smíšené pocity. Jedním z nich byl i ten, že se jedná o technologii, která je teprve v plenkách, tedy v CTP verzi, a přitom by si po jejím představení jistě spoustu vývojářů přálo, aby již byla dostupná pro produkční prostředí.

Tím dalším pocitem pak byl ten, že na jedné přednášce se nedá předvést vše, co .NET RIA Services nabízejí vývojáři při vývoji data entry aplikací. To se však dá vyřešit celkem jednoduše, jedna varianta je uspořádat přednášku druhou, nebo o této technologii – projektu nebo šabloně, záleží, jak se na to podíváme – napíši několik článků. Jak je jasné ze čtení těchto písmenek, rozhodl jsem se pro druhou variantu, kdy se pokusím představit .NET RIA Services v sérii článků. Mojí snahou bude věnovat se nejen samotné technologii, ale i jejímu zasazení do návrhu projektu.

n-vrstvá architektura aplikací

Když se podíváme na spoustu vyvíjených aplikací, které se snaží využívat objektového návrhu a výhod n-vrstvých aplikací, zjistíme, a to především u začínajících vývojářů, že se jedná vlastně jen o dvouvrstvé aplikace. Taková aplikace se vyznačuje tím, že hned v obsluze událostí uživatelského rozhraní se přistupuje k datové vrstvě a zároveň se v této prezentační vrstvě řeší i aplikační logika aplikací.

Jak jistě každý hned vidí, tento stav není vůbec ideální a přináší s sebou spoustu kódu, který je při rozšiřování aplikace třeba refaktorovat, v horším případě pak kód duplikovat.

Umístění servisní vrstvy s aplikační logikou

S příchodem RIA (Rich Internet Application), které je možné vyvíjet za pomoci .net frameworku však vzniká další požadavek, který je nutné řešit a to je nejen oddělení servisní vrstvy, ale zpřístupnění této vrstvy jako endpoint pro přístup z prezentační vrstvy přes internet. Samozřejmě nyní můžete navrhnout, že toto zpřístupnění je možné vytvořit například pomocí WCF, nebo jen vytvořením web services v již existující web aplikaci. Ti kteří vyvíjejí nad poslední verzí .net frameworku pak budou znát ADO.NET Data Services, jakožto přístupový bod k jejich datům.

Jak však vidíte, není to stále to pravé, vždy je potřeba udělat ještě jeden krok, který naší RIA aplikaci poskytne data a zapojí servisní vrstvu s aplikační logikou do celé aplikace.

RIA aplikace

Nyní si dovolím krátkou odbočku a pokusím se přiblížit ze svého pohledu RIA aplikace. Jsou to aplikace, jejichž prezentační vrstvu stále tvoří tenký klient. Tento klient však již není úplně “hloupý” a nabízí uživateli komfort blížící se tlustým nebo smart klientům. Tyto aplikace se nemusí instalovat, nebo k jejich instalaci je nutný jen minimální instalační balíček (framework), který využívají.

RIA aplikace můžeme využít všude tam, kde potřebujeme zajišťovat vstup dat od uživatelů tzv. data entry aplikace, kde právě komfort při zadávání dat zpříjemňuje uživateli jeho práci. Stejně tak do těchto aplikací můžeme zařadit LOB – Line Of Business – aplikace.

Které technologie můžeme očekávat ve spojení s RIA aplikacemi? Pokud zůstanu jen u .net aplikací, tak sem patří asp.net webové aplikace s bohatým využitím AJAXu, dalším silným zástupcem můžeme považovat Silverlight aplikace. Obecně by se pak dalo říci, že se jedná o takové aplikace, které umožňují interaktivitu aplikace s koncovým uživatelem na klientské straně a data jsou poskytována vzdáleně přes internet.

.NET RIA Services

Po přečtení předchozích odstavců mohu konečně přistoupit k popisu toho, k čemu byly vytvořeny .NET RIA Services, a které možnosti a usnadnění nám nabízejí při vývoji.

Jak již samotný název napovídá, jedná se o servisní vrstvu, která nám usnadňuje zapouzdření aplikační logiky na serverové straně a vytvoření n-vrstvé aplikace. Tato servisní vrstva pak bude obsahovat nejen aplikační logiku, ale též validaci vstupních dat, přístup a využití datové vrstvy k získávání dat, jejich uložení a modifikaci. Ale také může a nejspíše bude řešit authentikaci a řízení přístupu pomocí rolí.

Kompletní balíček však není jen o vytvoření servisní vrstvy, ale je zde zahrnut i balík komponent, které můžeme využít při tvorbě Silverlight aplikace, stejně tak zde najdeme prvky, které využijeme při vývoji asp.net webform aplikace. V neposlední řadě je to potom velice důležitý samotný projekt, který obsahuje připravené šablony a build akce, které se starají o generování kódu pro klientskou stranu – tak, aby byla zajištěna její bohatost.

DomainService

Na asi nejdůležitější část .NET RIA Services a to třídu DomainService a její potomky se podívám podrobněji v příští části tohoto seriálu.

1
May

.NET RIA Services – přednáška

Před týdnem jsem měl v prostorách české pobočky Microsoftu přednášku na téma .NET RIA Services, kde jsem se snažil představit tento nástroj pro snadnější vývoj RIA aplikací.

Slíbil jsem, že zdrojové kódy, které jsem z velké části odprezentoval na přednášce, zpřístupním, abyste měli možnost nahlédnout pod pokličku této technologii pro snadnější tvorbu data entry aplikací.

Zdrojové kódy aplikace obsahují připravovanou, avšak ne celou odprezentovanou, RIA aplikaci.  Před spuštěním aplikace budete muset do vývojového prostředí doinstalovat:

  • Silverlight 3 Tools Beta 1 for Visual Studio 2008 – nahrazuje Silverlight 2, proto doporučuji instalovat do testovacího prostředí např. Virtual PC
  • .NET RIA Services March ‘09 Preview

Součástí zdrojových kódů jsou i scripty pro vytvoření databáze.

V nejbližší době se pokusím připravit několik příspěvků na téma .NET RIA Services a tvorba data entry aplikací s využitím Silverlight 3.

V případě otázek jsem připraven je zodpovědět.

10
Apr

Jak vypadá ViewModel v asp.net MVC

Při psaní úvodního článku, ve kterém jsem se věnoval postřehům při vývoji asp.net MVC aplikace jsem si ani nepomyslel, že vydám i druhý článek, který bude popisovat Model-View-ViewModel upravený vzor pro takovou aplikaci. A už vůbec to, že bych se rozhodl ke psaní článku třetího o tom, jak vlastně taková třída ViewModel v mém podání vypadá.

Okolnosti tomu však chtěli a tak jsem zde s dalším pokračováním na rozpracované téma. Tentokrát se pokusím osvětlit, jak vypadá třída ViewModel v mém podání zasazená do asp.net MVC aplikace.

ViewModel

Jak jsem již popsal, třída ViewModel zprostředkovává data a komunikuje se sevisními objekty aplikace a zároveň poskytuje data aplikace pro View. Zároveň pak upravuje tato data, aby s nimi ve View byla snazší práce a View mohlo být velice jednoduché a nevykonávalo žádnou logiku. Ještě neopomenu zmínit jednu věc, že k vytvoření konkrétní instance ViewModel používám IoC/DI container, tudíž servisní objekty jsou injektovány a o jejich existenci tak nemusí mít Controller ponětí.

Zkusím projít popisem tak, jak většinou prochází takový normální požadavek na získání informací a jejich editaci a to pro jeden datový objekt.

Akce Controlleru vypadá nějak takto

public ActionResult Update(int id) {
    var model = Container.Resolve<ProductDetailViewModel>();
    model.Load(id);
    return View(model);
}

Odpovídající třída ViewModelu pak nějak takto

public class ProductDetailViewModel {
    private readonly IProductService _productService;
    public ProductDetailViewModel(IProductService productService) {
        _productService = productService;
    }
    
    public void Load(int id) {
        Product = _productService.Get(id);
    }
    
    public ProductEntity Product {
        get;
        private set;
    }
    
    public bool IsProductLoaded {
        get { return Product != null; }
    }
}

Pro jednoduchost jsem momentálně odstranil další potřebné servisní objekty o kterých jsem se zmiňoval již dříve. Například providera na TempDataDictionary. Zároveň je vidět, že ProductDetailViewModel obsahuje i další vlastnosti, které jsou použity ve View a odpadá nám tak nutnost testování a rozhodování se na úrovni View.

Nyní přejdu k akci, kdy uživatel žádá o aktualizaci takto poskytnutého záznamu, který zaktualizoval.

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Update(int id, FormCollection formCollection) {
    var model = Container.Resolve<ProductDetailViewModel>();
    model.Load(id);
    if (TryUpdateModel(model.Product, "Product", null, new string[] {"Id"})) {
        if (ModelState.IsValid) {
            model.Save();
            return RedirectToAction("Get", new { id = id});
        }
    }
    return View(model);
}

Jak je vidět, téměř nic se nezměnilo, jen přibyla metoda Save() na našem ViewModelu, která zpropaguje požadavek na servisní vrstvu.  Celé by to šlo samozřejmě ještě upravit tak, že by metoda Save vracela výjimku v případě, že by se nepodařilo záznam uložit a došlo by k znovupožadavku na editaci. Je však na samotné logice aplikace, jak se s takovou chybou vypořádá a zda nabídne uživateli opět možnost editace a odstranění problému, nebo jej přesune na jinou stránku.

Důležitou součástí celého procesu se tak stává ModelBinder, který může zároveň provést validaci vstupních dat oproti business pravidlům.

Spolupráce s ModelBinder

Výše uvedené je celkem pěkný postup, ale stále zde je ještě spousta kroků, které se mohou přesunout, abychom se mohli soustředit jen na samotné akce a pokud možno se co nejvíce přiblížili k pouhému vyvolávání metod na ViewModelem, tak jako se vyvolávají události ve WPF aplikaci při použití vzoru MVVM.

K tomu však potřebujeme maličko lepší spolupráci ModelBinderu, než která nám je nabízena prostřednictvím výchozího DefaultModelBinderu. Hlavní úlohou námi definovaného ModelBinderu je vytvoření instance ViewModelu a validace vstupních dat. Samozřejmě si zde můžeme připsat i další logiku bindování na data.

Takový ModelBinder pro náš ViewModel k detailu produktů může vypadat následovně:

public class ProductDetailViewModelBinder: DefaultModelBinder {
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) {
        bindingContext.Model = Container.Resolve<ProductDetailViewModel>();
        var id = int.Parse(bindingContext.ValueProvider["Product.Id"].AttemptedValue);
        bindingContext.Model.Load(id);
        return base.BindModel(controllerContext, bindingContext);
    }
}
Samozřejmě opět odhlížím od kontrol, které by bylo potřeba doplnit. Zároveň by bylo vhodné doplnit validaci nabindovaných dat oproti business pravidlům, což je pro zjednodušení vynecháno.

Akce v příslušném Controlleru se nám tedy rázem zjednoduší a její implementace bude následující:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Update([Bind]ProductDetailViewModel model) {
    if (ModelState.IsValid) {
        model.Save();
        return RedirectToAction("Get", new { id = model.Product.Id});
    }
    return View(model);
}

Což už je myslím akceptovatelný stav. Samozřejmě bude záležet na okolnostech a celkovém chápání aplikace. Neboť tento případ skrývá před vývojářem samotné naplnění modelu daty třídy Product, což je na druhou stranu obdobný případ, jaký nastává ve WPF aplikaci, kdy nedochází ke ztrátě stavu a pracujeme již s existující instancí naplněnou daty.

Před cílovou rovinkou

Už je mi celkem jasné, že jsem se nedostal ani před cílovou rovinku a vyvstaly další otázky. Třeba jak řeším právě předávání dočasných dat v TempDataDictionary a jak dochází k jejímu injektování do ViewModelu. Takže u tří článků určitě nezůstane. V příštím článku se tak pokusím soustředit se na tuto oblast a případně zodpovědět vložené dotazy.

7
Apr

MVVM v asp.net MVC

V minulém příspěvku, kdy jsem se věnoval mým postřehů z použití asp.net MVC jsem též zmínil možné použití MVVM přístupu a analogii použití k desktopovým aplikacím.

Použití MVVM – Model View ViewModel vzoru

Hlavní motivací pro použití tohoto vzoru pro mě bylo, jak jsem již minule zmínil v odlehčení Controlleru a zjednodušení View, kde jsem nechtěl řešit implementační detaily, především pak samotné vyhodnocování podmínek.

Zároveň s tím jsem se však dostal v prvních krocích do menších komplikací, neboť jsem byl postaven před otázku rozumného vyřešení předávání některých potřebných objektů do ViewModelu (VM) a zároveň jsem si chtěl ponechat volnost a možnost testování VM. Pro lepší přehled zmíním použití jednorázového uložiště dat v podobě TempDataDictionary.

IoC/DI container

Jelikož jsem si velice oblíbil použití IoC/DI containeru konstruoval jsem aplikaci tak, abych tento přístup mohl využít i při tvorbě asp.net MVC aplikace. Jako vhodnou volbou se tak jevilo použití MVCContrib projektu, který nabízel nativní podporu pro všechny rozšířenější implementace. Moji volbou se stal Unity vyvíjený skupinou pattern & practices.

V konečném důsledku mi právě použití DI containeru pomohlo v tom, jak vyřešit právě ono předávání (injectování) objektů do VM. Samozřejmě by to šlo zařídit i jinak, ale přeci jen mi tento způsob přijde elegantnější a pro vývojáře jednodušší – nemusí myslet na to, co musí udělat a co případně musí zavolat.

Když už jsem zmínil právě ono jednorázové uložiště dat (TempDataDictionary), chvíli jsem přemýšlel, jak jej vhodně předat, nakonec mi jako vhodný způsob přišlo použít existující instanci tohoto objektu získaného v okamžiku vytvoření Controlleru a v přepsané třídě poděděné od DefaultControllerFactory jsem tuto instanci vložil do containeru – samozřejmě s platností pouze pro daný web request. Zde tedy bylo nutné ještě napsat si vlastní WebRequestLifetimeManager, neboť Unity ve své výchozí instalaci zná pouze dva LifetimeManagery a samozřejmě ani jeden z nich nepodporuje web requesty :-).

Výhod použití IoC/DI jsem pak také využil i v případě předávání servisních objektů do VM, většinou pak přes constructor injection.

Role Controlleru

Jak jsem již zmínil, snažil jsem se odlehčit Controller, jeho úloha v mém pojetí se tedy redukovala na tyto základní operace:

  • vytvoření ViewModelu
  • nabindování dat – většinou dat z requestu
  • zavolání vhodné metody na ViewModelu – analogicky k desktop aplikaci, vyvolání vhodné události
  • propojení ViewModelu na příslušné View

Z předchozí věty by se mohlo zdát, že ViewModel je svázán s konkrétním View a nemůže bez něj koexistovat, což ovšem není pravda a VM je nezávislou jednotkou a může k prezentaci dat využívat několik různých View.

Když jsem se zmínil o vytvoření ViewModelu, je třeba říct, že ani toto nemusí být tak úplně úlohou Controlleru, stejně tak jako nabindování dat, neboť toto může zajistit vhodně napsaný a upravený ModelBinder.

Tím se tedy dostávám k odpovědi na Augiho otázku pod minulým příspěvkem, jakým způsobem řeším bindování dat. Určitě nepoužívám generický ViewModel, ten by bylo možné použít možná u jednoduchých CRUD stránek. Zároveň určitě nepředávám do ViewModelu kolekci FormCollection, neboť bych ViewModel příliš svázal s prostředím a já se snažil jej mít co nejvíce nezávislý – i ono vložení TempDataDictionary je řešeno přes interface poskytující přístup k dictionary.

Tudíž odpověď je následující. U stavových stránek je za vytvoření správného ViewModelu v akci zodpovědná daná akce, která též vybírá View. Vytvoření se pak děje přes resolving instance IoC/DI containeru. V případě, že se jedná o request mající za úkol vykonat příkaz, potom jsou dvě možnosti. Nechat ViewModel vytvořit upraveným ModelBinderem a bindování dat ponechat v jeho režii, případně postupovat obdobně jako ve stavové akci a binding ponechat na metodě UpdateModel/TryUpdateModel.

Osobně jsem volil spíše druhý přístup, ale to mělo spíše jiný důvod, ke kterému se přiznám a rovnou se i vymluvím :-) Funkce ModelBinderu mi byla delší dobu malou neznámou a převod dat jsem řešil spíše přes ValueProvidery, toto řešení však ve verzi 1.0 bylo zavrženo a já se nakonec stejně musel použití ModelBinderu naučit. A samozřejmě i ověřit, že tento přístup s použitím upraveného MVVM je stále funkční a vytvoření VM je možné i v ModelBinderu.

Těsně před koncem?

Tím se pomaličku dostávám ke konci tohoto příspěvku. Vím, že jsem neodpověděl na všechny otázky, které vyvstaly, ale toto určitě není poslední příspěvek na toto téma. Jistý podnět mám i ke komentářům v předchozím článku, které nabízeli možné řešení plugin modelu v asp.net MVC aplikaci. Toto řešení se mi nezdá úplně optimální a mám k němu jisté výhrady a určitě by se dala nalézt lepší implementace při použítí mnou navrženého modelu.

Diskuze

Jak jsem též v komentáři uvedl, budu rád, pokud se ozvete, ať už pomocí komentáře pod článkem nebo přes kontaktní stránku a projevíte zájem o možnou osobní diskuzi nad tvorbou MVC aplikací (nemusí se jednat jen o asp.net MVC implementaci). Každý podnět uvítám a určitě se najde prostor k zorganizování takové diskuze, kde může dojít ke sdělení a výměně poznatků.

6
Apr

Postřehy k asp.net MVC

Na chvíli se přesunu od mých oblíbenějších témat k tématu, které se v poslední době často přetřásá, a tím je použití MVC při tvorbě asp.net aplikací. Jelikož vývojáři dostali před poměrně nedávnou dobou k dispozici implementaci tohoto vzoru pro .net framework od MS, a to v jeho první verzi, určitě neuškodí, pokud se na něj podívám z praktického hlediska.

MVC model vývoje jsem při vývoji webové aplikace, nebo spíše prezentace použil již před nějakou dobou, kdy jsem nasazoval svoji verzi blogu. Postupně jsem pak přešel na použití Preview verzí asp.net MVC a následně jsem Beta verzi použil při komerčním vývoji jedné aplikace.

Již v době Preview verzí jsem však maličko zápasil s tím, jakou úlohu hraje v tomto přístupu Controller, který tvoří onu aktivní část. A právě Controller se při větších aplikacích poměrně rozrůstá, což se mi přestalo po nějaké době líbit a tak jsem se snažil najít způsob, jak mu, takříkajíc, odlehčit.

Související otázky

Zároveň s tím jsem začal řešit i několik dalších navazujících otázek. Na některé z nich jsem prozatím nenalezl odpověď, jiné se mi povedlo vyřešit s tím, jak byly přidávány nové vlastnosti.

Jednoduchý systém pluginů

Mezi jedny z hlavních nedostatků tohoto přístupu vidím horší možnosti implementací pluginů. Neříkám, že je to nemožné, a existuje několik pokusů, např. SubControllery, nebo metoda RenderAction. Stále to však není tak elegantní, jak to je možné například v klasických webforms.

CRUD vs Content page

Jinou úlohou pak může být případ, kdy potřebujete jednoduchou obsluhu pro správu modelu, pokud je Controller poměrně jednoduchý a využívá jen jeden, případně několik málo servisních objektů poskytujících data - záměrně nemluvím o repository, která se mi v ukázkách, které jsou v hojné míře k vidění, nelíbí. Přeci jen je občas potřeba s předanými daty ještě něco málo udělat, transformovat je, a až následně uložit. Myslím si, že tuto práci by však neměl vykonávat Controller jako takový, ale právě nějaká servisní vrstva dříve, než se data dostanou k repository objektu – v takovém případě jde vše celkem hladce a jednoduše. K opačnému pólu složitosti a nabubřelosti se však dostávám v okamžiku, kdy je potřeba vytvořit maličko složitější Content page, která se skládá z více datových objektů, které poskytují různé servisní objekty.

Analogie s desktop aplikacemi

V průběhu vývoje jsem se tak stále více dostával k otázkám, zda by nešlo využít dosavadních znalostí z vývoje desktopových aplikací a vhodnou formou je použít při vývoji asp.net MVC aplikace.

Jelikož se v poslední době zabývám především vývojem WPF aplikací a zde se poměrně dobře ujal vzor MVVM (Model – View – ViewModel) pokusil jsem se jít touto cestou.

Malé odbočení na vzor MVVM

Jedná se o poměrně mladý návrhový vzor, který využívá výhod WPF a to zejména při bindingu. Spadá pak do stejné “škatulky” vzorů, které vycházejí z principu MVC, obdobně jako třeba vzor MVP (Model View Presenter). ViewModel pak, zjednodušeně řečeno, poskytuje jak data Modelu samotná, tak i připravuje další data, která jsou využívána View pro prezentaci. View je v takovém případě pasivní, čehož je zejména u WPF dobře skloubeno s reakcí na události vyvolávana v Modelu, případně právě ViewModelu.

Jak jsem již uvedl, mé rozhodnutí bylo učiněno v souvislosti s analogií na desktopové aplikace, kde je přeci jen bohatší objektový model, proto si určitě nemyslím, že mé řešení může být za všech okolností to pravé a správné – ani nechci tvrdit, že je to přesně MVVM implementace vzoru, přeci jen je zasazen do jiného modelu, ale ona analogie zde byla.

Řešení pomocí MVVM

Postupně jsem se přes problémy dostal k nástinu možného řešení. Netvrdím, že bude všespásné, mě se však v současné chvíli líbí. Alespoň co se týká použití v asp.net MVC, samotné asp.net nebo-li webforms neberu v tuto chvíli v potaz, neboť mají jiný přístup a mnoho věcí se zde dá řešit jiným způsobem.

Mým cílem bylo:

  • odlehčit samotnému Controlleru
  • zároveň jsem nechtěl řešit logiku aplikace ve View, což je v mnohých ukázkách poměrně časté. Jedná se především o případy, kdy se testuje zda hodnota v modelu je právě taková, potom vypiš toto a jinak tamto
  • dalším požadavkem byla silná typovost ve View, to znamená žádné ViewData[klíč]
  • … další podružné věci na které si momentálně nevzpomenu

Jak tedy mé řešení vypadá:

Každé View má přiřazenu svoji třídu ViewModel, která je instancována až v dané akci Controlleru. ViewModel si následně obhospodařuje práci se servisními objekty, které mu poskytují data - Model. Odlišností od původního návrhu pak je, že ViewModel nereaguje přes události na View, ale tyto reakce jsou mu vnuknuty od Controlleru voláním metod.

Tím se mi podařilo docela vhodně eliminovat množství kódu v samotné akci Controlleru. Zároveň je tento ViewModel předán jako model do View, čímž je zajištěna silná typovost tohoto View přes vlastnost Model. Uvnitř třídy ViewModel je potom řešena logika pro zobrazování – nikoliv zobrazování samotné. Je třeba zde ještě zmínit, že ViewModel může poskytovat jako svoji vlastnost přístup k podřízeným ViewModelům, které jsou použity při konstrukci View. Zejména se jedná o případy, kdy je třeba předat data modelu do UserControlu.

Tento první nástřel možného řešení byl v první fázy dostačující, samozřejmě přišla i jistá úskalí, ale o těch zase příště.

3
Apr

I’m a PC and MVP

tak tímto sloganem a pokřikem byla zakončena oficiální část MVP Summitu 2009, které jsem se mohl jako MVP zúčastnit.

S první částí tohoto výroku ještě nejsem tak úplně sladěn :-), o to víc mě potěšilo, když se mi na apríla v mé emailové schránce opět objevila zpráva od Microsoftu, že jsem byl podruhé v řadě oceněn titulem Microsoft MVP pro Client Application Development a tak se naplnila i pro letošek druhá část výroku, což mě velice těší.

Byť je to ocenění za podporu komunity v uplynulém roce, a tak patří poděkování i Vám, že v této fajn komunitě mohu být a podporovat ji. Dívám se především na nadcházející rok.

Rok 2009

I nadále chci pokračovat v odpovědích na .net fóru o programování na builder.cz, stejně tak pak budou i nadále pokračovat neformální setkání účastníků (nejen) tohoto fóra. Určitě neskončila série online mikroseminářů, které jsou zpřístupněny i pro ostatní.

V nejbližší době se se mnou můžete osobně setkat na přednášce Představení .NET RIA Services a uvidím podle ohlasu, zda v obdobných akcích i nadále pokračovat. (Tak snad se bude líbit.) Taktéž chystám krátký seriál o WinForm aplikacích, které se sice pomaličku vytrácejí a zastiňuje je WPF, ale jsou stále v hojné míře používány. Nesmím ale zapomínat ani na WPF a jeho mladšího otce Silverlight – že vám to nedává smysl? – pak to někdy zkusím vysvětlit.

Co mě osobně toto ocenění přineslo je několik nových kontaktů a poznatků, něco málo nových informací, o některé z nich se pak s vámi rád podělím. A také motivaci do dalšího osobního rozvoje.

Publikováno pod: .net technology , personal