SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan...

72
Nummer 103 november 2009 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network www.sdn.nl IN DIT NUMMER O.A.: Snel en Schaalbaar met Velocity Distributed Cache < SQL Server Integration Services in de Praktijk < XML-Parsing in COBOL < Create and use of Google maps web part < MVP: Most Valuable Pattern? < SOFTWARE DEVELOPMENT NETWORK MAGAZINE 103

Transcript of SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan...

Page 1: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

Nummer 103 november 2009 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network

www.sdn.nl

IN DIT NUMMER O.A.:

Snel en Schaalbaar met Velocity Distributed Cache <

SQL Server Integration Services in de Praktijk <

XML-Parsing in COBOL <

Create and use of Google maps web part <

MVP: Most Valuable Pattern? <

SOFTWARE DEVELOPMENT NETWORK

MAGAZINE

103

Page 2: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

Advertentie Macaw

Page 3: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

magazine voor software development 3

ColofonUitgave:Software Development NetworkZeventiende jaargangNo. 103 • november 2009

Bestuur van SDN:Remi Caron, voorzitterRob Suurland, penningmeesterJoop Pecht, secretarisMark Vroom, vice-voorzitter

Redactie:Rob Willemsen ([email protected])

Aan dit magazinewerd meegewerkt door:Maurice de Beijer, Anko Duizer, PaulGielens, Christiaan Heidema, Marcel vanKalken, Stefan Kamphuis, Marcel Meijer,Mirjam van Olst, Johan Parent, Joop Pecht,Sandra de Ridder, Maarten van Stam,Bob Swart, Marianne van Wanrooij, RobWillemsen en natuurlijk alle auteurs!

Listings:Zie de website www.sdn.nl voor eventuelesource files uit deze uitgave.

Vormgeving en opmaak:Reclamebureau Bij Dageraad, Winterswijkwww.bijdageraad.nl

©2009 Alle rechten voorbehouden. Niets uitdeze uitgave mag worden overgenomen opwelke wijze dan ook zonder voorafgaandeschriftelijke toestemming van SDN. Tenzijanders vermeld zijn artikelen op persoonlijketitel geschreven en verwoorden zij dus nietnoodzakelijkerwijs de mening van het be-stuur en/of de redactie. Alle in dit magazinegenoemde handelsmerken zijn het eigen-dom van hun respectievelijke eigenaren.

AdverteerdersMacaw 2VNU 10Bergler 24Aladdin 29Avanade 364DotNet 44Sogeti 53Sybase iAnywhere 58Barnsten / Embarcadero 66Microsoft 72

Adverteren?Informatie over adverteren en de adverten-tietarieven kunt u vinden op www.sdn.nlonder de rubriek Magazine.

voorwoordIn de periode van de vallende bladeren, het natte wegdek, de laagstaande zon en de vierkantetreinwielen valt de laatste editie van het SDN-magazine van 2009 met een hart verwarmendeplof op je deurmat. Tijd genoeg om binnen te zitten en weer de volle 72 pagina’s tot je tenemen.Na de succesvolle Software Development Conference van oktober j.l., inclusief de Open-Force ’09 DNN-conferentie en de Developers Launch van Windows 7, en vóór het laatsteSoftware Development Event van 2009 – op 14 december in Houten – verwennen we je nogmet een 15-tal artikelen, variërend van de noodzaak van design van de user experience – inAndries van der Meulens artikel “Daarom User Experience Design!” - tot de broodnodigeaandacht die we als developers aan de dag (zouden) moeten leggen voor de beheerders vanal onze, ongetwijfeld prachtige, applicaties – zie “Monitoring” van Eric Denekamp - … wantzij kunnen maar weinig met een message-box met de melding “unknown error” en een Ok-button! Hoezo OK?!?

En er is nog meer aandacht voor de kwaliteitsaspecten van onze applicaties. Schaalbaarheidwordt b.v. in 2 artikelen behandeld. Roy Cornelissen kijkt hoe dat geregeld zal kunnen wor-den via Velocity’s Distributed Cache en Andre Boonzaaijer doet zijn verhaal over SchaalbareModellen. Ook voor security-aspecten is aandacht: Brandon Haynes praat in zijn “Under theHood’-reeks over de Security Services die je in DotNetNuke 5.1 terugvindt.Verbetering van de kwaliteit van een app kun je ook bereiken door niet het wiel opnieuw uitte vinden. Design patterns kunnen daar een goede rol bij spelen, zoals Marcel Peereboom laatzien in zijn eigen MVP-versie, die voor het Most Valuable Pattern.

Op het gebied van user interactie worden jullie o.a. voorzien door Dennis Vroegop die ingaatop de beginselen van development voor Surface: als je met z’n 4en rond die tafel staat is dattoch wat anders als dat je in je uppie met je eigen muis naar je eigen beeldscherm kijkt. Eenbelangrijke factor bij development voor Surface lijkt creativiteit: wie komt met het briljante ideevoor de nieuwe killer-app?Paul Keijzers laat in het artikel “Create and use of Google maps web part” zien hoe bezoe-kers van het Spaarne Ziekenhuis in Haarlem via een interactief kaartje kunnen zien bij welkehuisarts zij op zeker moment het beste/snelste terecht kunnen.

De resterende artikelen hebben allemaal wel een ‘data-link’. Johan Machielse kijkt naar “SQLServer Integration Services in de Praktijk” en Marcel Meijer blikt vooruit naar “SQL Azure”.Cary Jensen vervolgt zijn “Introduction to LINQ” van het vorige magazine, en Ann Lynnworthkijkt o.a. naar de performance van Firebird in haar artikel “Firebird SQL and Web Traffic Ana-lysis with Delphi”. Christiaan Heidema doet uit de doeken dat “XML-Parsing in COBOL” is op-genomen, en als gebruikers genereren wij die data vaak met behulp van een toetsenbord,misschien zelfs wel als een soort Hans Klok via “Het Magische Toetsenbord” van Peter vander Sman.

Veel leesplezier!rob willemsen,[email protected]

PS: Rest me nog te melden dat dit niet alleen het laatste magazine van dit jaar is … het is tevens

het laatste magazine dat onder mijn redacteurschap valt. Het is tijd voor iets anders, as simple as

that … er is – gelukkig! - nog zo veel uitdagends en interessants te beleven in de software-wereld.

Een bedankje mijnerzijds naar alle lezers en naar alle SDN-medewerkers, en ik hoop dat menigeen

met veel interesse en met veel plezier gelezen heeft in het SDN-magazine, en dat ook zal blijven

doen!

Page 4: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

SDN EVENT

14 DECEMBER 2009

HOUTEN

Inhoud03 VoorwoordRobWillemsen

04 Inhoudsopgave

05 Snel en Schaalbaarmet Velocity Distributed Cache

Roy Cornelissen

11 Firebird SQL and Web Traffic Analysiswith Delphi

Ann Lynnworth

17 Daarom User Experience Design!Andries van der Meulen

20 SQL Server Integration Services in de PraktijkJohan Machielse

25 ASP.NET onder de Motorkap:ASP.NET 4.0 op bezoek bij je browser

Michiel van Otegem

26 XML-Parsing in COBOLChristiaan Heidema

30 Surface developmentDennis Vroegop

35 Interesting Things:Writing Better Software Faster

Sander Hoogendoorn

37 Introduction to LINQ, part 2Cary Jensen

41 Under the Hood:Security Services in DotNetNuke 5.1

Brandon Haynes

45 Create and use of Google maps web partPaul Keijzers

50 DevTweet: Software Development with a winkMarianne vanWanrooij en Sander Hoogendoorn

51 Schaalbare modellenAndre Boonzaaijer

54 MonitoringEric Denekamp

56 SQL AzureMarcel Meijer

58 Boek Review: Handboek Silverlight 3Emile van Ewijk

61 MVP: Most Valuable Pattern?Marcel Peereboom

67 Het Magische ToetsenbordPeter van der Sman

Page 5: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

.NET Roy Cornelissen

Op veel grotere schaal, in de wereld van software development,krijgen we steeds meer te maken met gedistribueerde data enevent-driven applicaties. Gegevens zijn cruciaal voor applicaties omte functioneren, maar applicaties zijn door hun gedistribueerde enservicegeoriënteerde architectuur afhankelijk van vele schakels in deketen. Gegevens kunnen van diverse bronnen afkomstig zijn, zelfs vanexterne partijen. Soms moet je gegevens van verschillende bronnenaggregeren voor je er iets mee kunt. Ook kun je er niet altijd zeker vanzijn dat verbindingen voorhanden zijn. Of misschien heb je een SLAwaarbij je moet betalen voor het aantal calls dat je afneemt en is hetdus een kostenoverweging om het aantal aanroepen van services tebeperken. Denk ook aan offline scenario’s op smart clients, handhelddevices, enz. In een gedistribueerde en servicegeoriënteerdeomgeving ontstaat door al deze aspecten een behoefte aan een vormvan caching.

Er zijn gelukkig middelen die het ons steeds gemakkelijker maken omcaches te bouwen. De prijs van geheugenchips blijft dalen en doorslim gebruik te maken van meerdere computers kunnen wegedistribueerde caches bouwen op basis van goedkope hardware.Een gedistribueerde cache bestaat uit een verzameling computers diesamen één grote cache vormen. Doordat de cache verspreid is overmeerdere machines kun je profiteren van b.v. hoge beschikbaarheid(door kopieën van gegevens te verspreiden over meerdere computersen ze elkaars werk te laten overnemen als er een computer uitvalt) enhoge performance doordat de belasting van de machines wordtverdeeld over verschillende computers. Zolang je computers hebt metgeheugen en een netwerkkaart, kun je de gedistribueerde cacheblijven vergroten.

De performance van bekende community sites als Hyves en MySpaceof grote webwinkels als Amazon zou als een plumpudding in elkaarzakken als zij niet waren voorzien van grote gedistribueerde caches.

Wat stop je in een cache?Er zijn verschillende soorten gegevens die zich lenen om te cachenen waarbij ook verschillende scenario’s passen.

ReferentiedataDit zijn gegevens die niet vaak wijzigen maar wel heel vaak wordengeraadpleegd. Denk hierbij aan productgegevens in een product-catalogus of gegevens over reisverzekeringen van verschillendeverzekeringspartners. Stamtabellen voor landen, plaatsnamen,postcodes, etc., vallen ook in deze categorie. Meestal wordt aan dezegegevens een bepaalde geldigheidsduur meegegeven. Zolang dezeuiterste houdbaarheidsdatum niet is verstreken, kunnen dezegegevens in de cache blijven. Referentiedata lenen zich uitstekend omte cachen.

Activity dataHieronder verstaan we gegevens die geldig zijn terwijl een eindgebrui-ker bezig is met een gebruikerssessie. We noemen dit ook welconversational state. Een voorbeeld van activity data is de inhoud vaneen winkelwagentje dat een gebruiker aan het samenstellen is op desite van een internetwinkel. Deze gegevens bevinden zich meestalergens in de user interface / front end laag van een applicatie.In ASP.NET applicaties gebruiken we daarvoor vaak de Sessioncontainer. Pas na afloop van een transactie komt activity data in eenof andere vorm definitief in een backendsysteem, database of servicete staan. Het winkelwagentje uit het voorbeeld wordt dan omgezet ineen order. Activity data wordt vaak geschreven en gelezen, maaralleen binnen de context van één gebruiker. Deze gegevens moetendaarom worden gekoppeld aan die ene gebruiker. Voorbeeldenhiervan zijn de session state, cookies of de viewstate in ASP.NETapplicaties.

Resource dataDit zijn gegevens die vaak worden gelezen en geschreven doormeerdere gebruikers of applicaties. Bijvoorbeeld de beschikbarevoorraad van producten in een magazijn. Bij iedere bestelling moetendeze gegevens worden bijgewerkt en ze moeten altijd beschikbaarzijn. Hier is dus een sterke koppeling met de achterliggendegegevensbron en deze gegevens moeten doorlopend met elkaar inde pas worden gehouden. Caching is in deze gevallen vooral een

magazine voor software development 5

Snel en Schaalbaar met

Velocity Distributed CacheIn het hart van je computer vind je de processor en het interne geheugen. Deze onderdelen horen bijde computerarchitectuur die is vernoemd naar John von Neumann, een beroemd wiskundige encomputergeleerde. Eén van de onhebbelijkheden van deze architectuur is de “Von Neumannbottleneck”: doordat het geheugen zich “op afstand” van de processor bevindt en veel data kanbevatten, ontstaat er een grote hoeveelheid verkeer op de relatief smalle verbindingsweg tussen dietwee onderdelen. Dit leidt tot opstopping en vertraging. Deze flessenhals wordt in computers deelsopgeheven door een buffer tussen de twee onderdelen te plaatsen: de cache.

De ”Von Neumann bottleneck” is(deels) op te lossen via caches

De performance van bekende commu-nity sites als Hyves en MySpace ofgrote webwinkels als Amazon zou alseen plumpudding in elkaar zakken alszij niet waren voorzien van grotegedistribueerde caches

Page 6: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

MAGAZINE6

.NET

middel om snelheid te krijgen bij het raadplegen, maar het risico isgroot dat de gegevens in de cache verouderd zijn. De besteperformance krijg je door de cache zo dicht mogelijk bij de applicatiete leggen, b.v. door de cache in-process te draaien of op dezelfdemachine.

Gedistribueerd cachen met VelocityMicrosoft is een project gestart met de code naam Velocity uitgaandevan de eerder genoemde trend in applicatiearchitectuur en demogelijkheden die de hardware ons biedt. Velocity levert eengedistribueerde cache die in veel verschillende scenario’s inzetbaar is.Het product is nog volop in ontwikkeling en is momenteel als CTP3beschikbaar. Wanneer versie 1.0 beschikbaar komt is nog onduidelijk.In de rest van dit artikel ga ik in op de eigenschappen van VelocityCTP2 en waar je rekening mee moet houden als je het product wiltinpassen in je architectuur.

Velocity is dus een gedistribueerde cache. De filosofie die Microsofthanteert is die van een bundeltje computers waarvan de internegeheugens aan elkaar worden gesmeed tot één grote cache diebeschikbaar is voor de applicatie. Vanuit de applicatie gezien benaderje één logische cache, Velocity zorgt voor lastige zaken als hetverdelen van gegevens over een heel cluster. Hiermee zorgt Velocityvoor failover, hoge beschikbaarheid, schaalbaarheid enzovoort.In de huidige opzet is Velocity een cache-aside, wat betekent dat decache niet meer is dan een grote silo voor gegevens. De applicatiebepaalt zelf wanneer objecten in de cache moeten worden gezet ofwanneer ze moeten worden ververst. Velocity heeft zelf dus geen weetvan wat de applicatie doet of wat er in de cache wordt opgeslagen.

Wat kan er allemaal in Velocity worden opgeslagen? Eigenlijk allegegevens, zolang ze serializable zijn: .NET objecten, DataRows, XMLen byte arrays. De reden waarom ze serializable moeten zijn is dat zeproces- en machinegrenzen oversteken. Met serializable bedoel ik datze moeten zijn voorzien van het Serializable attribuut of de DataCon-tract en DataMember attributen.

In zijn kleinste vorm kan Velocity ook worden ingezet als een in-pro-cess cache. Dit heet een local cache. Velocity draait dan in het procesvan je applicatie mee. De hoeveelheid gegevens die Velocity in de localcache stopt heeft dan wel direct invloed op het geheugengebruik vande applicatie. Een local cache kun je ook combineren met eenvolledig cache cluster. Gegevens die je opvraagt vanuit het cachecluster worden dan gebufferd in de local cache. Velocity werkt meteen fallback mechanisme: het controleert of objecten in de local cachestaan. Alleen wanneer dat niet het geval is, zal Velocity het cachecluster aanspreken. De eerstvolgende keer staan de gegevens wel inde local cache. Omdat de local cache in het proces van de applicatiemeedraait, hoeven objecten niet te worden geserialiseerd engedeserialiseerd. Het werkt daardoor zeer snel, maar het zorgt er welvoor dat de applicatie zelf meer geheugen gaat gebruiken.

De opbouw van een cache clusterIn de gedistribueerde cache van Velocity praten we over een aantalonderdelen: de cache zelf, hosts, clusters en regions. Figuur 1 toonthoe de verschillende onderdelen met elkaar in verbinding staan.

Een cache host is een proces dat (een deel van) een cache beheert envormt een apart te beheren onderdeel van de gedistribueerde cache.Een host is meestal gekoppeld aan één fysieke machine, maar erkunnen best meerdere hosts draaien op één computer.Een cluster is een logische verzameling van hosts en van één ofmeerdere caches. Een cluster als geheel is ook weer een eenheid van

beheer. Zo kun je een cluster in zijn geheel stoppen en starten. Je kuntde omvang van je cache beïnvloeden door er hosts aan toe te voegenof eruit te verwijderen.Een cache wordt gevormd door het geheugen van de hosts binneneen cluster te combineren en er een logische naam aan te koppelen.Door die naam wordt het een ‘named cache’. Er kunnen meerderenamed caches in een cache cluster bestaan. De naam levert nietsmeer op dan een context voor je applicatie. Zo kunnen een order- eneen salesapplicatie gebruik maken van hetzelfde cachecluster en zelfsdezelfde sleutels gebruiken voor hun data, maar doordat de cache inbeide gevallen een eigen naam heeft, ontstaat er geen verwarring.Vergelijk het met de namespace van XML documenten. Zoals de figuural aangeeft, is een cache uitgesmeerd over de hosts in het cluster.

Binnen een cache kun je nog een opdeling maken in regions. Eenregion gebruik je om gelijksoortige gegevens te bundelen, vergelijk-baar met een tabel in een database. Je kunt dan, behalve de sleutelvoor een object, ook meer informatie aan je data koppelen in de vormvan tags. Je kunt daardoor tag based zoeken, b.v. naar alle objectenmet de tag “Dieselauto”. Velocity koppelt zo’n region wel aan éénbepaalde host, dus je kunt dan niet profiteren van het feit dat Velocityde gegevens verdeelt over de verschillende hosts ten behoeve van deschaalbaarheid. Velocity kan overigens wel regions als geheelrepliceren voor failover doeleinden.

Door een cluster op te bouwen uit verschillende hosts en daar eencache overheen te “projecteren” kan Velocity een cache leveren met

Velocity is een Silo van serializable data

Fig. 1: Schematische weergave van de Velocity onderdelen

FabricHet fabric clustering protocol is een populaire technologie in de netwerk-wereld. Het is een protocol dat zorgt voor het beheer van group member-ship van hosts binnen een cluster, het automatisch detecteren dat er hostsworden toegevoegd of verwijderd. Het zorgt voor schaalbaarheid en be-schikbaarheid en voorkomt een single point of failure doordat data wordtgerepliceerd naar andere nodes. Daarnaast levert het routing tables omeen verzoek van de client door te verwijzen naar de juiste host binnen eencluster.Microsoft heeft Fabric geïmplementeerd en beschikbaar gesteld als eenverzameling .NET assemblies. Deze zijn op dit moment onderdeel van deVelocity CTP2 download.

Page 7: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

magazine voor software development 7

.NET

een hoge beschikbaarheid en failover. Deze twee doelen bereiktVelocity door gegevens slim te verdelen over de hosts en vervolgenste repliceren. Mocht er een node uitvallen, dan is er altijd nog een hostdie een kopie van de gegevens beschikbaar heeft.Doordat er onbeperkt hosts kunnen worden toegevoegd aan eencluster, zelfs terwijl een cluster draait, is Velocity enorm schaalbaar.Het beheren van het cluster gebeurt in Velocity op basis van hetFabric Cluster Management protocol (zie kader). Voor het beheren vande clusters en hosts krijg je een beheertool op basis van WindowsPowerShell.

Velocity past goed op je spullenIn een gedistribueerde omgeving zullen er meerdere applicaties zijndie gebruik maken van de cache. Denk aan een web farm waaropdezelfde web applicatie meerdere malen is uitgevoerd. Ook meerderelagen binnen een applicatie kunnen gebruik maken van dezelfdecache. Doordat de cache vanuit verschillende bronnen kan wordengevuld met data en weer worden uitgelezen, is het belangrijk datVelocity zijn cache goed bewaakt.Bij het beheren van de cache waar meerdere partijen gebruik vanmaken komen eigenlijk dezelfde aspecten aan bod als bij “traditioneel”gegevensbeheer, namelijk constistency, concurrency en beveiliging.Specifiek bij caching is ook een goed beheer van geheugenbelangrijk.

ConsistencyConsistency in Velocity betekent het gelijk houden van de gegevensdie verspreid en gerepliceerd zijn over de verschillende hosts binnenhet cluster. Je kunt kiezen voor twee modellen: weak consistency ofstrong consistency. Bij strong consistency is een operatie omgegevens in de cache te stoppen of te wijzigen synchroon: de opera-tie is pas klaar als de gegevens succesvol zijn gerepliceerd naar allehosts in het cluster. Als je het niet zo belangrijk vindt om te weten ofeen object wel in de cache is opgeslagen, dan kun je kiezen voor hetweak consistency model. In het weak model gebeurt het wegschrijvenen repliceren van gegevens in de cache asynchroon. Dit kan je veelsnelheidswinst opleveren als je vaak gegevens in de cache schrijft,doordat je niet telkens hoeft te wachten totdat alle gegevens succes-vol over alle hosts in het cluster zijn verspreid. Wanneer het weg-schrijven van de gegevens mislukt door een onvoorzien probleemterwijl je daar niet van op de hoogte bent, moet je er in je applicatie welrekening mee houden dat objecten niet per se in de cache staan enje hierdoor mogelijk vaker misgrijpt als je om objecten vraagt.Velocity ondersteunt in CTP2 alleen nog het synchrone model (strongconsistency).

Concurrency en beveiligingBij resource data heb je mogelijk te maken met gegevens die doorverschillende clients worden gewijzigd. In deze gevallen is het prettigdat Velocity de concurrency bewaakt. Net als in een database kun jekiezen tussen optimistic en pessimistic locking. Bij optimistic lockinggebruikt Velocity wat extra metadata in de vorm van een versie-nummer. Een update op de gegevens in de cache lukt dan alleen alsje ook het juiste versienummer van die data hebt. Heeft iemand andersdat nummer in de tussentijd opgehoogd, dan zal de wijziging falen.In het pessimistic locking scenario leg je expliciet een lock op hetobject in de cache en kan alleen de houder van het lock de gegevenswijzigen en het lock weer vrijgeven.Het is wel belangrijk om te beseffen dat Velocity geen transacties overmeerdere items heen ondersteunt. In een pessimistic lockingscenario moet de applicatie goed de volgorde van acties en het leg-gen van locks bewaken om deadlock situaties te voorkomen. Velocityheeft zelf geen deadlock detectie, dus dat moet je in de applicatieverzorgen.Velocity doet in CTP2 nog niets aan beveiliging. Objecten worden nogniet beveiligd tegen ongeautoriseerde toegang en er is ook nog geen

moeite gestoken in b.v. het coderen van gevoelige gegevens. Hoewelje je moet afvragen of het verstandig is om gevoelige gegevens tecachen, moet je er dus wel rekening mee houden dat deze objectenin het geheugen van je computer kunnen zijn geladen. Ze zouden doorkwaadwillenden kunnen worden uitgelezen. Het Velocity team werktmomenteel aan een model voor security. De ideeën lopen uiteen vaneen systeem met ACL’s (Access Control Lists) of het gebruik van een

simpele sleutel per region of object. In de afweging wordt vooralgekeken naar een goed evenwicht tussen beveiliging en goedeperformance.

GeheugenbeheerEerder werd al genoemd dat Velocity een cache-aside is. Dit betekentdat de applicatie verantwoordelijk is voor het beheer van de gegevensin de cache: de applicatie bepaalt of gegevens nog geldig zijn enwanneer ze moeten worden vervangen.Velocity zorgt echter wel voor efficiënt geheugenbeheer en houdtdaarbij rekening met de kaders die je stelt bij het aanmaken van eengedistribueerde cache. Deze kaders worden uitgedrukt in tweestrategieën: expiration en eviction.Expiration gaat over de geldigheid van gegevens. Je kunt aangegevens een bepaalde levensduur (time-to-live) meegeven. Wanneerdeze levensduur is verstreken, zal Velocity de gegevens verwijderen uitde cache.Het verwijderen van items hangt nauw samen met eviction. Eviction ishet verwijderen van cache items op basis van een Low en een HighWatermark. Als je een cache aanmaakt, kun je een low en een highwatermark als kaders opgeven. Deze watermarks zijn een soortbarometers die bepalen wanneer Velocity moet gaan opruimen. Delow watermark geeft aan bij welk geheugengebruik Velocity moetbeginnen met opruimen van items waarvan de levensduur is verstre-ken. Als de high watermark is bereikt, dan gaat Velocity objecten op-ruimen ongeacht de levensduur. Bij deze laatste vorm van evictionverwijdert Velocity wel als eerste de objecten die het langst niet zijngebruikt. Dit gaat op basis van het least-recently-used (LRU)algoritme.

Als je in je oplossing gebruik maakt van expiration en/of eviction, danis het dus belangrijk om je bewust te zijn van het gedrag dat Velocitydan vertoont. Bij caching in zijn algemeenheid kun je er niet altijd vanuitgaan dat gegevens ook daadwerkelijk beschikbaar zijn in de cacheen je applicatie is ervoor verantwoordelijk dat ontbrekende gegevensworden aangevuld of ververst. Het Velocity team heeft wel toekomst-plannen voor het automatisch aanvullen van de cache op het momentdat objecten niet (meer) in de cache zitten.

Hoe gebruik ik Velocity?Grofweg zijn er twee manieren waarop je Velocity kunt inzetten in jeapplicatie: als een expliciete cache-aside en voor sessiemanagementin webscenario’s. In het eerste geval heb je een client API terbeschikking waarmee je objecten in de cache kunt stoppen of eruitkunt halen. Voor sessiemanagement heeft Velocity een provider. Als jeVelocity wilt inzetten als sessionstate-provider, dan is het wel belang-rijk de cache die je daarvoor gebruikt zodanig te configureren dat ses-sies niet zomaar verloren gaan. Denk daarbij aan het eerderbeschreven eviction en expiration gedrag. Eviction zal moeten

“Traditioneel” gegevensbeheer,zoals constistency, concurrency enbeveiliging, is nog steeds belangrijkin de cache

Page 8: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

MAGAZINE8

.NET

worden uitgeschakeld. Verder kan het handig zijn de standaardexpiration van 10 minuten te verhogen naar bijvoorbeeld een half uur.Sessiegegevens zijn belangrijk, dus het aanzetten van de highavailability eigenschap van Velocity is in dit geval ook een goed idee.Dit alles doe je via de PowerShell beheertool met de opdracht inlisting 1.

Set-CacheConfig –CacheName MijnSessionCache

–Eviction none –TTL 30 –Secondaries 1

Listing 1: Cache configureren voor session state via PowerShellbeheertool

Bovenstaande opdracht schakelt eviction uit (“-Eviction none”), stelt deexpiration periode in op 30 minuten (“-TTL 30”) en schakelt highavailability in (“-Secondaries 1”). Als je eviction uitschakelt, loop je welde kans dat het geheugen volloopt, omdat objecten niet meer wordenopgeruimd tenzij de houdbaarheid verloopt.

Om CTP2 te kunnen gebruiken moet je referenties maken naar tweeDLL´s: CacheBaseLibrary.dll en ClientLibrary.dll. Deze vind je nainstallatie in %PROGRAMFILES%\Microsoft Distributed Cache\v1.0.

Listing 2 laat zien hoe je toegang krijgt tot de cache en welkemethodes je onder andere kunt aanroepen om de data in de cache temanipuleren. In het eerste deel van de code wordt de cache-clientgeconfigureerd. De code geeft aan met welke cache-host hijcommuniceert, dat het een simple client is en dat de local cacheingeschakeld is. Je ziet dat hier expliciet de naam van een cache-hostwordt opgegeven. Er is altijd één host die je als eerste aanspreekt omtoegang te krijgen tot de cache, maar de Velocity infrastructuur zorgtervoor dat je ook bij de andere hosts binnen het cluster uitkomt als datnodig is.

//--------------------------

// Cache client configureren

//--------------------------

//We communiceren met 1 cache host

ServerEndPoint[] servers = new ServerEndPoint[1];

//Cache Host Details

// Parameter 1 = host name

// Parameter 2 = cache port number

// Parameter 3 = cache service name

servers[0] = new ServerEndPoint("localhost",

22233, "DistributedCacheService");

//Routing of Simple Client

// False = Simple Client (geen routing table)

// True = Routing Client

bool routingClient = false;

//Local cache of niet

// True = Wel local cache

// False = Geen local cache

bool localCache = true;

//Geen logging van cache exceptions

CacheFactory.DisableLogSinks();

//Configuratie meegeven aan CacheFactory constructor

myCacheFactory = new CacheFactory(servers,

routingClient, localCache);

//Vraag de "default" cache op

myDefaultCache = myCacheFactory.GetCache("default");

//----------------

// Cache gebruiken

//----------------

//Maak een region aan in de cache

myDefaultCache.CreateRegion("DemoRegion", true);

//Zet objecten in DemoRegion, beiden met twee tags

//Widget is een class met DataContract en DataMember attribu-

ten

Tag[] tags = new Tag[] { new Tag("lifestyle"),

new Tag("work") };

myDefaultCache.Add("DemoRegion", "key1",

new Widget("Widget101"), tags);

myDefaultCache.Add("DemoRegion", "key2",

new Widget("Widget102"), tags);

//Zoeken op tags

List<KeyValuePair<string, object>> results =

myDefaultCache.GetAnyMatchingTag("DemoRegion",

new Tag[] { new Tag("work") });

foreach (KeyValuePair<string, object> kv in results)

{

Console.WriteLine(kv.Key + ": " +

((Widget)kv.Value).Name);

}

//Zet een waarde buiten een region

myDefaultCache.Add("key2", "Testwaarde2");

//Zet een waarde via indexer

myDefaultCache["key3"] = "Testwaarde3";

Listing 2: Gebruik van Velocity vanuit code

Je hoeft de cache-client niet altijd vanuit code te configureren. Dat kanook in de App.config. Listing 3 geeft een voorbeeld van dezelfdeconfiguratie als in het C# codevoorbeeld, maar nu in App.config.

<configuration>

<configSections>

<section name="dcacheClient"

type="System.Data.Caching.DCacheClientSection,

CacheBaseLibrary"

allowLocation="true"

allowDefinition="Everywhere"/>

</configSections>

<!-- Simple client -->

<dcacheClient deployment="simple">

<!-- Local cache staat aan -->

<localCache isEnabled="true"

sync="TTLBased"

ttlValue="300" />

<hosts>

<!-- Cache host configuratie -->

<host name="localhost"

cachePort="22233"

cacheHostName="DistributedCacheService"/>

</hosts>

</dcacheClient>

</configuration>

Listing 3: Configuratie van Velocity in App.config

Page 9: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

magazine voor software development 9

.NET

De eigenschappen van Velocity, zoals het schaalbaar, gedistribueerden highly available zijn, hebben ook voordelen in webapplicaties diedraaien in grote webfarms. In ASP.NET heb je voor sessiemanage-ment de keuze uit in-process, SQL Server of een State Server.ASP.NET gebruikt daarvoor een provider model, waardoor je gemak-kelijk kunt wisselen zonder de applicatie te hoeven aanpassen. SQLServer en State Server zijn de opties die je overweegt wanneer jeapplicatie flink is opgeschaald en draait op meerdere webservers,zeker als je geen sticky routing toepast. Bij sticky routing wordtdezelfde gebruiker voor ieder request telkens door dezelfde webserver bediend.

Nu we de kracht van Velocity kennen, zou het handig zijn ook meteenhier het sessie-management te beleggen. Dat kan, want Microsoftlevert een ASP.NET sessionstate-provider op basis van Velocity.Listing 4 toont hoe je deze kunt configureren.

<!-- Overige configuratie weggelaten voor duidelijkheid -->

<sessionState mode="Custom" customProvider="Velocity">

<providers>

<add

name="Velocity"

type="System.Data.Caching.SessionStoreProvider"

cacheName="MijnSessionCache"/>

</providers>

</sessionState>

Listing 4: Configuratie van session state provider op basis vanVelocity

Afwegingen voor configuratieVelocity kun je in verschillende configuraties toepassen. Welk scena-rio past nu het best bij datgene wat je wilt bereiken? Tabel 1 geeft eenoverzicht van de effecten die een bepaalde configuratie met zichmeebrengt.

Tabel 1: Verschillende configuraties en hun effecten

De configuraties in tabel 1 kunnen worden gecombineerd. Je kunt duseen gepartitioneerde cache maken die highly available is. Het verliesaan performance door high availability te gebruiken kun je compen-seren door een local cache toe te passen.

Een kijkje in de toekomstDe CTP’s tonen al een aardig werkend product. Maar er zijn nog zakenwaar het team aan werkt. Naast het continu verbeteren van de schaal-baarheid en snelheid wordt gekeken naar betere manieren om decache te monitoren voor diagnose van problemen. Verder staan voorversie 1.0 de volgende zaken op de planning:

1. Notificaties vanuit de cache bij wijzigingen in objecten, zodat clientshierop kunnen anticiperen;

2. Beveiligde toegang tot named caches;3. Bulk operaties met meerdere objecten;4. Read thru/write behind ondersteuning.

Configuratie Effect Positief Negatief

High availability Hogere garantie dat gegevens beschikbaar zijn en blijven, ook bij uitval van een host.

Negatief effect op performance doordat Velocity kopieën van gegevens op meerdere hosts moet bijhouden.

Gepartitioneerde cache

Betere performance doordat gegevens worden verdeeld over het cluster en daardoor ook de belasting van de cache hosts. Hierdoor ook een grotere scale.

Als een cache host uitvalt, verlies je die gegevens. Deze moeten dan opnieuw in de cache worden gezet.

Local cache Hoge performance doordat local cache binnen de applicatie draait en objecten niet hoeven te worden geserialiseerd/gedeserialiseerd.

Kleine overhead door fallback mechanisme. De applicatie verbruikt meer geheugen.

Roy Cornelissen

Roy Cornelissen werkt als ITarchitect bij Info Support voor debusiness unit Industrie. Hij heeftnegen jaar ervaring in de ICT enheeft gewerkt aan uiteenlopendeprojecten. In zijn dagelijks werk pasthij Microsoft technologie toe inservice georiënteerde omgevingen.

De read thru/write behind ondersteuning is er één die een beetje tegende cache-aside filosofie indruist. Read thru betekent dat de cacheautomatisch terugvalt op een back-end service of database wanneereen object niet kan worden gevonden in de cache. Write behind houdtin dat Velocity een wijziging in een item in de cache (asynchroon)doorstuurt naar de back-end. Hiermee wordt Velocity meer dan eencache-aside, namelijk de spil tussen applicatie en gegevensbronnen.Persoonlijk ben ik benieuwd naar de manier waarop Microsoft dit gaatoplossen. Ik denk dat een uniforme toegang tot gegevens hiervoornoodzakelijk is, dus ik verwacht rechtstreekse koppelingen met SQLServer tabellen of REST style interfaces zoals als die van ADO.NETData Services.

Op de roadmap staan verder nog zaken als het ondersteunen vanLINQ queries op de cache en Velocity in the cloud. Deze zaken zullenwaarschijnlijk na versie 1.0 aan Velocity worden toegevoegd. Op dezemanier is Microsoft bezig om technologieën, die op zichzelf al nuttigzijn, op een slimme manier te combineren.

ConclusieIn een gedistribueerde applicatie, waar gegevens uit meerdereheterogene bronnen afkomstig zijn, is caching bijna onmisbaar.Het zorgt voor snellere toegang tot data, betere beschikbaarheid engrotere schaalbaarheid. Er zijn meerdere oplossingen op de marktmaar Velocity is een veelbelovende nieuwe speler. Het is gratisbeschikbaar als losse release naast het .NET framework.Velocity is veelzijdig doordat het in uiteenlopende scenario’s inzetbaaris, van een in-process cache tot volledig gedistribueerd en highlyavailable en zelfs als session state provider voor ASP.NET.

NB: Dit artikel is gebaseerd op de CTP2. Op dit moment is CTP3beschikbaar en is CTP4 onderweg. Ten opzichte van CTP2 bevatCTP3 meer mogelijkheden, hier komen we later op terug.

Referenties• Velocity team blog: http://blogs.msdn.com/velocity• Voorbeeld code: http://code.msdn.microsoft.com/velocity• Velocity whitepaper:http://msdn.microsoft.com/en-us/library/cc645013.aspx

• PDC 2008 Sessies (waaronder over Velocity):https://sessions.microsoftpdc.com •

Visual Studio 2010 TIP:Visual Studio 2010: VAR & IntellisenseJe kunt nu gebruik maken van het VAR type. Deze wordt alcompile time vervangen door het juiste datatype.Nadeel hiervan was, dat je deIintellisense moest ontberen. InVisual Studio 2010 is er nu full Intellisense support voor VARs.

Page 10: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

Advertentie VNU

Page 11: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

DELPHI Ann Lynnworth

• You can also find out how much traffic is coming from peopleversus from software robots. (One typical example of a "bot" isGooglebot, the "spider" used by Google to "crawl" the "web" forkeywords, etc.) If you are doing any type of search engineoptimization, such as displaying pages slightly differently to webrobots than to humans, it can be vital to detect new bots as theycome out.

• If you want to verify whether an advertiser is really sending you thetraffic that they claim to be sending you, especially if you arepaying on a per-click basis, running accurate queries is essential.

These are only a few of the reasons that people wish to have somestrong tools for viewing and analyzing web traffic logs.

Microsoft IIS offers an ODBC option for logging the data directly to aSQL database. So I tried that first, with Firebird ODBC. That idea hadTwo Big Problems:1. I could not make it work;2. In ODBC-mode, IIS only saves a few fields, not the full extended list

of fields.This led to the idea of building a utility to import the .log data into aFirebird database. Microsoft SQL has a bulk import feature; Firebirdoffers importing from so-called "external files". This external filefeature was to be the basis of the utility.

magazine voor software development 11

Firebird SQL and Web Traffic Analysis

with DelphiWhether you want to learn how to efficiently import data into Firebird, or you wonder if it is worthupgrading to Delphi 2010 for "routine" tasks, this article will give you some food for thought.In particular, this article explores the use of Delphi and the open-source relational databasesystem named "Firebird SQL" to load and analyze web traffic logs. Along the way, the size andperformance of EXEs compiled with Delphi 7 versus Delphi 2010 are compared, plus the speedof Firebird 1.5 versus Firebird 2.1 and four common Firebird data access components aremeasured. Fortunately, there are worldwide standards governing the format of web traffic logfiles. So, if you have a web site that logs traffic data (on any operating system), there is a verygood chance that the solution discussed in this article will apply to your situation. We have(so far) tested log files from IIS 5 on Win2000 and IIS 6 on Win2003, with various data fieldsincluded and excluded. The FBPrepLog utility described in this article is free, with ObjectPascal source, and is available immediately from Code Central thanks to Embarcadero (look foritem #27086). An early version of FBPrepLog is also on the Delphi 2010 Companion DVD.The source definitely compiles in Delphi 7 and in Delphi 2010; it probably compiles in allversions in between. All SQL code in this article probably works with Interbase but was onlytested with Firebird.Quick Background on Web Traffic LogsPicture a typical moment in your favorite web browser, just as you goto a web site, and focus on the address bar. The address starts HTTPor HTTPS, right? When you make a web request, an HTTP server,somewhere, processes your request and sends an answer-documentthat appears in your (client-side) software. Leaving all the complexityaside, that is how it works: request, process, response. It even worksthat way when you check the train schedule using your iPhone.

For each request, the HTTP server usually writes an entry in a webtraffic log to record which file was requested, by whom, whether therequest was successful, and so on. Whether those log files constitutea violation of your privacy is another long story which, althoughfascinating, is outside the scope of this article!

If you are the owner or webmaster of a web site, you might look at thetraffic log files using anything from Notepad to Firebird to a glossyweb-stats package to learn what surfers are doing on your web site.Here are some examples of reasons for studying web traffic logs:

• You can find out about errors on your site, including invalid links.Stop link rot!

Ordinarily, Windows-based webmas-ters use Microsoft SQL Server to storeand query their IIS web traffic logs, butwhat if you are using Apache, or wouldsimply prefer to use Firebird SQL?

In addition to having fun, I also wantedto quantify the relative speed of twodifferent versions of Delphi, two diffe-rent versions of Firebird, and severaldifferent data access components

Page 12: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

MAGAZINE12

DELPHI

Any difficulty?If you have not looked at a web traffic .log file lately, you might bewondering what could be so difficult about importing its contents intoa database. Surely in 2009, this must be a simple software task!The two main difficulties are:1. The .log file contains comment rows and data rows, and we only

want to import the data;2. The list of fields can vary within the file, whenever the comments

indicate a structure change.

To make these difficulties more clear, look at a minimalist .log file (fromhttp://msdn.microsoft.com/en-us/library/ms525807.aspx) with somecomment rows , starting with #, then one data row, and then morecomments to indicate a structure change and one final data row.

#Software: Internet Information Services 6.0

#Version: 1.0

#Date: 2009-05-02 17:42:15

#Fields: time c-ip cs-method cs-uri-stem sc-status

cs-version

17:42:15 172.16.255.255 GET /default.htm 200 HTTP/1.0

#Software: Internet Information Services 6.0

#Version: 1.0

#Date: 2009-05-02 17:44:00

#Fields: time c-ip cs-method cs-uri-stem sc-status

cs-version cs(User-Agent)

17:44:00 172.16.255.255 GET /default.htm 200 HTTP/1.0

Mozilla/5.0+Ok

Listing 1: Minimal IIS Log File where #Fields comment definesstructure of following data

Stripping out the comment fields can be done in many ways, includingusing the free utility named PrepLog from Microsoft. However, makingthe importer cope with a structure that can vary an unlimited numberof times per document is a bit more challenging.In web traffic log files, the data fields are delimited by a single space.Data strings, such as the user agent*, where you might ordinarilyexpect spaces, have those spaces translated to a plus ('+') symbolby the http server software prior to logging.(*: The "user agent" is the name of the http client software used bythe user - commonly a web browser such as Firefox, Opera orInternet Explorer. Finding a user agent of "Mozilla/5.0+Ok" in a log filecould mean that a person was there using Firefox, or it could meansthat some other http client was there, hoping that your web site wouldgive it content as-if it were Firefox. Zie http://en.wikipedia.org/wiki/Mozilla.)

The GoalIf all goes well, we will end up with the web traffic data in a table, ina Firebird database. In figure 1 you can see some of the fields, asdisplayed by the IB_SQL utility:

Fig. 1: IB_SQL shows some of the IISLOGS table after FBPrepLogdid the import

The question is, how quickly can we import the data? Does it matterwhich Delphi compiler we use, or which data access components?Can we measure a difference between Firebird SQL v1.5 and v2.1?And how exactly does one use the External Files feature?

Our Example Log FilesThe examples discussed here use log files generated by IIS 6 on Wind-ows 2003, in Extended log format, made daily, with some but not alloptional fields included.We have also tested the import of log files made by IIS 5 on Win2000.For testing, we used more than 60 log files, totaling more than 1/2 GBof data, courtesy of traffic data from Earth Wave Records, ranging fromJuly 4th to early September 2009. The web application behind the sitewas written with Delphi 7 and WebHub. The site uses the ISAPI filterfrom HREF Tools named StreamCatcher to, among other things,adjust the IIS log files on the fly so that the Session ID (without anyrandom portion) can be readily parsed out by FBPrepLog or humaneyes. The particular log file used for all the performance tests was from31-Aug-2009 and it size was 12,680 kb.

Runtime EnvironmentAll tests were done on inside a VirtualBox (with thanks to WebCentreLtd in New Zealand, who allowed us to run tests on one of theirbackup servers).

Table 1: Runtime Environment

Firebird Installation NotesThe tests started with the installation of Firebird-1.5.5.4926-3-Win32.exe, using default options with these minor adjustments on thelast page of choices:

[ ] Use the Guardian

[ ] Start Firebird automatically

[x] Install Control Panel Applet

[x] Copy Firebird client library

[x] Generate client library as GDS32.DLL

To test the newest Firebird, I uninstalled Firebird 1.5 and theninstalled the Firebird-2.1.2.18118_0_Win32.exe file, again usingdefault options.After installing Firebird, the firebird.conf file MUST be adjusted per thenotes in the readme-fbpreplog.rtf file. Otherwise, your output whenrunning FBPrepLog will look like this:

Preparing external LOGBLOCK #0...Created table...ExceptionAccess to external file "C:\FBPREPLOG\___LOGBLOCK___0"is denied by server administrator

Listing 2: Oops - forgot to modify firebird.conf to grant access toexternal files

Reset Between TestsOf course it is helpful to reset the starting point prior to each test. Thereset-test BAT file stops the Firebird service, copies an emptydatabase to the official location and restarts Firebird. Note that theempty database file does NOT include the table which will hold thedata; that is created on the fly by FBPrepLog.

Virtualizer Sun VirtualBox v3.0.4 Host OS Windows 2003 Standard Guest OS Windows XP Pro with SP3Guest RAM 512 KB Guest Disk 10MB drive C Guest CPU 1ble 1: Runtime Environment

F

Page 13: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

magazine voor software development 13

DELPHI

CD /D c:\FBPrepLog

net stop FirebirdServerDefaultInstance

copy IISLOGS.empty.fb2.fdb iislogs.fdb

net start FirebirdServerDefaultInstance

Listing 3: A BAT file to reset things between tests

Test ResultsThe test results cover two areas: size and speed.

Size of FBPrepLog.exeThe following table illustrates how much variation there is in the size ofthe FBPrepLog.exe depending on the type of components used andthe compiler used:• IBX is the built-in Interbase Express driver provided with Delphi;• IBO refers to the TDataSet-derived version of Interbase Objects,where all components are named TIBO*;

• IBO Native refers to the version of Interbase Objects which des-cends from TComponent, where all components are named TIB_*;

• dbExpress refers to the new Firebird driver provided with Delphi2010.

Table 2: Size of EXE depending on data access components andcompiler

To better understand where the "size" comes from, we can look at theunits linked in depending on the test:

program fbpreplog; {Firebird SQL "prep log" utility}

{$APPTYPE CONSOLE}

{$DEFINE TESTIBX} {any Delphi, test Interbase Express}//{$DEFINE TESTDBEXPRESS} {for Delphi 2010, test dbExpress}//{$DEFINE TESTIBO} {test TIBOQuery, www.ibobjects.com}//{$DEFINE TESTIBONATIVE} {test native TIB_Query}

//{$DEFINE HREFTOOLS} {to support ZaphodsMap configuration}

usesSysUtils, DateUtils,

{$IFDEF TESTDBEXPRESS} // dbExpressDBXFirebird,SqlExpr,WideStrings,

{$ENDIF}{$IFDEF TESTIBX} // Interbase Express

IBDatabase,IBCustomDataSet,IBQuery,

{$ENDIF}{$IFDEF TESTIBO} // IBObjects

IB_Components, IBODataSet,{$ENDIF}{$IFDEF TESTIBONative} // IBObjects Native

IB_Components,{$ENDIF}{$IFNDEF TESTIBONATIVE}

DB, // TDataSet used by most access components

{$ENDIF}{$IFDEF HREFTOOLS}{*htns*}ZaphodsMap,

// for advanced, flexible configuration{*htns*}ZaphodsMapMessages,{*htns*}ZaphodProjectOptions,{*htns*}NativeXml,{*htns*}uCode,

{$ENDIF}Classes;

Listing 4: Units used in FBPrepLog DPR

Speed of FBPrepLog.exeEach type of test was run at least three times and the average speedis reported here. The slowest speed is 4 minutes 41 seconds and thefastest is 1 minute 22 seconds.

Table 3: Results of Timing Tests

Unfortunately, table 3 does not include any Delphi 2010 test resultsfor IBO nor IBO Native because those components were not availablefor that compiler at the time of testing. Based on the results withDelphi 7, it seems reasonable to expect IBO's performance in Delphi2010 to be very similar to IBX and dbExpress.In any case, the speed differences among data access componentsis quite small. My guess is that this is because most of the time isspent (a) having the OS write the external file and (b) having Firebirdbulk-import. Remember, in FBPrepLog, we are using a very small, raresubset of the data access component's capabilities. Therefore thesetiming results are not indicative of overall performance; that wouldrequire different tests.

Highlights from the Source CodeThe FBPrepLog utility is made from one source code file, FBPre-pLog.DPR, with no additional PAS files. There are just under 900 linesof code. Some highlights follow.To understand the "engine" inside FBPrepLog, you will need somereference to the data structures, which follow in listing 5:

constcUtilVersion = '1.0.1.4';LogFieldDBEquivalent:array[0..29] ofarray[0..2] of string =(('time', 'fieldTime', '10'),

// ('Field in IIS Log-file', 'Equivalent tofield('time')

// in Firebird database').// 'Field' prefix avoids reserved-words.

('c-ip', 'fieldCIp', '20'),// snip

('cs(User-Agent)', 'fieldcsUserAgent', '2048'),('cs(Cookie)', 'fieldcsCookie', '2048'),('cs(Referer)', 'fieldcsReferer', '2048'),('cs-username', 'fieldCsUsername', '40'),

Delphi 7 IBX 405 kb IBO (TIBO*) 1159 kb IBO Native (TIB_*)

965 kb

Delphi 2010 IBX 827 kb dbExpress 1420 kb ble 2: Size of EXE depending on data access components and compiler

Delphi 7 Delphi 2010 IBX IBO IBO Native IBX dbExpress

Firebird 1.5 4min 41sec 4min 5sec 4min 11sec 2min 30sec 2min 36sec Firebird 2.1 3min 25sec 3min 1sec 2min 58sec 1min 23sec 1min 22sec

The speed improvement from Delphi 7to Delphi 2010 is quite significant,and Firebird 2.1 is definitely faster thanFirebird 1.5

Page 14: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

MAGAZINE14

DELPHI

// snip('sc-substatus', 'fieldScSubstatus', '40'));

AdditionalFieldsCount = 8;LogDBAdditionalFields:array[0..1] of

array[0..AdditionalFieldsCount - 1] of string =(('cs-uri-query', 'sessionid','session=', '&', '15', '', '+', ''),// SessionId placed in log-field "cs-uri-query". Value// placed after string "session=" and before delimiter "&"// This feature is for WebHub sites.

('cs-uri-stem', 'lingvo', '', '', '15', '#', '+','/eng#/fra#/rus#/spa#/deu#/ita#/nld#/jpn#/chi')

//# is delimiter//+/- is to include/exclude// erwrwe#cxvx - delimited string, erwrwe// and cxvx are items// This feature is for any site with translated sub-sites);

LogBlockMaxSize = 15000;

typeTLogBlockData = record

Date: string;Index: Integer;Fields: TStringList;FieldsLengths: TStringList;

end;TLogConfiguration = record

dbPath: string;dbUsername: string;dbPassword: string;dbTableName: string;

end;

TFBImportIISLog = classprivate

FLogFile: TStringList;FLogBlock: TStringList;FLogBlockData: TLogBlockData;FLogConfiguration: TLogConfiguration;FdbFieldNames: TStringList;FdbAdditionalFieldNames: TStringList;

publicconstructor Create;destructor Destroy; override;procedure LoadConfiguration;function PrepareLogsExternalTable(InFilename,

OutFilename : string;var BlockStart: Integer): Integer;

procedure ImportLogBlock(Filename: string);

publicproperty BlockIndex: Integer read FLogBlockData.Index;property LogTableName: string

read FLogConfiguration.dbTableNamewrite FLogConfiguration.dbTableName;

end;

var{$IFDEF TESTDBEXPRESS}

LogsDatabase: TSQLConnection;LogsTransaction: TObject = nil; // not used

{$ENDIF}{$IFDEF TESTIBX}

LogsDatabase: TIBDatabase;LogsTransaction: TIBTransaction;

{$ENDIF}{$IF Defined(TESTIBO) or Defined(TESTIBONATIVE)}

LogsDatabase: TIB_Connection;LogsTransaction: TObject = nil; // not used

{$IFEND}

Listing 5: Data structures and essential variables

The database location, log table name, user name and passwordparameters all have default values. These values can be overriddenby command line parameters.The type of components needed to connect to the database andmanage the external file import vary by test. At the end of listing 5,you can see how TSQLConnection is used in Delphi 2010 with dbEx-press, whereas TIBDatabase is used with the IBX components whichare available in older versions such as Delphi 7.When I compile with the {$DEFINE HREFTools} active and link inZaphodsMap, etc., I can use XML files to configure the same details.That is helpful for me because I have to organize FBPrepLog importprocesses for many servers. If you are interested in advancedconfiguration, see TFBImportIISLog.LoadConfiguration in the sourceand pay a visit to the ZaphodsMap web site.The function TFBImportIISLog.PrepareLogsExternalTable transformsthe data in the .log file into another file which is suitable for bulk-importinto Firebird.The procedure TFBImportIISLog.ImportLogBlock does the "real work",and it includes the definition of all the SQL that is used for all steps inthe process. Some steps are optional (such as creating the IISLOGStable, which may already exist). Please see the FBPrepLog.dpr file ifyou are interested in how this works -- look for procedure TFBImpor-tIISLog.ImportLogBlock. Listing 6 shows certain key lines in bold toshow the overall flow.

procedure TFBImportIISLog.ImportLogBlock(Filename: string);

//snip

case SQLId of

1:

//snip

12: begin

Clear;

Add('CREATE TABLE ' + 'Temp' + ‘ EXTERNAL FILE ''' +

Filename + ''' ');

//snip

14: begin

Clear;

Add('INSERT INTO ' + LogTableName + ' (');

//big snip

try

GetSQL(1, SQL); // step 1

Open;

TableExists := not Eof;

Close;

//snip -- code for creating table, trigger, generator

GetSQL(14, SQL); // step 14

ExecSQL;

//snip

Transaction.Commit;

//snip

GetSQL(11, SQL); // step 11

ExecSQL;

//snip

LogsDatabase.Connected := False;

//snip

Listing 6: ImportLogBlock

The rest of the FBPrepLog source code (other than ImportLogBlock)is involved with (a) showing usage syntax in case someone needs tosee the parameters allowed before running it, (b) looping as neededwhen importing all files in a directory and (c) timing the importprocess.

Data MiningTo get a rough idea of the amount of traffic by day, we can use thequery shown in listing 7. This includes requests by humans and webrobots.

Page 15: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

magazine voor software development 15

DELPHI

SELECT a.FIELDDATE, count(a.ID)

FROM IISLOGS a

group by a.FIELDDATE order by a.FIELDDATE

Listing 7: Query count of requests by date

FlameRobin or IB_SQL (or a custom Delphi application) can be usedto display the results. If FlameRobin is used, some reassuring infor-mation is displayed while the query runs, as shown in the figure below.

Fig. 2: FlameRobin shows status info prior to running the query

To find out whether we have any bad links on the site, we can searchfor hits where the status code is 404 (file not found). Of course, someof those hits will probably be from hackers trying to get in by tryingvulnerable resources which yield access on some systems. In figure 3,you can see some of these "rotten links" and who has them (theReferer is the URL which led to the request).

Figure 3: FlameRobin shows invalid requests and who sent them

To count the number of links from Google, we can count the hits wherethe referer starts with http://www.google.com (and that will includegoogle.co.jp which is relevant for this web site).

On a site that uses WebHub or for any reason includes a session id inthe URL, we can follow people (anonymously) and find out whichpages they view, and from that perhaps we can determine whichpages to improve. The example shown in figure 5 helps us focus onhits from people who were sent by Google, to find out whether theystayed around to view more than 1 page after arriving. The SQL is abit interesting and is shown in listing #8. The substring function is usedbecause the SessionID field is varchar(128) and only the first 15characters are signficant. (Yes - we have shortened that field sincetaking these screenshots.)

Fig. 5: FlameRobin shows result of query checking whether peoplearriving from Google "stick" on the web site

If this query is run on a site and shows mostly 1's in the Count column,that would indicate that arriving surfers did not immediately see whatthey wanted, and they did not feel like following any links within thesite. If these had been paid (adwords) links from Google, this wouldindicate an expensive problem, because all those click-throughs wouldrepresent wasted advertising.

select B.FIELDDATE,

Substring(B.SESSIONID from 1 for 15) as SESSIONIDCUT,

count(B.ID)

from IISLOGS B,

(

select A.FIELDDATE,

Substring(A.SESSIONID from 1 for 15) as SESSIONIDCUT

from IISLOGS A

where (A.SessionID > '1001')

and (A.fielddate >= '2009-09-01')

and (A.FIELDCSREFERER STARTING WITH 'http://www.google.')

) GOOGLERS

where (SUBSTRING(B.SESSIONID FROM 1 for 15) =

GOOGLERS.SESSIONIDCUT)

and (B.FIELDDATE = GOOGLERS.FIELDDATE)

group by B.FIELDDATE, SESSIONIDCUT

order by B.FIELDDATE, SESSIONIDCUT

Listing 8: Nested query to count hits on the same session numberfor GooglersFig. 4: FlameRobin shows people arriving from Google

Page 16: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

MAGAZINE16

DELPHI

This is just a sampling of the data mining that is possible once thedata is in a database. Different sites have different requirements, andit is possible for anyone to do their own analysis if they are willing toput in the effort to figure out the query syntax. The SQL KnowledgeBase compiled by IB Phoenix was helpful to me while I worked on thequeries shown here.For low-traffic sites, you might not need any queries. Simply havingthe traffic in an organized format makes it possible to read throughthe entries and see important patterns. If you have a do-it-yourselfsite, that might be sufficient.

Quick Tips• For prototyping queries, consider installing both FlameRobin andIB_SQL. They each have their strengths.

• Use the fastest machine available for Firebird SQL. Log databasesbecome large quickly and you will save yourself a lot of time by usinga fast machine.

• If you decide to use FBPrepLog, test it once on a relatively small.log file and review the resulting IISLogs table. Then, go back to thesource code and consider changing some of the field names to beshorter (easier to type and recognize), and consider making somefield lengths shorter. Then, recreate an empty database and startusing FBPrepLog daily or hourly.

• If you have other data transformations that you would like toaccomplish during import (such as tracking the lingvo in its own fieldrather than just in the uristem), study the code which fills in theSessionID and Lingvo and use that as a basis for your owncustomizations.

Enjoy!

International Character SetsThe examples in this article used English web sites and URLs. It is

possible, with IIS6 on Win2003 and later, to log requests using UTF8,allowing for many important non-western lingvos.The FBPrepLog utility would need to be modified to support UTF8.The logic within the external file processing would need to change,and importantly, when you create the Firebird database to hold thetraffic data, you would have to specify the charset as "UTF8", ratherthan "None." Both IB_SQL and FlameRobin make it easy to selectthe charset when the database is first created.It is very likely that by the time you read this article, the coding changeswill be complete and included in FBPrepLog as posted on CodeCentral.

Products and Other Things Worth FindingTo find any of the products or services mentioned in this article, pleasesee table 4. All URLs were valid as of September 3, 2009.

ConclusionWere you surprised to find so little difference in speed between thedata access components? I certainly was, until I realized that the wholepoint of doing a bulk import is that the Firebird engine does all thework, rather than the components.Finding out that Delphi 2010's compilation of the same source code(e.g. the "IBX" test) led to an EXE that was larger, yet 45% faster, wasa wonderful outcome and has convinced me to start recompiling all myutilities with Delphi 2010.Finding out that Firebird 2.1 was faster the 1.5 was not a surprise,although I was glad for the confirmation. Now I need to chase downmy last remaining copies of Firebird 1.5 and get them all upgraded!Thank you very much for reading this article, and please considerdonating at least $10 to Firebird Foundation if you use FBPrepLog.

Grazie. Danke sehr. Merci. Gracias. Dank u! •

Product URL Notes FBPrepLog Source

cc.embarcadero.com Use of Code Central is free as long as you have registered with the Developer Network. Look for item #27086.

Firebird SQL www.firebirdsql.org/index.php?op=files Free, open-source Firebird Foundation

www.firebirdsql.org/index.php?op=ffoundation&id=contributions

Any $ donation will be appreciated and invested per priorities which are open to discussion and community input.

Delphi 2010 www.embarcadero.com Not free; talk to your local Embarcadero sales rep for upgrade pricing and deals.

Firefox www.mozilla.com/en-US/firefox/all.html

Free; available in many lingvos

FlameRobin www.flamerobin.org Free admin and query tool Hosting www.webcentre.co.nz Colo server IB Objects www.ibobjects.com Interbase Objects components

(free eval; trustware license) IB_SQL www.ibobjects.com/ibo_ib_sql.html Free admin and query tool IIS6 enable UTF8

www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/bea506fd-38bc-4850-a4fb-

Topic: Log File Formats in IIS (IIS 6.0)

Table 4: Product Placement

Ann Lynnworth

Ann Lynnworth was born nearBoston, Massachusetts USA at theright time to catch the informationtechnology wave. In 1978, shefound she could not resist learningto program fancy macros for Word-Perfect, and she has never been af-raid to pick up a manual and/orguess her way into a new techno-

logy. She started her "Software Doctor" consulting business in1983 on Apple's early computers, published WordStar at YourFingertips, wrote Situation Analyst for the IBM PC, helped createRonstadt's Financials and then joined XL/Proteus to learn all aboutParadox and a bit about SQL.

Skipping ahead to 1994, Ann learned Delphi and soon co-foun-ded HREF Tools and has worn many hats with the internet toolscompany, the most enjoyable of which was producing “Tech TalkRadio” for several years for WebHub customers. A dynamic spea-ker with an unusual point of view, Ann has had rave reviews fromattendees in training seminars and at technical conferences. Annholds an associate art's degree from Simon's Rock College anda bachelor’s degree in psychology from Wellesley College, also inMassachusetts.

e3a0379d321f.mspx?mfr=true Knowledge Base

www.ibphoenix.com Use [Search KnowledgeBase] link, bottom-left of home page, for excellent information about many aspects of Interbase and Firebird SQL

Mozilla en.wikipedia.org/wiki/Mozilla History lesson Opera www.opera.com/mini/download Alternative to the alternative. RFC for logs www.rfc-editor.org/rfc/rfc2616.txt Defines standard for web traffic

.log files StreamCatcher www.streamcatcher.com Commercial ISAPI filter for

remapping; can modify IIS logs on the fly.

Vintage vinyl records

www.earthwaverecords.com Supplied the traffic logs

Virtual Box www.virtualbox.org Free, open-source... from Sun Warehousing and Distribution

www.csweb.biz Courier Services co-sponsored the development of FBPrepLog to help the Firebird Foundation

WebHub www.href.com/webhub Commercial product; a web development framework for Delphi for sites that are to be translated, skinned or otherwise deployed repeatedly.

ZaphodsMap www.ZaphodsMap.com Free, open-source, configuration subsystem from HREF Tools

Page 17: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

UX Andries van der Meulen

Wat is het?User Experience, of UX in het kort, is de wetenschap over hoe eenpersoon een systeem ervaart en gebruikt. In dit artikel richt ik mijvoornamelijk op UX van software applicaties. Dit varieert van mobieleapplicaties tot tablet-, desktop- en webapplicaties. Als je hetvervolgens over User Experience Design hebt, of UXD in het kort, danga je actief nadenken over wat de best mogelijke manier is om dieapplicatie door de eindgebruiker te laten “ervaren”.UX designers zijn voortgekomen uit verschillende rollen uit de 80erjaren. Destijds waren het voornamelijk mensen met een achtergronddie niet in de techniek lag, met bijvoorbeeld de naam UsabilityEngineers. In de loop der jaren zijn deze rollen geëvolueerd en is hetmeerdere specialisaties gaan kennen. Grafisch en interactie-ontwer-pers, bouwers van prototypen, mensen die gespecialiseerd zijn in hettesten met eindgebruikers, integratiespecialisten en de meer recentverschenen “Persuasion Architect”. Ze houden zich onder anderebezig met ergonomie, informatiedichtheid, navigatie, schermopbouwen de werkomgeving van de gebruikers.Helaas is het in veel projectmethoden nog steeds niet gestandaardi-seerd. Maar dit is aan het veranderen. Er zijn steeds meer bedrijven diehiervoor ondersteuning bieden. Maar wat in de meeste situatiesgebeurt is dat opdrachtgevers van het gebruik van UXD afzien, omdatniemand ze het voordeel van de “investering” heeft vertelt. Daarom ishet tijd om aan te geven waarom je dit nou juist wel wilt.

Waarom wil je het?De voordelen van het gebruik van UXD zal ik uitleggen aan de handvan de Application Lifecycle Management cirkel. Dit iteratief proces isonderverdeeld in drie delen. De eerste is “Business”, waar de functio-naliteiten worden bepaald. Daarna komt “Development” waarbij deapplicatie gebouwd en getest wordt. Als laatste is er “Operations”.Hier wordt o.a. de applicatie ondersteund in het gebruik. Van het laat-ste onderdeel kan vervolgens de applicatie worden uitgefaseerd, of erwordt teruggegaan naar “Business” om de cirkel te herhalen.

Fig. 1: Application Lifecycle management

magazine voor software development 17

Daarom

User Experience Design!Hieronder staan 4 argumenten waarom je als opdrachtgever UXD wilt.

1. Business - Verbeterde requirementsAls je UX wilt gebruiken in je project, is het verstandig dit te doenvanaf de eerste stap, door het toevoegen van wireframes,interface design, interaction design, rapid prototyping en eindge-bruikerstesten. Er wordt een betere dienst aan de opdrachtgevergeleverd omdat je nu kunt laten zien wat ze kunnen verwachten.Het is inderdaad een extra investering en zal vermoedelijk debusiness periode verlengen. Maar wanneer dit goed wordtgeïmplementeerd zal de toegevoegde waarde direct zichtbaarworden bij de volgende fase van het project. De ontwikkeltijdwordt verkort en daarmee de ontwikkelkosten.

2. Development - Versnelde “Time-to-market”Omdat de kwaliteit van de documentatie en specificaties isverbeterd, wordt de ontwikkeltijd gereduceerd. Er zullen minderwijzigingen op het laatste moment nodig zijn en de kans dat eronvoorziene fouten worden gemaakt is een stuk kleiner. Testenzal sneller en beter gaan, vanwege de duidelijke specificatie die alvooraf beschikbaar was.Door dit alles kun je sneller een applicatie uitbrengen. Sterker nog,naar mate het projectteam meer ervaring krijgt, wordt de extra tijdin de requirementsfase gecompenseerd door de snellereontwikkeltijd.

3. Operations - Toegevoegde waarde per gebruikerWanneer de applicatie is uitgerold, zullen de gebruikers beter ensneller kunnen werken en daarbij minder fouten maken. Deapplicatie is speciaal ontworpen en opgezet voor hun behoeftenen hun manier van werken. Nieuwe medewerkers zullen mindertijd nodig hebben om de applicatie te leren, omdat een applicatiemet een intuïtieve User Experience zichzelf uitlegt. Over hetalgemeen kun je zeggen dat het geleverde werk per gebruikertoeneemt.

4. Operations - Verlengde levensduur applicatieDe levensduur van een applicatie neemt toe wanneer deze perfectaansluit op de werkmethoden van de gebruiker. Deze zal danminder snel klagen, minder workarounds hoeven te gebruiken endaardoor minder snel aansturen op vervanging.

Naast de argumenten voor de opdrachtgever, staat hieronder waaromhet binnen het projectteam ook toegevoegde waarde heeft.

1. UXD bij ontwikkelingDoor het verbeterde functioneel en technisch ontwerp zullen er inde architectuur minder wijzigingen en fouten voorkomen. Hiermeeverkort je de volledige ontwikkeltijd. Het ontwikkelteam werkt metduidelijke en getoetste specificaties waardoor er een beter beeldis waarnaar wordt toegewerkt. Technisch wordt er een beterekwaliteit gehaald en onduidelijkheden zijn al in een vroeg stadiumweggenomen.

Page 18: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

MAGAZINE18

UX

UXD in de ontwikkelfase werkt het best met de volgende drierollen; de designer, de ontwikkelaar en iemand die daartussenstaat, een zogenaamde integrator. De designer zorgt voor deinteractie en interfaces. De ontwikkelaar maakt de interne werkingvan het systeem. De integrator kent beide kanten van de applica-tie en kan zodoende het proces sturen zodat het werk van dedesigner en ontwikkelaar goed op elkaar aansluit.

2. Visuele terugkoppeling opdrachtgeverÉén van de belangrijkste zaken is hoe je communiceert met deopdrachtgever. Met UXD kun je naast tekst ook met beelden dewensen en eisen omschrijven. Het biedt de mogelijkheid te zienwat het wordt voordat het klaar is. Door het tekenen van wire-frames, het maken van een interactie- en interface-ontwerp, enbouwen van prototypen met de voorgestelde functionaliteit, is erde mogelijkheid om een betere indruk te geven dan wat met tekstalleen mogelijk is. Daarbij bied je een handvat aan de opdracht-gever om duidelijker eventuele wijzigingen door te geven. Het ismakkelijker aan te geven hoe, waarom en waar iets moet wordenveranderd. En als er daarbij gebruik wordt gemaakt van proto-typen, kunnen alle vooraf ontstane aannames worden voorkomen.Daarbij wordt ook gelijk getest of het voorgestelde idee werkt inde praktijk.

Fig. 2: Interaction Design

Fig. 3: Wireframe example

Wanneer gebruik je het?User Experience Design wordt toegepast op het moment dat erdirect of indirect gebruikers bij het eindproduct betrokken zijn. Voor

het beste resultaat zul je voor elke mens-machine interactie actiefmoeten nadenken hoe dit gebeurt en hoe je het kunt optimaliseren.Met de huidige technieken zijn er weinig restricties om zo’n mens-machine interactie zodanig uit te ontwikkelen dat het perfect kanaansluiten bij de werkzaamheden van zijn eindgebruikers.Uiteraard moet je een gezonde afweging maken in de mate van hettoepassen. Voor kleinere projecten met relatief weinig eindgebruikersis de toegevoegde waarde van een uitgebreid onderzoek ook een stukminder. Hierbij kun je er voor kiezen om alleen op basis van feedbackvan een uitgerolde applicatie verbetering aan te brengen. Initieel eenzo’n goed mogelijk product opleveren, maar waarbij je uitgaat dat erregelmatig nieuwe versies worden gelanceerd.

Op het moment dat het product door veel mensen gebruikt gaatworden, en waarbij de beschikbare tijd van de eindgebruiker vanbelang is, is het ‘t absoluut waard om UXD vanaf het begin toe tepassen in het project.

Wat is het niet?Waarschijnlijk doen veel mensen onbewust aan UXD. Ze denken naover een product dat goed aansluit bij de wensen van de gebruikers.Echter doordat ze hier niet bewust mee bezig zijn of omdat ze ookvaak een andere agenda hebben, komt het UXD gedeelte nooitvolledig tot zijn recht. Voor een stukje bewustwording gebruik ik de 10meest voorkomende misvattingen over UXD die Whitney Hess (UserExperience Designer in New York) heeft samengesteld.

1. UXD is niet alleen User Interface DesignAlhoewel de User Interface (of UI) het meest herkenbare is van degebruikerservaring, is het slechts een onderdeel van UXD. Hoeinformatie getoond wordt en hoe mensen ermee communicerenis ongelofelijk belangrijk, maar UXD gaat veel dieper. Het is debasis voor de gehele applicatie en daarmee ook de UI.

2. UXD is niet één stap in het procesHet is iets waar je continu mee bezig moet blijven. Bij iedereiteratie neem je de ervaringen mee, en wordt er opnieuw gekekenwaar en of je kunt verbeteren. UXD is niet een stap die je kuntafronden, het moet samenvallen in alles wat je in het project doet.

3. UXD gaat niet over techniekUser Experience gaat niet over techniek, maar over hoe mensenleven, werken, hun dingen doen en alles wat daarmee te makenheeft. Techniek is daarbij een middel, maar geen doel.Net zoals schilders hun verf gebruiken om te communiceren,gebruiken User Experience Designers beschikbare techniek ommensen te helpen hun doel te bereiken. Het primaire doel is danook om mensen te helpen en niet om de beste, mooiste of laat-ste techniek te gebruiken.

4. UXD gaat niet alleen over bruikbaarheidDe bruikbaarheid van een product verhogen is erg belangrijk, maarUXD gaat ook over gedrag. Je gebruikers moeten het productwillen gebruiken. Het moet aantrekkelijk zijn en rekening houdenmet leerbaarheid en emoties. Een goede manier om dezeaspecten weer te geven is Peter Morville’s UX honeycomb.

5. UXD gaat niet alleen over de gebruikerDe U van UXD staat voor “User”. Het staat centraal in dezemethodologie. Maar deze eindgebruiker is niet het enige waar

UXD is de toegevoegde waarde bijapplicatieontwikkeling dat het verschilgaat maken in de nabije toekomst

Page 19: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

UX TIP:jQTouchiPhone applicaties maken maar geen zin om met Objective-Caan de slag te gaan. Het kan ook met HTML en JavaScript!Kijk eens naar jQTouch dat de kracht van HTML 5, jQuery enJavaScript combineert om iPhone applicaties te maken.En ze kunnen zelfs offline werken. Zie http://www.jqtouch.com/voor meer info.

magazine voor software development 19

UX

Fig. 4: Honeycomb

rekening mee gehouden moet worden. UXD gaat namelijk overde zoektocht naar de beste combinatie van gebruikerservaringmét de business doelstellingen. Het is namelijk wel de bedoelingdat de applicatie bedoeld is om werk mee te verrichten. Daar-naast moet er ook rekening gehouden worden met bedrijfsspeci-fieke onderdelen zoals bijvoorbeeld de interne werkprocessen ende huisstijl.

6. UXD is niet prijzigHet gebruiken van UXD in je project hoeft niet veel te kosten. Elkeproject is afhankelijk van beschikbare mensen, mogelijkheden, tijden geld. Daarop moet worden aangesloten en bepaald worden inhoeverre je UXD kunt gaan toepassen. Het is onverstandig om erdirect bij het eerste project volledig voor te gaan. Probeer hetstapsgewijs in te voeren, zodat op gegeven moment het eenstandaard in de projecten wordt.

7. UXD is niet makkelijkHelaas is het niet zo dat één methode alle antwoorden biedt voorhet ontwerp. De grootste valkuilen zijn dat je aannames doet overhoe je eindgebruiker werkt. Het kost tijd om ze te leren kennen.Samen kun je vervolgens, op iteratieve wijze, komen tot het besteontwerp. Daarbij wil je de juiste mensen gebruiken om diebehoeftes te faciliteren.

8. UXD is niet de rol van één persoon of afdelingBinnen een project is het niet aan één specifieke persoon of eenbepaalde groep om met UXD het product succesvol te maken.Iedereen moet hier aan meewerken.Echter omdat rollen en methodes nog niet gestandaardiseerd zijn,is het nu lastig hier volledig vorm aan te geven. Als je het niet kuntbenoemen wordt het moeilijk hiervoor expertise aan te trekken. Erkomt hier echter wel meer duidelijkheid in. Meer rollen wordenalgemeen erkend en krijgen daarmee ook de verantwoordelijk-heden binnen het UX ontwerp. Maar voor een succesvol product,zal elk projectlid mee moeten doen met User Experience Design.

9. UXD is niet één disciplineAfhankelijk van het product zijn er meerdere expertises nodig. Ditis ook van toepassing op UXD. Voor een webshop werk je naareen totaal andere gebruikerservaring dan bij een systeem vooreen helpdesk. Hiervoor heb je ook mensen met andere expertises

nodig. Net als dat je voor een gebroken voet niet naar de cardio-loog gaat. Je kunt niet verwachten dat alle UXD professionals vooralle expertises een antwoord hebben.

10. UXD is niet een keuzeIk kan het me niet voorstellen dat een bedrijf bewust kiest vooreen slecht UX ontwerp. Maar het gebeurt onbewust. Het is eenrisico. Daarbij beschouwen helaas nog steeds veel bedrijven UXDals een toevoeging, niet als een basisbehoefte. Wanneer je hetverschil moet maken met de concurrentie, is UXD essentieel.Techniek zal op den duur het verschil niet meer maken,aangezien elk bedrijf kwalitatief op hetzelfde niveau komt door decontinue ontwikkelingen van de frameworks. Het is daaromessentieel om nu te gaan werken om UXD binnen de projecten tekrijgen om straks het verschil te maken.

ConclusieUser Experience Design is niet de rol van één persoon of afdeling. Hetis een bewustwording dat het volledige team ondersteund voor eenoptimaal functionerend resultaat voor opdrachtgever en eindgebrui-kers. Je zorgt voor volledigere en getoetste requirements waarmeebeter wordt gecommuniceerd, waardoor ontwikkeltijd wordt verkort,waar de applicatie meer oplevert tijdens operatie, en waarbij er eenverlengde levensduur is voordat het uitgefaseerd kan worden. UXD isde toegevoegde waarde bij applicatieontwikkeling die het verschil gaatmaken in de nabije toekomst.

Referenties• 10 Most Common Misconceptions About User ExperienceDesign, 9 Januari 2009, door Whitney Hess,http://mashable.com/2009/01/09/user-experience-design/ •

Andries van der Meulen

Andries knows a lot about thepresentation side of applications.He works regularly with subjects asgraphical and interaction design formany different customers andprojects. He also is a (certified)developer and knows multipleprogramming languages.

By knowing both sides, he has the rare combination of creativityand logic. This regularly places him in the position of an integra-tor, which stands between designer, developer, requirementsengineer and architect.

Page 20: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

DATABASES Johan Machielse

Standaard bouwblokkenBij het maken van een SSIS-applicatie heeft de ontwikkelaar eenaantal standaard bouwblokken tot zijn beschikking. Een SSIS-solution bestaat uit één of meerdere uitvoerbare packages met daarinde functionaliteit om het ETL-proces te kunnen bouwen.Deze functionaliteit bouw je op met tasks en pijlen die de flow tussentasks aangeven. De structuur van de package wordt beschreven inde control flow en het werkelijke inlezen, transformeren en laden vande data gebeurt in de data flow. Connection managers zijn deverbinding tussen een bron of doel en worden door de tasks gebruiktom data in te lezen resp. weg te schrijven. Je kunt de packagesconfigureren met zgn. package configurations, en je kunt gebruikmaken van event handlers voor het afhandelen van verschillendegebeurtenissen.

SSIS voorbeeldapplicatieDe voorbeeldapplicatie in dit artikel verzamelt elke week de kosten diezijn gemaakt voor de verschillende projecten binnen een bedrijf.Projecten worden uitgevoerd op diverse locaties in de wereld, waar-door kosten in verschillende munteenheden worden uitgedrukt.De manager van het bedrijf wil elke week een rapport hebben waarinalle projectkosten gesommeerd zijn uitgedrukt in euro’s. De wekelijksekosten van alle projecten worden aangeleverd in een CSV bestandmet meerdere regels per project. SSIS genereert hier een rapport vanwaarin de projectkosten per land en per project gegroepeerd zijn.

Fig. 2 : Schematische weergave van de SSIS voorbeeldapplicatie

Fase 1: ExtractIn de eerste fase van het ETL-proces leest de package de brondatain. SSIS kan de brondata van verschillende soorten bronnen lezen,zoals een externe SQL Server database, een SAP-systeem of in onsgeval een CSV-bestand. De data die het ETL-proces inleest, moetbetrouwbaar zijn voor het doel en dus is het belangrijk om de

MAGAZINE20

SQL ServerIntegration Services in de PraktijkSQL Server Integration Services (SSIS) is deMicrosoft implementatie voor ETL (Extract,Transform, Load) waarmee je complexedata-integratie- en transformatie-oplossingenkunt bouwen. Met behulp van de BusinessIntelligence Development Studio (BIDS) kan deontwikkelaar met standaard bouwblokken eenenterprise oplossing bouwen. Dit artikelbeschrijft de belangrijkste bouwblokken vanSSIS, gevolgd door een beschrijving van deverschillende fasen van het ETL-proces aan dehand van een voorbeeldapplicatie. Daarna zaler een greep gedaan worden uit een aantalpraktijksituaties waar je als SSIS ontwikkelaarmee te maken kunt krijgen.

Fig. 1 : Overzicht van SQL Server Integration Services

Een ETL-proces bestaat uit Tasks enpijlen die de flow aangeven

Page 21: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

magazine voor software development 21

DATABASES

kwaliteit van de brondata te valideren. Voorbeelden van validatie zijn decontrole op de lengte van een reeks karakters, de controle van hetdata type of op een onder- en bovengrens. Een ETL-oplossing maaktvaak gebruik van een staging area, een database die je gebruikt voorde tijdelijke opslag van data gedurende alle fases van het ETL-proces.Deze database kan data bevatten van verschillende bronnen, ingele-zen op verschillende tijdstippen, die wordt gegroepeerd tot één resul-taat. Om de opgehaalde data door het gehele proces te kunnenvolgen kun je een Lineage ID veld gebruiken, een unieke reeks vankarakters die wordt gebruikt om een set van data uniek te maken.Dit is zeer bruikbaar voor audit doeleinden, foutafhandeling, systeem-herstel en het gemakkelijk kunnen selecteren van data tussen deverschillende stappen in het ETL-proces.

In de voorbeeldapplicatie gebruiken we een Flat File Source task ombrondata uit een CSV-bestand te lezen. Het ETL-proces valideerttijdens het ophalen van de data de waarden op datatype en of dezehet juiste aantal karakters bevatten. Ook wordt de Lineage IDtoegevoegd aan de dataflow om de gehele set van data uniek temaken.

Fig. 3: De technische en functionele validaties die wordenuitgevoerd tijdens de Extract fase

Voor de validatie maak je gebruik van Data Conversion tasks. Voor hetvoorbeeld is gekozen om elk type validatie in een aparte task onder tebrengen, waardoor de applicatie overzichtelijk is en gemakkelijkonderhoudbaar blijft.

Fig. 4 : De datatype- en lengte-validatie

Met een Derived Column task kun je de Lineage ID aan de datastroomtoevoegen.

Fig. 5 : Het toevoegen van de Lineage ID kolom aan de datastroom

De OLE DB Destination task laadt de gereedstaande data in deSourceData tabel in de staging area. Deze eerste tabel die deopgehaalde data bevat, wordt de “landing” tabel genoemd.

Fase 2: TransformDe tweede fase van het ETL-proces is de transformatie van de bron-data. Het komt vaak voor dat de brondata niet in het juiste formaatwordt aangeleverd. Om de data betekenis te geven voor het doelsys-teem moet je deze data transformeren. Veel voorkomende taken dieje hier voor kunt gebruiken zijn het opzoeken van waarden, het doen

van berekeningen, het groeperen van data, het uitvoeren van functio-nele validaties en het toepassen van business rules.

Tijdens de transformatiefase converteert de voorbeeldapplicatie dekosten van de verschillende projecten naar euro’s en sommeert dezekosten vervolgens.Met een Lookup task zoekt het proces de wisselkoers op, waarna hetde kosten omzet naar euro met een Derived Column task. Selecteeraltijd alleen de velden (dus geen ‘SELECT *’) die je gebruikt voor hetopzoeken; dit kan veel performancewinst geven. Om de kosten perland en per project te sommeren gebruik je de Aggregate task.

Fig. 6 : Een Lookup task die de wisselkoers (Rate) bij een bepaaldeeenheid opzoekt

Fig. 7 : De conversie van de kosten naar de eenheid Euro (kosten xwisselkoers)

Fig. 8 : Sommeren van de kosten per land, per project

Fase 3: LoadDe derde fase van het ETL-proces is het wegschrijven van de datanaar een doel, zodat het bruikbaar is voor andere gebruikers ensystemen. Het formatteren van de data speelt hierbij een belangrijkerol. De voorbeeldapplicatie genereert een rapport dat de kosten laatzien per project en per land. Het rapport bevat de namen van delanden en projecten en de daarbij behorende kosten afgerond op tweedecimalen.

Fig. 9 : De kosten worden afgerond op twee decimalen

Het proces schrijft de geformatteerde data met een Flat FileDestination task weg naar een rapport in CSV-formaat.

FoutafhandelingTijdens het ETL-proces kunnen zich allerlei fouten voordoen. Om dezefouten op een goede manier af te kunnen handelen is het noodzake-lijk om deze fouten te loggen en de verantwoordelijke gebruikers op dehoogte te brengen. Hierbij maken we onderscheid tussen functioneleen technische fouten, onderstaande tabel geeft kort de kenmerkenvan beiden.

Page 22: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

MAGAZINE22

DATABASES

Omdat fouten op meerdere plaatsen in het ETL-proces kunnenvoorkomen, moet het proces de fouten verzamelen en pas op het eindeen e-mail versturen. De e-mail kan een lijst met alle fouten bevattenof een verwijzing naar een locatie waar de fouten kunnen wordenbekeken en afgehandeld.

Fig. 10 : De gegenereerde fouten worden verzameld en vervolgensper e-mail verstuurd

De Extract-fase valideert een aantal velden op datatype met een DataConversion task. Wanneer het proces een waarde niet kan converte-ren, stuurt het de rij door naar de error output. Om een duidelijkeomschrijving van de fout te kunnen maken moet je de veldnaam in debeschrijving opnemen. Met SSIS is het echter een uitdaging om develdnaam te achterhalen van de waarde die het niet kon converteren.De error output van de Data Conversion task stuurt onder andere denumerieke waarde van de ErrorColumn door, wat een verwijzing isnaar het veld waarvan de conversie niet lukte. Met deze ErrorColumnwaarde ben je in staat de bijbehorende veldnaam op te zoekenwaarbij je gebruik kan maken van één van de volgende oplossingen.

De eerste optie is een Derived Column task. Zo’n task is eenvoudig temaken en snel te implementeren. Helaas is een expressieonoverzichtelijk en heeft deze een afhankelijkheid op de relatie tussenErrorColumn en veldnaam. De “ID” waarde van een veldnaam(opzoeken in Input and Output Properties tabblad) komt overeen metde ErrorColumn die de Data Conversion task naar buiten stuurt. Deze“ID” waarde kun je in de expressie van de Derived Column taskgebruiken om de relatie ErrorColumn - veldnaam te leggen.

Fig. 11 : De relatie tussen de ErrorColumn waarde en debijbehorende veldnaam

Een andere optie is het opzoeken van een naam in een XML-bestanddat de package beschrijft. Hier ben je onafhankelijk van de relatietussen ErrorColumn en veldnaam. Wel moet je een script bouwen omhet XML-bestand te doorzoeken en ben je afhankelijk van de locatievan het XML-bestand. Selecteer het element “outputColumn” waarvanhet attribuut “id” overeenkomt met de waarde van de ErrorColumn;het attribuut “name” bevat de veldnaam.

<outputColumn id=”148” name=”Expenses” …

Een laatste mogelijkheid is een tabel met de ErrorColumn en veld-naamgegevens, waardoor je een duidelijk overzicht hebt van de rela-tie tussen ErrorColumn en veldnaam. Hier ben je weer afhankelijk vanwijzigingen in de relatie tussen ErrorColumn en veldnaam. Zoek de“ID” waarde van een veldnaam op in de Input and Output Propertiestabblad en schrijf deze in een tabel. Met een Lookup task kan je aande hand van de ErrorColumn de bijbehorende veldnaam opzoeken.

Fig. 12 : Lookup tabel

VariabelenZoals we gewend zijn bij programmeertalen, kunnen ook binnenpackages variabelen gedeclareerd worden. Het gebruik vanvariabelen wordt interessant als deze ook gebruikt worden in childpackages. Een variabele die je declareert in een parent package kanje met package configurations doorgeven aan een child package;daarbij wordt een kopie van de waarde doorgegeven. In de childpackage moet je een variabele declareren die de kopie van de door-gestuurde waarde bewaart.

Fig. 13 : M.b.v. package configurations wordt een waardedoorgegeven naar de child package

Als het ene child package de resultaten van een andere child packagewil gebruiken, los je dat op door:• Declareer in de parent package een variabele (ParentVariable);• De eerste child package kent een waarde toe aan de variabele;• De parent package geeft de aangepaste waarde van variabele metpackage configurations door aan de tweede child package.

Fig. 14 : De variabele wordt gevuld door child package 1en vervolgens gelezen door child package 2

Installatie (bestandssysteem of SQL Server)SSIS kan een package vanaf het bestandssysteem of een SQLServer instantie laden. Tijdens het bouwen van packages staan depackages op het bestandssysteem, terwijl de packages in deproductie omgeving in een SQL Server instantie staan. Bij hetaanroepen van child packages vanuit een parent package, gebruik-makend van een Execute Package task, dien je rekening te houden

Functionele fouten Technische fouten Business gerelateerd Systeem gerelateerd De business gebruikers zijn verantwoordelijk voor de afhandeling (mogelijk met de tussenkomst van de systeembeheerder)

De systeembeheerder is verantwoordelijk voor de afhandeling

Uitkomst van functionele validaties Deze fouten activeren de OnError event handler

Fouten worden gelogd in een tabel Fouten worden gelogd in de Windows Application Eventlog

De gebruikers worden op de hoogte gebacht middels een e-mail

De beheerder wordt op de hoogte gebracht middels een e-mail

Voorbeelden: een waarde heeft een onjuist datatype, een waarde ligt buiten de vereiste grenzen

Voorbeelden: database verbinding verbroken, account gegevens verlopen

Met SSIS is het een uitdaging omde veldnaam te achterhalen vande onconverteerbare waardes

Page 23: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

Core Systems TIP:CUT en PASTE commando’s (ISPF)Om veelvuldig hetzelfde blok tekst in een source te kunnenplakken kan handig gebruik worden gemaakt van de CUT enPASTE macro’s. Selecteer de gewenste tekst en gebruik hetcommando CUT <naam> om deze tekst op het clipboard teplaatsen. Met het commando PASTE <naam> is de tekst op degewenste plek in de source te kopiëren. Om te voorkomen datPASTE de tekst van het clipboard verwijdert, kun je het vol-gende doen: open voordat je PASTE gebruikt het clipboardm.b.v. CUT DISPLAY; selecteer <naam> met de optie “O” (Tog-gle read-only) en verlaat het clipboard (PF3); kopieer vervol-gens de tekst zo vaak als je wil met het commando PASTE<naam>.

magazine voor software development 23

DATABASES

met de fysieke omgeving waar de child package is opgeslagen. Vooreen child package dat SSIS vanaf het bestandssysteem laadt, is na-melijk een ander type connection manager nodig dan voor een SQLServer instantie. Dit is eenvoudig op te lossen met een variabele, ge-koppeld aan package configurations, en door het definiëren van deexpressies Connection en PackageName van de Execute Packagetask. In deze expressies selecteer je afhankelijk van de waarde van devariabele de juiste connection manager.

In de voorbeeldapplicatie is de variabele IsProduction gedeclareerdals van het type Boolean dat aan de package configurations gekop-peld is. Er zijn twee connection managers toegevoegd, één File con-nection manager die verwijst naar de package ExtractData.dtsx ophet bestandssysteem en één OLE DB connection manager die verwijstnaar een bepaalde SQL Server instantie. De Execute Package task“ExtractData” voert een child package uit waarvan de expressiesConnection en PackageName zijn gedefinieerd.

Fig. 15 : De Connection en PackageName expressies van deExecute Package task

De Connection expressie selecteert de OLE DB connection manager(CM_SQL_ExtractData) of File connection manager (CM_FILE_Ex-tractData), afhankelijk van de IsProduction waarde. De PackageNameexpressie is leeg voor de File connection manager, en bevat de naamvan de package voor de OLE DB connection manager.

Indien de package naam een punt bevat, moet je er rekening meehouden dat deze punten automatisch worden vervangen doorspaties wanneer je deze packages op een SQL Server instantieinstalleert. Een best practice is dan ook om geen punten te gebruikenin package namen.

Mee leren leven...En dan zijn er nog zaken waar de wenkbrauwen van menig SSIS-ont-wikkelaar van gaan fronzen, maar waar we mee moeten leren leven:• Packages kun je voorzien van commentaar met annotations. Dezeannotations kun je helaas niet kopiëren en ze zijn niet gekoppeldaan tasks;

• Indien je een aantal keurig uitgelijnde tasks van de ene packagenaar een andere package kopieert, verandert de layout van dezetasks in de doel package;

• Als je de metadata van een package met meerdere tasks verandert(er veranderen bijvoorbeeld datatypes van bepaalde velden), zul jede meeste tasks moeten verversen. De Union task is echter eenvreemde eend in de bijt, omdat je deze task niet kunt verversen. Deenige manier om dit op te lossen is door de task te vervangen dooreen nieuwe;

• In de control flow zijn er genoeg situaties te bedenken die simpelmet een if-then-else opgelost zouden kunnen worden. SSIS bevathelaas geen if-then-else of case task. Een workaround is om eenScript task met bijbehorende Constraints en expressies te gebrui-ken of een For Loop Container task waarin de EvalExpressionexpressie de oplossing biedt;

• In de control flow kun je Script tasks debuggen, zoals elke ontwik-kelaar gewend is (breakpoints, watches, etc.). In de data flow kunje de Script componenten echter niet debuggen waardoor allerleitrucs nodig zijn, zoals door gebruik te maken van de oude, ver-trouwde messagebox of door de fouten middels een error outputnaar buiten te sturen;

• SSIS ondersteunt het .NET Framework, maar als C# ontwikkelaar

heb je alléén de keuze uit Visual Basic.NET. Gelukkig kan er in SQLServer 2008 wel naar hartelust in C# gebouwd worden.

ConclusieAls doorgewinterde .NET ontwikkelaar krijg je bij het bouwen van eenSSIS applicatie al vrij snel het gevoel dat je beperkt wordt in je bewe-gingsvrijheid. Met een aantal standaard bouwblokken moet de gehelefunctionaliteit worden gebouwd. Echter, als je eenmaal aan hetbouwen bent met SSIS, heb je snel iets werkends in elkaar gezet enleer je vrij snel waar welke trucs nodig zijn om bepaalde uitdagingenop te lossen. Tijdens het ontwikkelen kom je zo nu en dan situatiestegen waarin je simpele functionaliteit op een vrij omslachtige maniermoet bouwen; de Script task en het Script component bieden hiervaak een uitkomst. Gelukkig zijn er veel bedrijven die al dan niet opensource SSIS componenten aanbieden waardoor deze omslachtigemethoden niet meer nodig zijn. Ondanks dat SSIS hier en daar nog zijneigenaardigheden heeft, is SSIS uitermate geschikt om op eenproductieve manier en snel een goede ETL-oplossing te bouwen.

ReferentiesOp het internet is ontzettend veel informatie te vinden over SSIS; hier-onder zijn de belangrijkste bronnen bij elkaar gezet.

• Microsoft MSDN:http://msdn.microsoft.com/en-us/library/ms141026(SQL.90).aspx

• Microsoft Communities:http://www.microsoft.com/communities/newsgroups/en-us/de-fault.aspx?dg=microsoft.public.sqlserver.integrationsvcs

• http://social.msdn.microsoft.com/Forums/en-US/sqlintegrationser-vices/threads/

• Microsoft Team Blog: http://blogs.msdn.com/mattm/about.aspx• SQL Server Central:http://www.sqlservercentral.com/articles/Integration+Services •

Johan Machielse

Johan Machielse is SolutionDeveloper bij Avanade en isgespecialiseerd in Microsoft tech-nologiën, zoals .NET en SSIS.Voor vragen of opmerkingen ishij te bereiken via [email protected].

Page 24: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

Advertentie Bergler

Page 25: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

magazine voor software development 25

.NETASP

Toen ik Scott Guthrie in 2000 leerde kennen was hij de leaddeveloper van ASP.NET, maar hij is in sneltreinvaart hogeropgeklommen binnen Microsoft en is inmiddels Corporate VicePresident. Ondanks dat hij op dat niveau is aanbeland staat Scott nogzelf met z’n poten in de modder en geeft hij zelf zijn demo’s en kan hijop veel technische vragen antwoord geven. Aan de hand van een veel-heid aan demo’s behandelde Scott op 25 september een hoop, maarhet meest opvallende voor ASP.NET, afgezien van allerleiverbeteringen aan Visual Studio, ging over dat wat zich in de browserafspeelt, terwijl ASP.NET toch bij uitstek een server gebaseerdetechnologie is. Microsoft heeft echter begrepen dat de slag om hetinternet zich niet meer afspeelt rond de mogelijkheden van deservertechnologie, maar verplaatst is naar dat wat je in de browserkunt doen en hoe goed je standaarden kunt ondersteunen. Het bestevoorbeeld hiervan is een nieuwe feature van ASP.NET AJAX die ClientTemplate Rendering (CTR) genoemd wordt. Met CTR kun je eenHTML-sjabloon definiëren dat in de browser voorzien wordt van data.Eigenlijk is dit net als een ListView-control die je aan een gegevensbronkoppelt, maar dan gebeurt de DataBinding in de browser.Aanpassingen op bijvoorbeeld de sortering zijn daardoor vrijwelonmiddellijk, omdat er geen request naar de server hoeft te gaan voorandere data. Wanneer je CTR toepast op lijstdata, dan doe je dit metde zogenaamde DataView-control.

Het vreemde voor “old school” ASP.NET ontwikkelaars is dat dit geenserver control is, maar een client control. Je kunt deze simpelweg kop-pelen aan ieder JavaScript array, ongeacht of je die statisch definieert,programmatisch opbouwt of ophaalt met een webservice-aanroep.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" ><head>

<style type="text/css">.sys-template { display:none; }

.selecteditem { color: Red }</style>

<script type="text/javascript"src="http://ajax.microsoft.com/ajax/beta/0909/MicrosoftAjax.debug.js">

</script><script type="text/javascript"src="http://ajax.microsoft.com/ajax/beta/0909/MicrosoftAjaxTemplates.debug.js">

</script><script type="text/javascript"src="ContactsService.svc/jsdebug">

</script></head>

<body xmlns:sys="javascript:Sys"xmlns:dataview="javascript:Sys.UI.DataView"sys:activate="*"><div><ul id="nameListView" sys:attach="dataview"class="sys-template"dataview:dataprovider="ContactsService.svc"dataview:fetchoperation="GetContacts"dataview:autofetch="true"dataview:selecteditemclass="selecteditem"dataview:initialselectedindex="0"dataview:sys-key="master"><li sys:command="select">{{ Firstname }}</li>

</ul>

<div id="detailView" class="sys-template"sys:attach="dataview"dataview:data="{binding selectedData, source=master}"><div>Voornaam:<strong>{binding Firstname}</strong>

</div><div>Achternaam:

<strong>{binding Lastname}</strong></div>

</div></div>

</body></html>

Als je wilt kun je de DataView control ook direct, declaratief, koppelenaan een webservice en kun je zonder een regel code Master-Detailschermen maken zoals in figuur 1. De HTML die nodig is voor figuur1 vind je hierboven. Merk op dat hier geen ASP.NET code in zit … hetis dan ook een gewone HTML-pagina, maar wel met het een en anderaan referenties naar ASP.NET AJAX-scripts en naar een webservice!

Vind je dit zo cool dat je er nu al mee aan de slag wilt?Op http://aspnet.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=32770 kun je de meest recente release en voorbeeldendownloaden. Veel plezier! •

Het is je vast niet ontgaan dat Microsoft druk bezig is met de volgende versie van .NET en VisualStudio. Op het moment dat dit SDN-Magazine op de mat ligt zou het best kunnen zijn dat Beta 2 albeschikbaar is. Op 25 september is de Nederlandse community getrakteerd op een voorproefje vanBeta 2 door niemand minder dan Scott Guthrie, de bedenker van ASP.NET, die te gast was bij dotNED.

Michiel van Otegem

Fig. 1: Master-Detail met Client Template Rendering

ASP.NET onder de Motorkap:ASP.NET 4.0 op bezoek bij je browser

Page 26: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

CORESYSTEMS Christiaan Heidema

KeuzesGrofweg zijn de aanvankelijk gekozen oplossingen vanuit de keuzeom XML-parsing buiten COBOL te houden in twee groepen onder teverdelen (zie figuur 1). In beide gevallen wordt gebruik gemaakt vaneen externe XML-parser danwel -generator.

Fig. 1: Traditionele keuzes XML-parsing

In het eerste geval (I) wordt de te verwerken XML aangeboden aaneen XML-parser die vervolgens de inhoud van de XML-data omzetnaar een COBOL-datastructuur. Deze datastructuur wordt aan hetCOBOL-programma doorgegeven, die vervolgens deze data verwerkt.Wanneer data in XML-formaat moet worden teruggegeven, danretourneert het COBOL-programma de data in een COBOL-datastructuur. Deze wordt vervolgens aangeboden aan een XML-generator die deze datastructuur omzet naar XML. In dit geval weethet COBOL-programma niet dat de data oorspronkelijk in een XML-structuur is aangeleverd. De enige functie van het programma is hetverwerken van de data en eventueel het retourneren van data.

In de tweede oplossing (II) wordt de data wel in XML-formaat aan hetprogramma aangeboden, maar roept het programma zelf een externeXML-parser aan. Deze parser vertaalt de XML-data naar een COBOL-datastructuur en geeft deze terug aan het programma. De data wordtverwerkt en eventueel aan een XML-generator aangeboden die dedata vanuit een COBOL-datastructuur vertaalt naar XML. Hetprogramma geeft deze data in XML-formaat terug. De XML-parserdanwel -generator wordt aangeroepen met een complete verzame-ling aan regels voor het vertaalproces.

XML-StatementBeide oplossingen hebben zich in de loop van de jaren bewezen, enCOBOL is gebleken een overlever te zijn en is meegegaan met denieuwe technologieën. Een van de speerpunten hierbij is de integratiemet XML. Hiervoor is de verzameling van statements uitgebreid methet XML-statement.

Voor het parsen van XML:

XML PARSE identifier

PROCESSING PROCEDURE [IS] procedure-name

[THROUGH|THRU procedure-name]

[[ON] EXCEPTION imperative-statements]

[NOT [ON] EXCEPTION imperative-statement]

[END-XML]

Voor het genereren van XML:

XML GENERATE identifier FROM identifier

[COUNT [IN] identifier]

[[ON] EXCEPTION imperative-statements]

[NOT [ON] EXCEPTION imperative-statement]

[END-XML]

De werking van XML PARSE verschilt nogal ten opzicht van XMLGENERATE. Aan de hand van een voorbeeld wordt de werking vanbeide statements uitgelegd.

XML PARSE StatementMet behulp van het XML PARSE statement wordt de interne XML-par-ser aangeroepen. Deze parser controleert of de XML well-formed is engeeft de besturing terug aan het aanroepende programma, o.a. bij elkbegin en einde van een document, element, attribuut en content. Dezeevent-driven benadering is de grote kracht van deze parser. Hierdoor

MAGAZINE26

Sinds de intrede van de SOA-principes is XML in de praktijk de standaard geworden voor gegevensoverdracht tus-sen applicaties. Met behulp van XML worden gegevens gestructureerd vastgelegd en zijn ze leesbaar voor zowelmens als machine. Ook COBOL-applicaties hebben te maken met gegevensstromen die op XML gebaseerd zijn.Het realiseren van een XML-parser in COBOL is echter geen eenvoudige klus. Bovendien hebben de UNSTRINGen STRING statements de naam een zware claim op het CPU-gebruik te leggen. In veel transactie georiënteerdeomgevingen - waarin een hoge verwerkingssnelheid een vereiste is - heeft men daarom in het verleden beslotenom de XML-parsing buiten de COBOL-applicaties te houden. Maar de ontwikkelingen op het gebied van COBOLstaan niet stil. Mede door de introductie van ISO-2002 COBOL worden steeds meer COBOL-compilers uitgerustmet functionaliteit voor het parsen en genereren van XML. Een voorbeeld hiervan is de Enterprise COBOLcompiler. Tijd om de in het verleden gemaakte keuzes met betrekking tot XML-parsing te evalueren.

XML-Parsing in COBOL

Page 27: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

magazine voor software development 27

CORESYSTEMS

is het mogelijk om de besturing over de verwerking van de aangele-verde data volledig in het aanroepende programma te houden.

Listing 1 toont een voorbeeld van het gebruik van het XML PARSEstatement.

Parse-XML section.** Parse XML within XMLin using internal parser*

XML Parse XMLinprocessing procedure is XML-event-handleron exception

perform XML-Errornot on exception

Display 'XML succesfully processed'End-XML.

Listing 1: Aanroep van de interne XML-parser

De gespecificeerde processing procedure (in dit geval XML-event-handler) wordt voor elk event door de parser aangeroepen. Een eventkan b.v. gevonden content zijn of het einde van een element. Voor decommunicatie tussen de parser en de processing procedure is eenaantal special registers in het leven geroepen. De meest gebruikte zijnweergegeven in tabel 1.

XML-EVENT De naam van het opgetreden event

XML-CODE Een numerieke waarde die status van de parsing weergeeft

XML-TEXT Aanvullende informatie over het event, is afhankelijk van dewaarde van het event

Tabel 1: Meest gebruikte special registers voor XML PARSE

De event-handlerDe processing procedure is in feite een event-handler voor de parser.Listing 2 toont een voorbeeld van een event-handler.

XML-event-handler section.** XML PARSE processing procedure.* This procedure is called every time an event* occurs*

evaluate XML-Eventwhen 'START-OF-DOCUMENT'

perform startOfDocument-Handlerwhen 'END-OF-DOCUMENT'

perform endOfDocument-Handlerwhen 'START-OF-ELEMENT'

perform startOfElement-Handlerwhen 'END-OF-ELEMENT'

perform endOfElement-Handlerwhen 'CONTENT-CHARACTER'when 'CONTENT-CHARACTERS'

perform contentCharacters-Handlerwhen 'ATTRIBUTE-NAME'

perform attributeName-Handlerwhen 'ATTRIBUTE-CHARACTERS'

perform attributeCharacters-Handlerwhen 'EXCEPTION'

perform exception-Handlerwhen other

display 'Unknown event : ', XML-Eventend-evaluate.

Listing 2: Voorbeeld van een event-handler

Het register XML-EVENT bevat de naam van het event dat opgetredenis. Afhankelijk van deze waarde wordt een subhandler aangeroepen.Zo wordt startOfElement-Handler aangeroepen op het moment dathet event ‘START-OF-ELEMENT’ optreedt. In dit geval bevat XML-TEXT de waarde van het element. Op deze wijze kan het programmazelf bepalen welke elementen al dan niet verwerkt worden.

Als ontwikkelaar krijg je hier een leuke uitdaging voor je kiezen. Deparser geeft namelijk alleen de naam van het element mee en niet denamen van de elementen waar het onderhanden element onderdeelvanuit maakt.Als we kijken naar de XML in listing 3, dan zien we een aantal ele-menten met dezelfde naam onder de verschillende groepselementenvoorkomen, zoals <id> en <name>. De event-handler moet hier reke-ning mee houden en is zelf verantwoordelijk voor het bijhouden van hetpad naar de verschillende elementen. Op basis van dit pad kan dehandler besluiten om data te negeren of juist te valideren en teverwerken.

De events ‘CONTENT-CHARACTER’ en ‘CONTENT-CHARACTERS’treden op bij het parsen van de content van een element. Per elementkunnen deze events meerdere keren optreden. Dit heeft te maken metde afhandeling van karakters met een specifiek doel binnen XML(<,>,&,' en ") . Voor deze karakters zijn aparte entity references gede-finieerd (&lt; - &lt; - &amp; - &apos; - &quot;). De tekst “Jip & Janneketaal” wordt in well-formed XML weergegeven als volgt: “Jip &amp;Janneke taal”.

<Order><Date>2009-06-12</Date><ID>83738</ID><Client><ID>26736</ID><Name>J. van Couver</Name>

</Client><Details><Product category=”CD”><ID>86353</ID><Name>The Best of ABBA</Name><Amount>2</Amount><Price>24.89</Price>

</Product><Product category=”book”><ID>94432</ID><Name>COBOL 2002 Standards</Name><Price>54.55</Price></Product>

</Details></Order>

Listing 3: Voorbeeld XML voor verkoop van order

Wanneer we deze tekst door de parser halen, dan treedt eerst hetevent “CONTENT-CHARACTERS” op. XML-TEXT bevat in dit gevalde waarde “Jip ” (let op de spatie). Vervolgens treedt het event “CON-TENT-CHARACTER” op. De parser heeft de entity reference “&amp;”vertaald naar “&” en in XML-TEXT geplaatst. Vervolgens treedt “CON-TENT-CHARACTERS” weer op voor het laatste deel van de naam “Janneke taal”. Om de volledige naam te kunnen formeren, moet bijhet afhandelen van deze events moet de waarden van XML-TEXT aanelkaar geplakt worden (zie listing 4).

contentCharacters-Handler section.** Append content of XML-Text to content-buffer*

string XML-Text( 1 : Length Of XML-Text )delimited by size

into contentBufferwith pointer contentBufferPtr

end-string.

Listing 4: Afhandelen event CONTENT-CHARACTER(S)

XML Parsing werkt op basis van eenevent-driven benadering

Page 28: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

MAGAZINE28

CORESYSTEMS

Op het moment dat het event “END-OF-ELEMENT” optreedt, bevatcontentBuffer de volledige content van het betreffende element. Deinitialisatie van de variabelen contentBuffer en contentBufferPtr moetplaats vinden bij het begin van de verwerking van de content, dus alshet event “START-OF-ELEMENT” optreedt.

Exceptions en controlesDe XML-parser van COBOL voert alleen controles uit om vast te stel-len of de XML-code goed is opgezet. Is dit niet het geval dan treedthet event “EXCEPTION” op. Bovendien treedt dan de ON EXCEPTIONclause van het XML PARSE statement in werking. In het register XML-CODE wordt met een cijfer aangegeven wat de oorzaak van de foutis (het cijfer 5 betekent ‘start-tag en end-tag komen niet overeen’ ).De afhandeling van deze exceptions ligt bij het programma zelf.

De parser stopt zodra XML-CODE een waarde anders dan nul heeft.Er zijn situaties denkbaar dat je dit niet wil. Voor bepaalde waardenvan XML-CODE kun je forceren dat de parser doorgaat nadat er eenEXCEPTION-event is opgetreden. De parser controleert namelijk indeze gevallen nádat de event-handler is aangeroepen of XML-CODEde waarde 0 heeft. Door de handler voor het afhandelen van het EX-CEPTION-event XML-CODE de waarde 0 te laten geven, geef je eensignaal aan de parser dat het probleem is verholpen. Je forceert hier-mee dat de parser doorgaat daar waar hij is gebleven.

exception-Handler section.** Handle exception event*

display 'XML Parse Error'.display 'Error code : ', XML-Code.display 'Current path : ', elementPath.

* force parser to proceed.move zero to XML-Code.

Listing 5: Exception handler

Het programma voert zelf ook validaties op de data uit. Wanneer blijktdat een bepaald element een onjuiste waarde bevat, kun je er voorkiezen om de parser te laten weten dat er een fout is opgetreden doorXML-CODE de waarde -1 te geven. Op het moment dat de parser debesturing weer terugkrijgt wordt het parse-proces dan afgebroken.De parser controleert niet of de content voldoet aan de specificaties.De verantwoordelijkheid voor deze controles ligt bij het programmadat de parser aanroept. Dit betekent dat wanneer strikte XML-con-troles noodzakelijk zijn, alle controles in het programma gecodeerdmoeten worden.

XML GENERATE StatementNaast het parsen van XML bestaat ook de mogelijkheid om XML doorCOBOL te genereren. Hiervoor is het XML GENERATE statement inhet leven geroepen. Met behulp van één aanroep naar dit statementis het mogelijk om een complete COBOL datastructuur naar XML omte zetten. Om dit te illustreren wordt op basis van de voorbeeld XMLin listing 3 elke verkoop van een product geregistreerd in een sales-logboek. De mutaties op dit logboek worden met behulp van XMLaangeleverd. We gebruiken hiervoor de datastructuur in de working-storage section van listing 6.

** Datastructure for saleslog*01 SalesLog.

03 SalesLogDate pic x(10).

03 SalesLogEntry occurs 10depending onentryCount.

05 SalesLogCategory pic x(01).05 SalesLogProduct pic 9(10).05 SalesLogAmount pic 99.05 SalesLogValue pic 9(05)v9(02).

01 entryCount pic 9(03) binary.

Listing 6: Datastructuur Saleslogboek mutaties

De event-handlers uit listing 2 dragen zorg voor het vullen van dezedatastructuur. Op het moment dat het event “END-OF-DOCUMENT” optreedt zijn er geen producten meer en kunnen demutaties naar het logboek worden geschreven. Het genereren van deXML om deze mutaties aan het logboek toe te voegen is vrij eenvou-dig (listing 7).

endOfDocument-Handler section.** End of XML reached, generate XML for Saleslog*

XML generate XMLout from SalesLogcount in XMLout-length

on exceptionDisplay 'Error during generating XML'

not on exceptionperform Send-XML

End-XML.

Listing 7: Voorbeeld XML GENERATE

Het XML GENERATE statement genereert op basis van zowel destructuur als de inhoud de XML. De uitvoer is weergegeven in listing 8.

<SalesLog>

<SalesLogDate>2009-06-12</SalesLogDate>

<SalesLogEntry>

<SalesLogCategory>2</SalesLogCategory>

<SalesLogProduct>86353</SalesLogProduct>

<SalesLogAmount>2</SalesLogAmount>

<SalesLogValue>49.96</SalesLogValue>

</SalesLogEntry>

<SalesLogEntry>

<SalesLogCategory>1</SalesLogCategory>

<SalesLogProduct>94432</SalesLogProduct>

<SalesLogAmount>1</SalesLogAmount>

<SalesLogValue>54.55</SalesLogValue>

</SalesLogEntry>

</SalesLog>

Listing 8: Uitvoer XML Generate

De tag-namen worden door de compiler afgeleid uit de definitie van dedatastructuur in de working-storage section. De inhoud van de data-structuur wordt ontdaan van voorloopnullen en –spaties en de speci-ale karakters worden vertaald naar entity references. Lege velden,velden gevuld met spaties, worden in de XML opgenomen als ele-menten met een waarde gelijk aan één spatie. De DEPENDING ONclausule bij de OCCURS zorgt ervoor dat alleen de gevulde occuren-ces van de tabel worden meegenomen bij het genereren van de XML.Laat je deze weg, dan wordt voor de gehele tabel XML gegenereerd.

Hoewel dit een krachtig en eenvoudig mechanisme is om XML tegenereren, missen we ook een aantal zaken. Zo is het bijvoorbeeldniet mogelijk om attributes te genereren. In het voorbeeld van listing 3bevat het element “product” een attribuut “category”. Met het XMLGENERATE statement is het niet mogelijk om onderscheid te makentussen attributen en elementen. Enterprise Cobol ondersteunt vanaf

Genereer XML vanuit een COBOLdatastructuur met één statement

Page 29: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

versie V4.1 wel de generatie van attributen door de toevoeging vande clause WITH ATTRIBUTES. Hierbij worden alle elementaire veldenniet als element maar als attribuut opgenomen. Tevens worden vanafdeze versie extra features ondersteund voor het gebruik vanencoding, namespaces en namespace-prefixes.

Nogmaals: keuzesNu COBOL zelf krachtige functionaliteit biedt om XML-data af te han-delen, moeten we dan de in het verleden gemaakte keuzes maar overboord gooien? Dat is nog maar de vraag. Vanuit architectuuroogpuntis hier wel veel voor te zeggen. De volledige afhandeling van XML vindtnamelijk op één plek plaats. Maar ook voor de ontwikkelaar biedt hetgebruik van de interne parser veel voordelen. Het biedt hem namelijkveel vrijheid bij het parsen van XML. Hij heeft veel controle over demapping van XML-data op een COBOL-datastructuur. Validaties kun-nen naar eigen inzicht gerealiseerd worden. Niet gebruikte elementenen attributen kunnen genegeerd worden. Maar wanneer de organisa-tie strikte eisen stelt aan b.v. XML-validatie aan de hand via een XSD,betekent het gebruik van deze parser wel een enorme workload voorde ontwikkelaar. Alle validatieregels moeten door de ontwikkelaar zelfworden gecodeerd. In deze situatie is het gebruik van een externeparser te rechtvaardigen of zelfs te adviseren.

Het gebruik van slechts één statement om een volledige datastruc-tuur om te zetten naar XML is wel een zeer krachtige manier om XMLte genereren, maar er zijn ook beperkingen die door het gebruik vaneen externe parser opgelost kunnen worden. Denk ook hierbij aanXML-validatie tegen een XSD. Ook hierbij geldt dat de eisen die deorganisatie stelt aan de XML bepalend kunnen zijn voor de keuze vande XML-generator.

ConclusieCOBOL vierde dit jaar zijn 50ste verjaardag en is daarmee een van delangst levende en meest gebruikte talen. Met de toevoeging vanfunctionaliteit voor integratie met XML komt COBOL nog steviger in hetzadel te zitten om deze positie te handhaven. De interne XML-parserpresteert goed als het gaat om CPU-tijd en verwerkingssnelheid.Hierdoor is deze parser bijzonder geschikt voor transactie-georiën-teerde applicaties, omgevingen waar COBOL de standaard is.De keuze voor het gebruik van de COBOL-functionaliteit ten opzichtevan de externe parsers en generatoren zal voornamelijk gebaseerdworden op de eisen vanuit de organisatie. De ontwikkelingen op ditgebied staan echter niet stil. Wellicht dat de in het verleden gemaaktekeuzes in de toekomst nog eens geëvalueerd moeten worden. •

De COBOL XML-parser scoort zeerhoog op verwerkingssnelheid

Christiaan Heidema

Christiaan Heidema is MainframeSoftware Guru at Sogeti NederlandBV. During the last 12+ year Christi-aan has worked in several mainframeenvironments as DBA, Engineer andChange- and Configuration-manager.

He developed a passion for mainframe software solutions. Hisexpertise encloses o.a. COBOL, DB2, IMS, CICS and JCL.

Advertentie Aladdin

Page 30: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

.NETUX

Dennis Vroegop

De specifieke Surface-uitdagingHet ontwikkelen voor Surface is anders dan het schrijven vanWindows of Web applicaties.Er zijn een aantal dingen die het zo anders maken:• Er is geen boven en onderkant van het scherm: de applicatiesmoeten in principe van alle kanten te benaderen zijn;

• Er is niet één gebruiker met één muiscursor: er kunnen (horen?)meerdere gebruikers tegelijkertijd aan het werk (te) zijn die ieder huneigen ding doen;

• Alles vindt plaats in één scherm: je kunt beter geen gebruik makenvan andere schermen en popup windows;

• De resolutie is beperkt tot 1024 bij 768 pixels, je hebt dus niet al teveel schermuimte;

• Maak weinig gebruik van tekstinvoer: Surface is geen ‘data entry’platform;

• Hou rekening met de fysieke beperking van de gebruikers: met eenvinger is het moeilijk om heel nauwkeurig een element te selecteren.Vingers zijn minder nauwkeurig dan een muis!

Dit klinkt allemaal nogal beperkend, maar in de praktijk valt dat bestmee. Zeker de resolutie klinkt als een belemmering maar als je het zietdraaien op je 30” Surface machine ziet het er allemaal toch goed uit.Je kunt alleen niet al te veel elementen op je scherm kwijt.

OntwikkeltoolsEen Surface-machine is te krijgen in twee varianten: de commercialuitvoering en de developer uitvoering. Indien je bij Microsoft de laatstekoopt, krijg je, naast de indrukwekkende hardware, ook alle tools dieje nodig hebt om applicaties te schrijven. Ook mensen met een Aca-demic Alliance MSDN abonnement (de MSDNAA leden) hebbentoegang tot de software.

Deze software bestaat uit een aantal onderdelen:1. De simulator: deze gebruiken we om onze code op te testen als weniet direct bij de Surface unit kunnen komen;

2. Een SDK: alle libraries, samples en dergelijke zijn hier te vinden;3. Een aantal tools: denk hierbij aan een tool om tags te printen en omje applicatie een stress test te laten ondergaan.

De SDK draait momenteel alleen op 32-bitsversies van Windows VistaBusiness en hoger, en ook op Windows 7. Een 64 bits versie is er nietmaar met enige hacken kun je dat wel aan de praat krijgen. Let wel op:dit is geen supported omgeving!

Je hebt uiteraard Visual Studio nodig, maar de C# Express-editievolstaat (dat is ook de versie die je bij je Surface-machine krijgt).Download wel SP1 en de XNA-toolkit; zonder deze installeert de SDKniet.

XNA of WPF?Als je de SDK geïnstalleerd hebt, krijg je in je ‘New Project…’ dialoogin Visual Studio een paar extra templates te zien. Je kunt hier kiezentussen een nieuw Surface-project in WPF of in XNA.

Fig. 1: Project-templates in VS2008 met Surface SDK

Wat moet je nu kiezen? Ga je voor XNA of voor WPF? En waaromhebben we die keuze? Het antwoord daarop ligt in het verleden.

Microsoft had ooit bedacht dat XNA het platform zou worden voor hetontwikkelen van applicaties voor devices. Als eerste was er de om-geving voor de XBox. Als je applicaties wilt ontwikkelen voor de XBoxdoe je dat in de XNA-omgeving. Later is daar de Zune bij gekomen:ook daarvoor moet je gebruik maken van de XNA-templates.

MAGAZINE30

Surface developmentVeel mensen die Surface voor het eerst zien ervaren het als iets ‘magisch’. De gebruikers zieneen Surface niet als een PC maar als een gebruiksvoorwerp, en uiteraard is dit precies wat debedoeling is. Ook ontwikkelaars denken er zo over. Doordat de user interface niet lijkt op watwe gewend zijn van PC’s is de koppeling tussen PC- en Surface-ontwikkeling verbroken.Toch is het ontwikkelen van Surface-applicaties niet moeilijker dan het bouwen van andereapplicaties met Windows Presentation Foundation (WPF). De moeilijkheid van het bouwen vanSurface-applicaties ligt meer in het concept, de form factor en het maken van applicatiesdie van alle kanten benaderd kunnen worden. Liever gezegd: de ‘wat’ vraag is moeilijker tebeantwoorden dan de ‘hoe’ vraag.

XNA of WPF: voor Surface maakthet niet uit

Page 31: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

magazine voor software development 31

.NETUX

Aangezien Surface gezien werd als device, lag het voor de hand omXNA in te zetten als ontwikkelplatform. Echter, tijdens de ontwikkelingvan de SDK bleek dat er eigenlijk weinig verschil was tussen hetbouwen voor Surface en voor normale Windows-applicaties. Toen isbesloten omWPF als platform in te zetten als ontwikkelomgeving voorSurface. Het maakt niet zoveel uit welk van de twee je kiest, hoewelXNA iets meer gericht is op het low-level programmeren. Als je bij-voorbeeld de ruwe input van de camera’s wilt afvangen, moet je datvia XNA doen. WPF daarentegen biedt meer tools voor het schrijvenvan de business logic in je applicatie.Daarnaast, maar dat is een persoonlijk gevoel, vind ik het vreemd omeen serieuze applicatie te schrijven waarbij de hoofdregels de code‘Game app = new Game()’ bevatten.In de praktijk kiezen de meeste ontwikkelaars voor WPF.

De simulator

Fig. 2: De simulator aan het werk

Als je de SDK geïnstalleerd hebt, krijg je ook de Surface Simulatorerbij. Deze tool stelt je in staat om je code op je werkstation te testenzonder dat je echt naar een Surface-machine moet gaan.Het is wel belangrijk dat je je werk regelmatig op een fysieke Surface-machine draait: het is erg lastig om vanaf je desktop te controleren ofje User Interface vanaf alle kanten van de tafel goed te gebruiken is.Ook het testen van je tags gaat makkelijker op de tafel zelf dan in desimulator.Toch zul je merken dat, naarmate je meer ervaren wordt in Surface-development, de Simulator een enorm goede tool is. Bij Microsoft zelfhebben ze bij het Surface-team slechts één Surface-machine perongeveer 8 ontwikkelaars: 90% van de tijd werken zij in de Simulator.

In de simulator kun je met meerdere muizen tegelijkertijd werken.Op die manier kun je meerdere gebruikers nadoen, maar in de prak-tijk is dat vrij lastig. Ik kan niet echt werken met een muis in iederehand, maar misschien lukt het jou wel. Nodig is dit niet: je kunt met jemuis een vinger nadoen, vastzetten en dan er een tweede vinger aantoevoegen. Je kunt je bewegingen opnemen en later weer afspelenzodat je een soort van test kunt maken.Je kunt vingers en objecten simuleren en uiteraard van bijna allemogelijkheden van de Surface-omgeving gebruik maken. Je kunt nietbij de ruwe camerabeelden komen: de Simulator heeft immers geenechte fysieke camera’s aan boord.Voor de rest werkt de Simulator uitermate goed en is het een mooiemanier om de bulk van je werk te doen. Alleen het fine-tunen en hettesten van je applicaties hoef je dan nog op de Surface-machine zelfte doen.

Om applicaties te ontwikkelen heb je meer nodig dan alleen deSimulator. Na installatie krijg je dan ook nieuwe Visual Studiotemplates, een aantal tools en een nieuw stel WPF-controls.

ControlsNaast de standaard WPF-controls heb je na installatie van de SDKeen extra set controls tot je beschikking. Deze controls zijn onder teverdelen in 3 categorieën:1. Afgeleide controls, deze zijn varianten van de standaard WPF-controls;

2. Surface-specifieke controls, oftewel controls die je alleen voorSurface-applicaties kunt gebruiken;

3. Non-Visual controls, die extra functionaliteit bieden.

Je ziet de controls in figuur 3.

Fig. 3: De toolbox met Surface-items

Afgeleide controlsAls je WPF gewend bent, ken je de standaard controls wel. Veel ervankun je direct gebruiken in je Surface-applicatie; onze applicatie isimmers een WPF-applicatie. Toch zijn er een paar dingen anders:Surface stelt speciale eisen aan de applicaties.Surface-applicaties zijn bedoeld om door (meerdere) mensen gebruiktte worden, met behulp van vingers en objecten. Dit betekent dat destandaard controls niet voldoen. Denk b.v. aan een standaard check-box. Door het aanklikken van deze control kun je een vinkje plaatsenof verwijderen. Dit vakje echter is vrij klein, te klein om met je vingerste bedienen. Voor Surface is dus een grotere control gemaakt.Ook een Button is anders dan je gewend bent. Naast het grotereformaat is het gedrag van een button ook anders. Stel je eens voor:iemand plaatst zijn vinger op de button. Een tweede persoon plaatstzijn vinger ernaast, op dezelfde button. De eerste persoon verwijdertzijn vinger weer. Wat moet er nu gebeuren? In standaard Windows-applicaties kennen we dit probleem niet: er is immers maar één muis.De Surface Button control zorgt ervoor dat dit soort gebeurtenissengoed afgehandeld worden (voor de volledigheid: er is een Contact-Removed event dat afgevuurd wordt voor iedere vinger die van decontrol af gaat, maar het Click-event wordt pas afgevuurd als allevingers weg zijn.)

Page 32: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

MAGAZINE32

.NETUX

De afgeleide controls staan in de volgende tabel:

Bij een aantal van deze controls (vooral de menu’s) heb ik vermeld datje ze beter niet kunt gebruiken. De reden hiervoor is dat het gebruikvan menu’s niet intuïtief werkt, het staat de acceptatie van je applica-tie in de weg. Indien je toch een menu wilt gebruiken, kun je beter voorde speciale ElementMenu kiezen.

Surface specifiekEen aantal controls zijn speciaal ontwikkeld voor Surface. Momenteelzie ik hier en daar al open source libraries verschijnen met meer con-trols, dus je bent niet beperkt tot dit lijstje.

In figuur 4 zie je een voorbeeld van een LibraryBar, met daarin 3LibraryBarItems. De gebruiker kan deze met de vingers selecteren enze eventueel ergens naar toe slepen.

Fig. 4: De LibraryBar in actie

Non-Visual ControlsMomenteel is er maar één non-visual control, en dat is de TagVisuali-zer. Hier ga ik later in dit artikel dieper op in. Hij staat hier alleen evenvoor de volledigheid.

ContactsDe kracht van Surface zit hem in het gebruik ervan. Een goedeSurface-applicatie moet uitnodigen tot gebruik; mensen moeten ergraag aan zitten. Nu is ‘eraan zitten’ niet zo’n probleem, maar het iswel prettig als we in onze applicaties ook iets kunnen doen met dieaanrakingen.Surface is geen touch-systeem. Veel mensen noemen het een aan-raakscherm maar dat is niet correct. Surface is, zoals dat zo mooiheet, vision based. Met andere woorden: er zitten camera’s in hetsysteem die door het scherm naar buiten kijken en detecteren wat er

gebeurt. Dit maakt het mogelijk om objecten te herkennen, iets watmet een aanraak-systeem niet zou kunnen.In je code moet je uiteraard ook bij de contacten kunnen. Veel contact-gebaseerde events worden al opgevangen door de Surface-controls:een SurfaceButton b.v. kan zelf omgaan met de contacten die op hetscherm geplaatst worden en er weer vanaf gehaald worden. Somsmoet je echter zelf iets met de contacten doen. Het is b.v. mogelijk omte detecteren welke gebruiker iets op de machine doet. Nou ja, nietecht detecteren maar je kunt een aardige gok maken.

Als iemand zijn vinger op het scherm plaatst, ziet het systeem dat. Hetleuke is dat als je je vinger op het scherm neerzet, er een schaduwontstaat onder je vinger; deze schaduw wordt lichter naarmate jevinger verder van het scherm is. Op deze manier ontstaat er eenplaatje wat een beetje op een komeet lijkt: een duidelijke afdruk bij hetpuntje van de vinger met een vager wordende staat in de richting vande hand. Op basis daarvan kan de Surface-omgeving de hoekbepalen waaronder de vinger op het scherm staat, en daarmee kun jedus raden waar de gebruiker staat (mensen leggen hun vinger meestalin het verlengde van hun arm neer).

private void OnContactDown(DependencyObject sender,ContactEventArgs e)

{// Is het een vinger?if (e.Contact.IsFingerRecognized){// Wat is de hoek?double angle = e.Contact.GetOrientation(this);// Bereken het kwadrantif (angle....)

}}

Mocht je nu een contact op het scherm hebben wat geen vinger is,dan kun je de locatie, de bounding-rectangle enz. opvragen. Op diemanier kun je alle soorten objecten herkennen en er iets mee doen.

TagsAls je een Surface-machine koopt krijg je er een groot vel bij, metdaarop 255 stickers. Deze stickers, voorzien van een stippenpatroon,kun je gebruiken om objecten te ‘taggen’. De stickers worden doorSurface herkend en behandeld als Contacts. Dit stippenplaatjenoemen we de tags.

Byte TagsEr zijn twee soorten tags: we kennen de byte tag en de identity tag.De byte tags bevatten, zoals de naam al suggereert, een bytewaarde.Ze kunnen dus waardes tussen 0 en 255 bevatten. Figuur 5 laat eenvoorbeeld van zo’n byte tag zien, in dit geval met de waarde 42 (2Ahexadecimaal)

Fig. 5: ByteTag 42

Door het contrast tussen dewitte stippen en de zwarteachtergrond kan Surface ditherkennen als een byte tagen de waarde daarvan door-geven aan je applicatie. Enhier komt de non-visual con-trol TagVisualizer om de hoekkijken.

Control Opmerkingen SurfaceScrollBar SurfaceButton SurfaceCheckBox SurfaceContextMenu Bij voorkeur niet gebruiken SurfaceInkCanvas SurfaceTextBox Indien deze control geactiveerd wordt, verschijnt er een keyboard op

het scherm. Er kan slechts één keyboard tegelijk aanwezig zijn. SurfaceMenu Bij voorkeur niet gebruiken SurfaceMenuItem Bij voorkeur niet gebruiken SurfaceSlider SurfaceListBox SurfaceListBoxItem SurfaceRadioButton SurfaceScrollViewer SurfacePasswordBox Ook hier verschijnt bij het activeren een keyboard, echter de

toetsaanslagen zijn niet zichtbaar. In een multi-user omgeving kun je twijfelen aan het nut hiervan (iedereen kijkt mee terwijl je het wachtwoord invoert...)

Control Opmerkingen ElementMenu Een speciaal menu voor Surface. Werkt meer intuitief dan de

standaard context menu maar is functioneel vergelijkbaar ElementMenuItem Dit zijn de items in het ElementMenu LibraryBar Een speciale container LibraryBarItem Items in de LibraryBar LibraryStack Een soort ListBox, maar dan met elementen over elkaar heen

geplaatst. LibraryStackItem Items in de LibraryStack LibraryContainer Een mengvorm van de LibraryBar en de LibraryStack: de gebruiker

kan tijdens gebruik switchen tussen de LibraryBar en de LibraryStack modus

ScatterView Een soort ListBox waarbij de elementen vrij over het scherm kunnen worden verplaatst, geroteerd en vergroot of verkleind.

ScatterViewItem De items die in de ScatterView zitten. Hier kun je per item aangeven of ze mogen worden verplaatst, van grootte veranderd en/of geroteerd.

Surface is Vision Based,niet Touch Based

Page 33: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

magazine voor software development 33

.NETUX

De TagVisualizer control is een control die je ergens op je schermplaatst. Je kunt hem het hele scherm laten beslaan of slechts een deelervan. Op het moment dat het systeem at runtime een tag op eenTagVisualizer ziet, zal het de juiste events afvuren zodat je weet waarde tag geplaatst is en welke waarde deze bevat. Kijk eens naar hetvolgende stukje XAML code:

<s:TagVisualizerVisualizationAdded="TagVisualizer_VisualizationAdded"VisualizationRemoved="TagVisualizer_VisualizationRemoved"><!-- Bepaal welke tags geldig zijn --><s:TagVisualizer.Definitions>

<s:ByteTagVisualizationDefinition Value="#2A"/><s:ByteTagVisualizationDefinition Value="#F0"/>

</s:TagVisualizer.Definitions></s:TagVisualizer>

Hier plaatsen we in het scherm (het hele scherm om precies te zijn) eenTagVisualizer. We geven hem twee event-handlers mee: één om af tevangen dat er een tag geplaatst wordt, en één om af te vangen dat detag weer van het scherm genomen wordt.Verder definiëren we dat hij alleen mag reageren op de byte tags metde waardes #2A en #F0. Alle andere worden genegeerd. Meer heb jeniet nodig om je systeem te laten reageren op tags!

Nu is dit leuk, maar als je dit zou gebruiken krijg je op het moment datde tag geplaatst wordt een standaard plaatje op je scherm, in de vormvan een draadkruis zoals we dat in schietspelletjes kennen. Dat ismeestal niet wat je wilt: je wilt meestal een afbeelding, een stelcontrols of iets anders betekenisvols op je scherm plaatsen.

Om dat voor elkaar te krijgen moeten we een speciaal soort User-Control definiëren, de zogenaamde TagVisualization class. Dit isgewoon een UserControl met wat extra waardes. Op het moment datwe dan een tag op het systeem zetten die herkend wordt, zal Surfaceeen instance maken van deze UserControl en plaatst deze op de plekvan de tag. Als je de tag draait, zal de UserControl mee draaien. Alsje de tag verwijdert, verdwijnt ook de User Control. Dit is overigensinstelbaar: je kunt er ook voor kiezen hem te laten staan, of pas na 10seconden te laten verdwijnen, enz.

<s:TagVisualizationx:Class="SurfaceApplication2.MyTagVisualization"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/

presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:s="http://schemas.microsoft.com/surface/2008"Loaded="MyTagVisualization_Loaded"Width="200" Height="150"><StackPanel Orientation="Horizontal">

<StackPanel><Label Content="Naam" /><Label Content="Bedrijf"/>

</StackPanel><StackPanel>

<Label x:Name="lblName"/><Label x:Name="lblCompany"/>

</StackPanel></StackPanel>

</s:TagVisualization>

In bovenstaand voorbeeld definieer ik een TagVisualization class.Het is een user-control die twee labels weergeeft: een naam en eenbedrijfsnaam. Op het moment dat deze aangemaakt wordt, wordt hetMyTagVisualization_Loaded event afgevuurd. Hierin kunnen we dankijken wat de bijbehorende Tag-waarde is zodat we de labels kunnenvoorzien van zinnige data.Het enige wat we nu nog moeten doen is de ByteTagVisualizationDefinition die hoort bij de TagVisualizer, aanpassen zodat hij de nieuwe

control gebruikt. Dit doen we door de Source Property in te vullen metde naam van de XAML van de UserControl. Als we het systeem nudraaien en we plaatsen er de juiste tag op, ziet het er zo uit:

Fig. 6: Tags in action

Het rode vierkantje is de gesimuleerde geplaatste tag van de SurfaceSimulator. Ik heb hem iets gedraaid zodat je ziet dat onze UserCon-trol mee draait.Ik geef toe, echt zinvol is deze applicatie niet, maar met een beetjefantasie kun je zelf andere toepassingen bedenken.

In de TagVisualization kun je ook nog aangeven waar de sticker zit ophet fysieke object: het lukt namelijk vrijwel nooit (of is ook niet wense-lijk) om je tag precies recht en in het midden van je object te krijgen.

Identity TagsByte Tags kunnen, zoals de naam al suggereert, een bytewaardebevatten. Als je echter b.v. brieven naar al je klanten wilt sturen, en opdie brieven een unieke tag wilt printen die ze dan in je winkel op deSurface kunnen leggen voor hun speciale, persoonlijke aanbieding,dan heb je aan 255 waardes waarschijnlijk niet genoeg.Je wilt meer mogelijkheden hebben, en om aan die wens tegemoet tekomen is er in Service Pack 1 van de SDK de Identity Tag toegevoegd.De waarde van een Identity Tag is een GUID, dus een getal tussen de0 en 2^128. Je hebt ruwweg 3.4e+38 mogelijkheden. Dat moet, zelfsvoor de grootste bedrijven, voldoende zijn om alle klanten een uniekecode te geven ;-).Identity Tags zijn groter dan Byte Tags. Ze worden ook iets minder snelherkend. Daarom is het aan te raden om Byte Tags te gebruiken voorobjecten die veel verplaatst worden en Identity Tags voor objecten dievrij statisch op het scherm blijven staan.Voor je code maakt het niet veel uit of je Byte Tags of Identity Tagsgebruikt: in de TagVisualizer schrijf je in plaats van een ByteTagVisua-lizationDefinition een IdentityTagVisualizationDefinition en je bent klaar.Oh ja, een Byte Tag heeft een value property, een Identity Tag heeft eenSeries (de eerste 64 bits) en een Value (de laatste 64 bits) property,maar voor de rest zijn ze gelijk. Ze zien er uit als in figuur 7.

Fig. 7: Identity Tag

DeploymentHet installeren van een applicatie op Surface gaat iets anders dan jewellicht gewend bent. De Visual Studio Template genereert een XML-bestand voor je met daarin een aantal settings die je nodig hebt voorhet uitrollen van je applicatie naar de Surface-machine.

Page 34: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

MAGAZINE34

.NETUX

Dit bestand ziet er als volgt uit:

<?xml version="1.0" encoding="utf-8" ?><ss:ApplicationInfoxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:ss="http://schemas.microsoft.com/Surface/2007/

ApplicationMetadata"><Application>

<Title>SDN Surface</Title><Description>Demo applicatie voor de SDN</Description><ExecutableFile>

c:\apps\SurfaceApplication2.exe</ExecutableFile><Arguments></Arguments><IconImageFile>c:\apps\Resources\icon.png</IconImageFile><Preview>

<PreviewImageFile>c:\apps\Resources\iconPreview.png

</PreviewImageFile></Preview><Tags>

<ByteTag Value="2A"><Actions>

<Launch /></Actions>

</ByteTag></Tags>

</Application></ss:ApplicationInfo>

In dit XML-bestand zet je een aantal zaken:1. De titel: deze verschijnt boven het menu-item in het Surface-

menu;2. Een omschrijving: deze verschijnt onder het menu-item in

Surface;3. Het pad naar de executable: dit moet een absoluut pad zijn;4. Eventuele argumenten om je applicatie mee op te starten;5. Een pad naar een plaatje wat als icoon gaat werken: dit is geen

echt Windows ioon, deze plaatjes zijn groter dan dat;6. Een Preview: dit is wat getoond wordt als je applicatie de focus

krijgt in het menu. Dit kan ook een video zijn waarin je laat zienwat je applicatie doet!

Daarnaast heb ik in deze XML ook de tags gedefinieerd. Ik heb de Tag2A (42 dus...) gekoppeld aan onze applicatie. Dit houdt in dat alsiemand, wanneer dan ook, een bytetag op het systeem plaatst metdeze code, hij de mogelijkheid krijgt om de applicatie direct op testarten. Dus: de applicatie kan gestart worden simpelweg door eenobject met de juiste tag te plaatsen.

Dennis Vroegop

Dennis Vroegop is softwarearchitect bij Detrio, waar hij onderandere verantwoordelijk is voor hetbegeleiden van .NET projecten.Hij is een programmeur in hart ennieren en is een echt communitymens. Momenteel is Dennis naastzijn normale werkzaamheden ookvoorzitter van de NederlandsedotNET gebruiksgroep .NET.

AGENDA2009/2010

SDN Event – Hotel Houten, Houten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .14 decemberSDN Magazine Nr. 104 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .26 februariMicrosoft SharePoint Connections 2010 – RAI Amsterdam . . . . . . . . . . . . . . .18 & 19 januariSDN Event . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .26 maartSDN Magazine Nr. 105 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .14 meiTechEd USA, New Orleans . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .7 – 11 juniSDN Event . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .14 juniGenoemde data onder voorbehoud

Dit biedt enorm veel mogelijkheden: denk b.v. eens aan het onderwijs.De onderwijzer geeft aan een groepje kinderen een kaartje met daaropde tag die de rekenapplicatie start. Daarna krijgt een ander groepjeeen kaartje die de taal-applicatie toont. Geen moeilijke menu’s meermaar simpelweg iets op het scherm neerzetten en je applicatie draait!

Om je applicatie uit te rollen moet je alle bestanden kopiëren naar delocatie die in het XML-bestand staat aangegeven. Daarna moet je hetXML-bestand zelf plaatsen in de directory C:\ProgramData\Micro-soft\Surface\Programs. Als je dat gedaan hebt, en je hebt geenfouten in je XML-bestand gemaakt, dan verschijnt je applicatie in hetmenu en je gebruikers kunnen er mee aan de gang!

ConclusieDit is slechts een korte introductie van de hulpmiddelen die je hebt alsje gaat ontwikkelen voor Surface. Maar, als je eenmaal gewend bentaan de omgeving, zul je merken dat de techniek, hoewel uitdagend enspannend, niet de beperkende factor is. Het bedenken van goedeSurface-oplossingen, die gebruik maken van de 360 graden interface,van objecten en het verschil tussen de fysieke en virtuele wereld weg-neemt, dat is een stuk lastiger. Surface is typisch een omgeving voormensen die niet (willen?) weten dat ze met een computer werken, houdaar rekening mee in je ontwerp.De tools zijn er, de hardware is er, nu de ideeën nog! De SDK is eengoed stuk software waarmee je in staat bent om snel productief tezijn. Dus bedenk een goede oplossing, vind een Surface-machine omop te testen en leef je uit! •

De tools zijn er, de hardware is er,nu de ideeën nog!

Page 35: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

magazine voor software development 35

GENERAL

Darkening perspectivesThere are good reasons for increasing productivity and quality. First ofall, we have to increase productivity by a hundred-fold to meet up withcurrent demands, says Gartner. Furthermore, technology is becomingincreasingly complex. Ten years ago I was working in both Microsoftand Java projects. Anno 2009, I’ve let go of the idea that I even havean overview of either one of them. It is hard enough working with asmall subset of frameworks. A Silverlight designer is not likely know-ledgeable in NHibernate. Being a Spring guru does not guarantee foxyJavaFX user interfaces.Despite this darkening perspective, there’s techniques and technolo-gies that might keep you from drowning, by simply raising the level ofabstraction. Good frameworks help. Smart use cases certainly do.And even UML assists. And then there’s model driven developmenta.k.a. model driven architecture a.k.a. model driven engineering a.k.a.domain specific languages. Different names for generating code andother deliverables from a model. What model? To be honest, anymodel will do the trick. Business process models, use case diagrams,user interface models, domain models, and last but not least data mo-dels.

DIYEight years ago I was helping a customer set up the domain model fora help desk application. After that I started to build the software inASP.NET. Having modeled all domain objects, their properties andtheir services, I was typing them out in C#. Then, as any decent de-veloper would do, I wrote a code generator. That helped.I suspect most code generation efforts have a similar empirical start.That’s probably why there are so many approaches to generatingcode. Some really high-brow, squeezing everything-and-the-kitchen-sink into a model, and then trying to generate the whole ap-plication. From front to back. Or, at the very low and of the spectrum,inspecting the database, generating create-read-update-deletescreens in a flat two-tier architecture.

Where’s the value?Recently I was invited in a panel on model driven development, toge-ther with some academic and commercial experts. For starters, eachof the panel members introduced their position briefly to the audience.This noteworthy event learned me two things. One: never allow fourenthusiastic innovators talk freely on their innovations. The word ‘brief’is not in their vocabulary. Two: coming from a business background, Ididn’t have a clue to what model driven development does in the aca-

demic world. A whole new spec-trum of approaches met my eye.

So where’s the value in this? Fol-lowing the good old Scrumadagio I’d say: it depends. Modeldriven development can be highlyrewarding for projects. But I’vealso witnessed projects that

made a terrible mess of it. In my opinion, being successful at modeldriven development requires some preconditions to be met:• Embed approach. Successful model driven development projectsshare a single principle: it’s all in a day’s work. Model driven devel-opment is never a goal. It’s just a means to an end. Making bettersoftware faster. No guru’s, no heroes.

• Allow changes. Projects go through changes. That’s a fact of life.Model driven development should never be blocking changes, butrather should stimulate creativity, by allowing projects to show quic-kly what effect new or changing requirements have.

• Stabilize architecture. Knowing how to model and where to ge-nerate what code is key. Set up a stable (layered) software archi-tecture, pick frameworks that match it, and only then elaborate oncode generation.

• Be pragmatic. My general advice in life also holds for model drivendevelopment. Be pragmatic. Never overdo it. Don’t try to squeezethe whole world in your model. It’s not necessarily a bad thing to stillhave to write some code manually.

Skepticism?Having said all that, and having seen projects that very successfullyapply model driven development, why is there still so much skepti-cism? After all, the paradigm really helps to deliver high quality at highproductivity.After witnessing both highly successful and extremely failing modeldriven development projects recently, I have given this some conside-ration. The vast majority of projects are in the middle of the wide spec-trum of approaches. They run smoothly, being fairly practical. But it’sthe failing projects at either end of the spectrum that draw the atten-tion. Highly complex, slow moving, rigor projects on the one end, andoversimplified, bug-absorbing, underestimated projects on the otherend. It’s no fun at either end.

No Jedi knightMy team and I have always adopted a highly pragmatic approach tomodel driven development, modeling smart use cases, applying do-main driven design, run the model through our code generators (To-bago MDA) and we’re set to go. We do make better software faster.Can life be this simple? It certainly can. We have applied this appro-ach to all kinds of projects, and generated code in a variety of langu-ages and frameworks, from Visual Basic to C#, from PHP and Java toCobol. At the last SDC I checked out a combination of Silverlight, .NETRIA Services, ADF and (maybe) Fluent NHibernate. It was fun!To leave you with some words of wisdom (ahum). If there’s one thingI’ve learned from being successful at model driven development, it’sthis: modeling and generating code should be everyday practice inyour project. There’s no such thing as a “model driven developmentproject”. There’s only software development projects. You don’t haveto be a Jedi knight to steer a code generator. It’s all in a day’s work.

Sander Hoogendoornblog.sanderhoogendoorn.org •

Looking back on twenty years of software development, I must have spent most of that time trying to improve thequality and productivity of software development. Ever since I started to write small applications in Turbo Pascalin 1988 I got infected with the writing-better-software-faster virus. Right after I finished the second of fourteen ofthese applications, I wrote my first framework. It took some effort, but writing the following twelve applicationstook me less time than building the first two.

Interesting Things:Writing Better Software Faster

Page 36: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

Advertentie Avanade

Page 37: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

DELPHI Cary Jensen

LINQ to ObjectsLINQ to Objects is any version of LINQ that does not employ a LINQprovider. Consequently, all LINQ queries that were shown in part 1 ofthis series were examples of LINQ to Objects. Here is anotherexample.

var Customers := GetCustomers;var query := from c in Customers

where (c.Age > 10)and (c.Age < 40)and (c.Active = true) select c;

for each m in query doResultsList.Items.Add(String.Format("Name: {0}, Age={1}"

[m.Name, m.Age]));

If you had wanted to create a query that produced a sequence ofobjects that only included the Name and Age members, you couldhave used the technique shown in part 1, where the select clause re-turned a newly created object (which was an anonymous object inthat example, but could have been any compatible type).In the preceding query, a sequence of Customer objects is returned bythe GetCustomers function. This particular function is an example ofan iterator method. Iterator methods are discussed in the followingsection.

Granted, this is a simple example. However, there are many differentmethods in the .NET framework class library that return arrays,collections, and other queryable data sources. As a result, it ispossible to use LINQ to perform a wide variety of useful tasks.

Examples of some of these uses can be found in the Windows SDKfor .NET 3.5. For example, there are a number of examples of how touse LINQ to explore files and directories on the local file system. Thisis possible because method such as System.IO.Directory.GetFilesreturn an array of strings containing the names of the files in a givendirectory. Arrays, as you’ve seen, can be used in LINQ queries.

Iterator Methods and Yield StatementsIterators are special methods that return a sequence. You declare aniterator by including the iterator modifier in the method signature. Eachelement in the sequence is specifically returned by the iterator througha call to yield.This is demonstrated in the following code sample. First, the iteratoris declared using the following statement.

method GetLowDigits: sequence of Integer; iterator;

Next, the implementation of the iterator includes one or more calls toyield, which, like exit, can be used to return a value (though yield doesnot cause a return from the method in the same way that exit does):

method MainForm.GetLowDigits: sequence of Integer;

begin

for i: Integer := 1 to 9 do

yield i;

end;

The following code demonstrates the use of this iterator:

var numbers := GetLowDigits;

for each n in numbers do

MessageBox.Show(n.ToString);

Iterator methods are not executed when the sequence is assigned toa sequence reference. Specifically, the var declaration and initializa-tion in the preceding code segment did not cause the GetLowDigitsiterator to execute. Instead, it was the specific iteration over thesequence in the for each loop that caused the iterator to be executed.Furthermore, the iterator was not executed all at once. Specifically,the iterator is executed up until it returns the first element of the se-quence (using yield), that element is then used by the for each loop,which will then call back to the iterator to get the next value in thesequence, and so on.

The yield keyword can be used to return either a single element of thesequence or a reference to a sequence (which could be an array, amethod that returns an array, or other similar reference).Here is another example of an iterator and a sequence. This coderequires a type declaration, which looks like the following:

Customer = class

private

FName: String;

FAge: Integer;

public

property Name: String read FName write FName;

property Age: Integer read fAge write FAge;

end;

Here is the declaration of the iterator:

method GetCustomers: sequence of Customer; iterator;

magazine voor software development 37

Introduction to LINQ, part 2In part 1 of this 2 part series I provided you with a basic introduction to Language Integrated Query,or LINQ. In this second part I take a look at several specific implementations of LINQ, includingLINQ to Objects, LINQ to DataSets, and LINQ to XML. I also have an opportunity to introduce ite-rator methods, special methods that you implement to return a sequence for use by LINQ queries.

Examples of some of these usescan be found in the Windows SDKfor .NET 3.5

Page 38: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

MAGAZINE38

DELPHI

And here is the implementation of the iterator:

method MainForm.GetCustomers: sequence of Customer;begin

yield new Customer(Name:= 'Allan', Age := 10);yield new Customer(Name := 'Bob', Age := 25);yield new Customer(Name := 'Craig', Age := 18);

end;

Finally, here is the iteration over the sequence:

var Customers := GetCustomers;for each c in Customers do

MessageBox.Show(c.Name);

The implementation of the iterator in this case used the new namedparameters feature of constructors to return each of the customers(which in reality would have probably been populated with data froman external source, such as a database). Also, the Customers typedeclaration used type inference to determine that Customers variablewas a sequence of Customer.

What is LINQ to DataSets?LINQ to DataSets is a LINQ provider that permits you to use LINQqueries against DataTables, DataRows, and other classes in theADO.NET framework. In order to use LINQ to DataSet, you must addthe System.Data.DataSetExtensions assembly to the references sec-tion of your Delphi Prism project. This section is designed to provideyou with a brief introduction to LINQ to DataSet. As such, it does notgo into ADO.NET, which is the data connectivity framework in .NET.As a side note, LINQ to DataSet should probably be called LINQ toDataTable or LINQ to DataRows, or even LINQ to ADO.NET. None ofthe operations in LINQ to DataSet are performed on instances of theDataSet class. Instead, they are performed on DataTables andDataRows.

As you learned earlier in this series, LINQ queries can be performed onany object that implements the IEnumerable<T> interface. DataTables(and DataRows) do not implement IEnumerable directly. However, theyboth have extension methods that support IEnumerable. These aredefined in the DataTableExtensions class, which is located in theSystem.Data.DataSetExtensions namespace.This last point is an important one, as far as writing applications thatuse LINQ to DataSet is concerned. Specifically, you must add theSystem.Data.DataSetExtensions assembly to your project referencesfolder (if it is not already there) before you can use LINQ to DataSet ina project.There are only three extension methods in the DataSetExtensionsclass. These are AsDataView, AsEnumerable, and CopyToDataTable.For DataTables, the key method is AsEnumerable, which returns anenumerable collection of DataRows (records). This is demonstrated inthe following segment code.

method MainForm.LINQToDataSet_Click(sender: System.Object;e: System.EventArgs);

vabrConnection: DataStoreConnection;Adapter: DataStoreDataAdapter;DataTable1: DataTable;

beginConnection := new DataStoreConnection(conStr);Connection.Open;try

Adapter := new DataStoreDataAdapter

('SELECT * FROM CUSTOMER',connection);

DataTable1 := new DataTable;

DataTable1.TableName := 'Customer';

Adapter.Fill(DataTable1);

var query :=

from cust ibn DataTable1.AsEnumerable

where cust['ON_HOLD'].Equals(DbNull.Value)

and (cust.Field<string>('STATE_PROVINCE') = 'CA');

for each c in query do

begin

ResultsList.Items.Add(String.Format

('Customer Number: {0}' +

' Company Name: {1}',

c['Cust_No'].ToString,

c['Customer'].ToString));

end;

finally

Connection.Close;

end;

end;

Once the DataTable has been populated with data from the SQL query,the AsEnumerable method of the DataTable is called, and this objectis used in the LINQ query. Interestingly enough, the object returnedfrom the AsEnumerable method is a generic IEnumerable<T>, wherethe type is a collection of DataRows.The following figure shows how the sample application looks after thepreceding code is executed.

As you consider this code segment, you might conclude that youwould be better off using a SQL statement that performs the filteringof the results, rather than use a LINQ query. While that may be true insome instances, if you want to load a DataTable once, and performnumerous queries on the returned value, the LINQ query offersperformance benefits. (Note that another alternative is to use a Data-View to filter and sort the DataTable results.)

It’s worth mentioning that in addition to LINQ to DataSet, the .NETframework provides the LINQ to SQL provider. Unlike LINQ to Data-Set, which can be used against any database for which there is a .NETdata provider, LINQ to SQL is specifically designed to work only withMicrosoft SQL Server. LINQ to Entities is another LINQ provider thatcan be used against supported databases.

What is LINQ to XML?LINQ to XML provides a programming model, similar to XPath, withwhich you can create, edit, query, and save XML documents. LINQ toXML provides you an alternative to using the XML DOM (documentobject model), which is what is used by the XMLDocument class in the.NET framework. Similar to the XMLDocument the DOM, LINQ to XMLworks with the XML document in memory. From there you can read,

LINQ queries can be performed onany object that implements theIEnumerable<T> interface

Page 39: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

magazine voor software development 39

DELPHI

query, and write data to the XML document, after which you canstream it to a service or write it to a file, if you desire.

As is the case with the LINQ to DataSet topic that precedes thissection, this discussion is designed to provide you with a basicintroduction to LINQ to XML. It does not, however, cover general XMLissues.

LINQ to XML is far more involved than LINQ to DataSet. This isbecause LINQ to XML not only supports features necessary for que-rying, but as mentioned earlier, an entire programming model forworking with XML. As a result, this section will cover just enoughinformation to get you started.Unlike LINQ to DataSet, where most of the functionality is found inextension methods added to DataTable and DataRow, LINQ to XML,found in the System.Xml.Linq namespace, includes a large number ofconcrete classes that you can use to work with XML documents.Of these classes, there are three that you are likely to use most often.These are XDocument and XElement, which descend from XNode,and XAttribute, which descends from XObject. (XNode, by the way,also descends from XObject.)You can create a valid XML document using either XDocument orXElement, though XDocument provides a little more support for this.Specifically, there are certain advanced features of XML documentsthat you can access through the XDocument class which are unavai-lable through the XElement class. XAttribute, by comparison, is usedto define attributes of XML elements.But before you get started, at a minimum you will need to add theSystem.Xml.Linq namespace to your uses clause. In addition, you mayhave to add one or more of the following additional namespaces,depending on what features your code will use: System.Xml,System.Xml.Schema, System.Xml.XPath, and System.Xml.Xsl.

Creating XML Documents using LINQ to XMLAs mentioned previously, you can create XML documents using eitherthe XDocument or the XElement class. The following example de-monstrates how to create an XML document using the XElementclass.

element :=

new XElement('customers',

new XElement('customer',

new XAttribute('custno', 1001),

new XElement('name', 'John Doe'),

new XElement('address', '101 Broadway Avenue'),

new XElement('city', 'New York'),

new XElement('state', 'NY'),

new XElement('zip', '00123')

),

new XElement('customer',

new XAttribute('custno', 1002),

new XElement('name', 'John Doe'),

new XElement('address', '1001 Main Street'),

new XElement('city', 'Los Angeles'),

new XElement('state', 'CA'),

new XElement('zip', '90123')

)

);

element.Save(XmlFileName);

This code creates an XML file with a root element named customers.The root element has two child elements named customer. Each childelement has one attribute and four child elements. The following ishow the XML file created by this code looks.

<?xml version="1.0" encoding="utf-8"?><customers><customer custno="1001"><name>John Doe</name><address>101 Broadway Avenue</address><city>New York</city><state>NY</state><zip>00123</zip>

</customer><customer custno="1002"><name>John Doe</name><address>1001 Main Street</address><city>Los Angeles</city><state>CA</state><zip>90123</zip>

</customer></customers>

Creating this same file using an XDocument looks similar, though thereare differences. An example of using XDocument appears in the codesample.

The documentation for LINQ with XML includes a large number ofdemonstrations of XML definition using declarations like the oneprovided previously. These declarations, however, are anything butflexible. In other words, they always create the same XML file, whichis rarely useful.The following example, which obtains its data from an ADO.NET datareader, produces an XML file similar in structure to the preceding one,except that its data is entirely based on the results of a SQL query.

Connection := new DataStoreConnection(conStr);Connection.Open;tryCommand := Connection.CreateCommand;Command.CommandText :='select cust_no, customer, address_line1, ' +' city, state_province, postal_code ' +'from customer';

DataReader := Command.ExecuteReader;trydocument := new Xdocument(new XElement('customers'));

while DataReader.Read dobeginattribute :=new XAttribute('custno', DataReader.GetString(0));

element :=new XElement('customer',new XElement('name', DataReader.GetString(1)),new XElement('address', DataReader.GetString(2)),new XElement('city', DataReader.GetString(3)),new XElement('state', DataReader.GetString(4)),new XElement('zip', DataReader.GetString(5))

);element.Add(attribute);document.Root.Add(element);

end;finallyDataReader.Close;

end;document.Save(XmlFileName);

finallyconnection.Close;

end;document.Save(XmlFileName);

LINQ to XML provides a programmingmodel, similar to XPath, with which youcan create, edit, query, and save XMLdocuments

Page 40: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

Windows 7 TIP:Windows 7: Show DesktopDe button voor het tonen van de desktop is verplaatst en zit nunaast de klok aan de rechterkant.

MAGAZINE40

DELPHI

Querying with LINQ to XMLQuerying using LINQ to XML is similar to other LINQ queries, thoughthere are classes and methods that you use in LINQ to XML that arenot found in other LINQ technologies. In short, once you have areference to a queryable object (an IEnumerable, a sequence, or othersimilar construct), you use query statements to retrieve the data youare interested in. The following example demonstrates a LINQ to XMLquery.

element := XElement.Load(XmlFileName);

var childList :=

from el in element.Elements

where String(el.Element('state')) = 'CA'

order by String(el.Attribute('custno')) desc

select new XElement('document',

new XElement('CustomerName', el.Element('name')),

new XElement('Address', el.Element('address')),

new XElement('CityStateZip',

el.Element('city').Value +

', ' + el.Element('state').Value +

' ' + el.Element('zip').Value));

for each e in childList do

begin

ResultsList.Items.Add(e.Element("CustomerName").Value);

ResultsList.Items.Add(e.Element("Address").Value);

ResultsList.Items.Add(e.Element('CityStateZip').Value);

ResultsList.Items.Add(String.Empty);

end;

This query returns a sequence of XElement references, which have astructure similar to, though different than, the original XElements. Forexample, the new XElements are not named customer, they arenamed document. Furthermore, there are no attributes in the newXElements, and there are only three child nodes.

The preceding example demonstrated a query using the XElementclass. The following code shows the same basic query, however anXDocument is used in this example.

document := XDocument.Load(XmlFileName);

var childList :=

from el in document.Descendants

where String(el.Element('state')) = 'CA'

order by String(el.Attribute('custno')) desc

select new XElement('document',

new XElement('CustomerName', el.Element('name')),

new XElement('Address', el.Element('address')),

new XElement('CityStateZip',

el.Element('city').Value +

', ' + el.Element('state').Value +

' ' + el.Element('zip').Value));

for each e in childList do

begin

ResultsList.Items.Add(e.Element("CustomerName").Value);

ResultsList.Items.Add(e.Element("Address").Value);

ResultsList.Items.Add(e.Element('CityStateZip').Value);

ResultsList.Items.Add(String.Empty);

end;

Modifying XML using LINQ to XMLOnce XML is in memory, you can add elements or attributes, removeelements or attributes, as well as modify the data for elements orattributes. If you load the XML from an existing source, such as a file,make modifications, and then save the XML back to the originalsource, you have effectively changed the XML. This is demonstratedin the following code.

document := XDocument.Load(XmlFileName);

var childList :=

from el in document.Descendants

where String(el.Element('state')) = 'CA'

order by String(el.Attribute('custno')) desc

select el;

//make changes

for each e in childList do

begin

e.Element('state').SetValue('California');

end;

//save the changes

document.Save(XmlFileName);

There is an important characteristic of the preceding code that youshould note. Specifically, the select clause of the LINQ to XML queryreturned a sequence of XElements from the original XDocument. Whilethese represent a possible subset of all XElements returned by theDescendants method of the XDocument, they are still child elementsof the original XDocument.When changes are made to the items in the sequence returned by thequery, those changes are actually being made to the correspondingXElements in the XDocument. This is why the changes are preservedwhen the subsequent call to XDocument.Save is made.By comparison, if the select clause had created new XElements,similar to how the last query in the preceding section demonstrated,the subsequent changes would have been performed on the newlycreated objects, which are not child elements of the XDocument.

SummaryThis two part series has provided you with a brief introduction toLINQ with Delphi Prism. Here you have learned how to constructLINQ Queries, the nature of LINQ to Objects, define and implementiterators, and have been given a preview of LINQ to DataSets andLINQ to XML. •

Cary Jensen

Cary Jensen is President of JensenData Systems, Inc., a training andconsulting company that won the2002 and 2003 Delphi InformantReaders Choice Awards for BestTraining. He is an award-winningauthor of 20 books, including

Advantage Database Server: A Developers Guide (2007, Sybase),Building Kylix Applications (2001, Osborne/McGraw-Hill), JBuilderEssentials (1998, Osborne/ McGraw-Hill), and Delphi in Depth(1996, Osborne/McGraw-Hill).For information about onsite training or consulting services, youcan contact Cary at [email protected] or visithis web site at www.JensenDataSystems.com.

Page 41: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

DOTNETNUKE

Brandon Haynes

While in some cases these services serve merely to expose aneasy-to-consume interface to already-existing .NET functionality (e.g.encryption and permissions), in many instances these services wouldnot be available at the ASP.NET level without significant additional work(or by the consumption of an external library). Additionally, extensi-ons which rely on core functionality are able to benefit from subse-quent enhancements to the framework, typically without anymodifications to the extension itself. Because of this, DotNetNukedevelopers are often able to design and deploy modules and extensi-ons that are more secure, more quickly, and with less developmenteffort expended.

Herein we review some of the security-related services that areoffered by the core DotNetNuke framework and discuss their abilityto defend against real-world threats.

Framework-Managed Authorization and LifecycleDotNetNuke handles much of the routine authorization and instantia-tion logic on behalf of a developer. When a module is installed, it mayregister one or more controls that require explicit permission toaccess. When the module is later added to a page, an authorizedparty associates the ability to view and edit that instance with one ormore security roles. Thereafter DotNetNuke manages this associa-tion; users who are not a member of one of the authorized roles willnot only be disallowed from utilizing the associated control, but thecontrol itself will not even be instantiated by the framework. The factthat the control is neither instantiated nor added to the control hierar-chy ensures that some forms of attacks are made more difficult, and,most saliently, moves the responsibility for authorization out of thehands of the module developer and into the framework (where itshould be). Only in specific scenarios will a module developer need toimplement additional authorization logic at all.

The DotNetNuke.Security.PortalSecurity ClassThe PortalSecurity class contains a number of methods that may beleveraged by developers. In general, these methods may be catego-rized into groups that address input sanitization, encryption, privacy,and authorization. These methods are summarized in table 1. Weexplore each of these in more detail below.

Table 1: The public methods of the DotNetNuke.Security.PortalSecurity class

PortalSecurity.InputFilterBy far the most commonly-used method by module developers,DotNetNuke offers an InputFilter method that is designed to aid inreducing some of the most common data sanitization issues anextension developer is likely to experience. A flag specifies which ofthe five filter types are performed; we explore the subtleties of theseflags in turn.

FilterFlag.NoMarkupWhen this flag is set, the text is returned HTML-encoded if and only ifthe source text contains one or more tags (i.e. elements with anopening and closing marker such as <tag>). This is by far the mostsecure filter with which to sanitize untrusted input, as it effectively fullymitigates the risk of malicious markup. Note that for data that areintended to be displayed as HTML (e.g. a forum post that by-designallows for limited markup), this method might not be suitable, as it willencode everything, including authorized markup.

Table 2 illustrates some of the transformations that are performed bythis filter method.

magazine voor software development 41

Under the Hood: Security Services in

DotNetNuke 5.1DotNetNuke is a highly robust web-application framework that is ideally suited for a wide varietyof purposes, from simple websites to enterprise applications. Associated with the frameworkis a team of security professionals who are dedicated to ensuring that third-party developers areable to create secure modules (and that the DotNetNuke framework itself is maximally securedagainst external threat). In this way, DotNetNuke developers are able to quickly leveragesecurity services provided by the core framework, allowing for more rapid development andincreased overall quality.

DotNetNuke developers are oftenable to design and deploy modulesand extensions that are more secure,more quickly, and with lessdevelopment effort expended

PortalSecurity Method

Description

InputFilter Used to prevent malicious cross-site scripting (XSS) or SQL injection attacks.

Encrypt Encrypts a string given a key and value. Decrypt Decrypts a string given a key and value. CreateKey Creates a key of a given size using a cryptographically-strong

algorithm. ForceSecureConnection Requires that the current page be requested via the HTTPS

protocol. SignOut Deauthorizes a user from the ASP.NET forms authentication

system and clears all DotNetNuke-related cookies. ClearRoles Clears all cached role cookies associated with the current user.

Page 42: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

MAGAZINE42

DOTNETNUKE

Table 2: Some sample HTML transformations using InputFilter withFilterFlag.NoMarkup

FilterFlag.NoScriptingWhen this flag is set, the InputFilter method attempts to remove anymalicious markup within the input, as defined by a set of blacklistedHTML tags (e.g. form, script, and object). An appropriate use for thisflag would be in instances where some limited HTML input waspermitted (for example, a forum post) but malicious script mustnonetheless be defended against. Because this configuration utilizesa blacklist set of disallowed tags, as opposed to a stronger whitelistset of allowed tags, this flag should only be used over FilterFlag.NoMarkup when specific use-scenario warrants its use.

FilterFlag.NoSQLIn a manner similar to the FilterFlag.NoScripting flag above, setting thisflag causes a blacklisted set of dangerous SQL tokens to be removedfrom an untrusted source. In this manner, a developer may protectagainst SQL injection attacks - especially when the input text is usedin conjunction with ad-hoc or dynamic SQL execution. Note, howe-ver, that many modern development techniques (such as parameteri-zed stored procedures) offer greatly increased protection over thatwhich is afforded here. Whenever possible, these techniques shouldbe relied upon, and the FilterFlag.NoSQL filter should be used asecondary line of defense.

FilterFlag.MultiLine and FilterFlag.RemoveAngleBracketsThese flags exist, respectively, for legacy and one-off scenarios, andas such should rarely (if ever) be used during development. TheMultiLine flag was historically utilized to replace newlines with a HTMLline-break tag (“<br />”); this flag is no longer used within the coreframework and exists as a likely candidate for deprecation.Similarly, the RemoveAngleBrackets flag simply removes angle brac-kets (“<” and “>”) from the input if and only if a RemoveAngleBracketskey is specified in the appSettings portion of the web.config. This flagdoes not provide any meaningful security (especially over the NoMar-kup flag discussed above), and was included at the request of a majorcustomer (1). As such, few if any circumstances exist that wouldwarrant its use.

Combining Flags and CaveatsBecause the flags associated with the InputFilter method exist asa bit field, multiple flags may be specified within a single call. Anexample of this is demonstrated in listing 1, where the input data willbe encoded (via the FilterFlags.NoMarkup bit) and all blacklisted tagswill be stripped (via the FilterFlags.NoScripting bit).

Dim untrustedText =_

“<h1>Markup</h1><script>alert(‘’);</script>”

Dim sanitizedText = New PortalSecurity()

.InputFilter(untrustedText, _

FilterFlag.NoMarkup Or Filterflag.NoScripting)

Debug.Assert(sanitizedText = “&lt;h1&gt;Markup&lt;/h1&gt;”)

Listing 1: A sample InputFilter call specifying two flags

In general, the flags may be combined in any way that an end-developer desires, though in virtually all circumstances dealing withuntrusted or user-supplied text the FilterFlag.NoMarkup bit will be set.However, there is one important exception to this rule that should be

noted – whenever the NoSQL flag is specified, the NoMarkup,NoScripting, and Multiline flags are ignored. Since the NoSQL flag isdesigned to be used whenever a dynamic or ad-hoc SQL statementis about to be executed this is generally acceptable, but a developershould nonetheless be aware of this subtle behavior.

PortalSecurity.Encrypt, PortalSecurity.Decrypt, and PortalSecurity.CreateKeyThese two methods, given a key and input, encrypt and decrypt theinput and return it as a base64-encoded string. In this way, moduledevelopers may quickly obfuscate data that may be recoveredelsewhere.However, due to concerns about backward-compatibility, both ofthese methods internally utilize the DES algorithm. This algorithm islargely considered to be weak, and has been widely deprecated (3).Because of this, developers who require cryptographically-secureprotection are advised to utilize other algorithms (such as AES orTriple-DES) until the DotNetNuke framework is enhanced to utilize astronger encryption method; this is likely to occur in future release.Finally, the PortalSecurity.CreateKey utilizes the RNGCryptoService-Provider to generate a sequence of n pseudo-random bytes; thesebytes are encoded as a hexadecimal string before being returned.This algorithm is considered to be secure, and may safely be utilizedfor cryptographic purposes (4). A code sample demonstrating thegeneration of a 128-bit key is illustrated in Listing 2.

Dim myKey As String = _

New PortalSecurity().CreateKey(128 / 8)

Listing 2: Sample code illustrating the generation of a 128-bitcryptographically-strong key

PortalSecurity.ForceSecureConnectionWhile DotNetNuke offers robust privacy options at the page level,allowing an administrator to require a private and confidentialexchange (via SSL), there is currently no such option exposed at themodule level. Thus, for modules which might present information thatmust not be viewed by third parties, it is up to the developer to ensurethat privacy is maintained.The PortalSecurity.ForceSecureConnection may be utilized for thispurpose; when called, it will ensure that the HTTPS-protocol is in usefor the current request, and, if not, will redirect to a URI that utilizes aHTTPS-connection. Developers should carefully consider thesensitivity of the data presented in a module in determining if dataprivacy should be a precondition of display.

PortalSecurity.SignOut and PortalSecurity.ClearRolesThe PortalSecurity.SignOut method may be utilized to de-authorize auser from the DotNetNuke application. In addition to making a call toFormsAuthentication.SignOut, this method explicitly clears all Dot-NetNuke-related cookies (e.g. current language, authentication type,and cached portal association).Similarly, the PortalSecurity.ClearRoles method clears the security rolesassociated with a user that might be cached in that user’s cookies.This method is useful when a role is added or removed from thecurrent user; a call to ClearRoles will ensure that the change isreflected immediately (rather than after cache expiration).

PortalSecurity.IsInRole and PortalSecurity.IsInRolesAs their names suggest, these methods are used to determine if thecurrently-authorized user is a member of a given role (or roles). Whenutilizing the plural version, a semicolon-separated list of roles isexpected (e.g. “All Users;Subscribers”). Deny permissions may beincluded by including a “!” prefix on any role. For example, “!Subscri-bers” would return false for any user who was a member of theSubscribers role.

Input InputFilter(Input, FilterFlag.NoMarkup) Regular Text Regular Text Text with <Markup /> Text with &lt;Markup /&gt; &lt;Already Encoded Markup /&gt; &lt;Already Encoded Markup /&gt; Text without markup: 5 > 3 Text without markup: 5 > 3

Page 43: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

magazine voor software development 43

DOTNETNUKE

Listing 3 illustrates some uses of these methods.

If(PortalSecurity.IsInRole(“Administrators”)) Then

Response.Write(“You are an administrator.”)

Else If(PortalSecurity.IsInRoles(“Gold User;Subscribers”)) Then

Response.Write(“You are a gold user OR you are a subscriber.”)

End If

Listing 3: Sample code illustrating the use of the PortalSecurity.IsInRole and PortalSecurty.IsInRoles methods.

File System ServicesDotNetNuke exposes a robust set of classes and static utility methodsthat may be used to interact securely with the file system. In manycases the appropriate leveraging of these services will save a develo-per considerable time and effort in effectuating a design, and at thesame time serve to increase overall application-security. In thissection we briefly examine the objects and utilities available to such adeveloper.

The low-level classes used to interact with the file system throughDotNetNuke are located in the DotNetNuke.Services.FileSystemnamespace. At this level, the most commonly used classes will bethe two controllers FileController and FolderController along with theirrespective entities, FileInfo and FolderInfo. However, DotNetNuke alsoexposes a set of (generally static) utility methods that are sufficient tomeet the needs of most developers. Whenever possible, utilize thesemethods, located in the DotNetNuke.Common.Utilities.FileSystemUtilsclass.

In addition to files stored on the server’s file system, DotNetNukeoffers two additional storage methods: the secure file system anddatabase-secured files. Files persisted to the secured file system arepersisted to the server file system as usual, except that the file has a“resources” extension appended to its name. Because files with thisextension are not served by IIS, all such files are inaccessible by directURI request, and may only be accessed via a special DotNetNukeHttpHandler (accessed via LinkClick.aspx) or through the DotNetNukeAPI. Database-persisted files are, as one would expect, storeddirectly inside the database, and like their secured file systemcounterparts, may only be accessed via API. Irrespective of storagestrategy, the DotNetNuke API may be used to access all files within theapplication. To this end, all relevant methods require an instance of theenumeration FolderController.StorageLocationTypes to indicate whichstorage method is expected (unsecured, secured, or database-secured). Table 3 summarizes these storage types.

Table 3: Members of the StorageLocationTypes enumeration, usedto indicate where a file is stored in a DotNetNuke installation.

Exceptions, Logging, and Disclosure-PreventionThe Common Weakness Enumeration (CWE) classifies error informa-tion message leaks as being one of the most dangerous security-related programming errors (5), yet many developers remain unawareof the consequences associated therewith. To this end, DotNetNukeoffers a number of logging and exception-handling methods designedto properly deal with errors and present minimal information useful toan attacker.Developers will typically utilize the methods in the ExceptionLogCon-troller class and Exceptions module when preventing the disclosureof exceptions. The ExceptionLogController exposes a single method,AddLog, with several overloads for specific situations. Developers willtypically utilize this method in situations where an exception needs tobe logged but the module is otherwise able to handle the issue andproceed. Listing 4 illustrates one such example.

Try

Using myReader As New StreamReader("myFile.txt")

' Use the stream ...

End Using

Catch ex As FileNotFoundException

Dim controller = New ExceptionLogController()

controller.AddLog(ex)

' Recover and continue ...

End Try

Listing 4: Sample code illustrating the use of ExceptionLogController.AddLog, where a module needs to log the issue, but isotherwise able to recover and continue.

Some errors may be anticipated at design-time but aren’t otherwisehandleable by a developer. In this case, the module should takeadvantage of the ProcessModuleLoadException method of theExceptions module; this pattern is illustrated in listing 5.Note that uncaught exceptions, including those that are not anticipa-table at design-time, will still be caught by the framework, where anappropriate error message will be displayed (with no risk of informa-tion leakage).

Try

DoSomethingThatMightCauseAnUnexpectedException()

Catch ex As MyUnexpectedException

ProcessModuleLoadException(myErrorMessage, Me, ex, True)

End Try

Listing 5: Sample code illustrating the use of Exceptions.Process-ModuleLoadException method.

Security Policy ServicesDotNetNuke is designed to run in a wide range of environments,including both medium trust and custom security configurations. Fordevelopers that need to take advantage of functionality that may notbe authorized in a particular environment, the DotNetNuke frameworkoffers several methods to aid in determining this fact. The DotNet-Nuke.Framework.SecurityPolicy class is used to this end.Table 4 summarizes the relevant methods available to developers.

Table 4: Policy-Relatedmethods of the DotNetNuke.Framework.SecurityPolicy class

Storage Location Type

Description

InsecureFileSystem Files persisted under this storage type are written to the underlying file system as-is, and may be served directly by IIS (usually bypassing both DotNetNuke and ASP.NET).

SecureFileSystem Files persisted with this type are written to the underlying file system with a “resources” extension, ensuring that it will not be served by IIS (and thereby is not accessible by direct URI).

DatabaseSecure With this storage method, files are persisted directly in the DotNetNuke database. This is the arguably the most secure method of storage, but also the least efficient.

Method Name Description HasAspNetHostingPermission() Indicates whether the application has been

granted the AspNetHostingPermission permission HasReflectionPermission() Indicates whether the application has been

granted ReflectionPermission HasWebPermission() Indicates whether the application has the

WebPermission permission.

Whenever possible, utilize themethods located in the DotNetNuke.Common.Utilities.FileSystemUtilsclass for file system manipulation

Page 44: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

DOTNET

NUKE

ConclusionThe DotNetNuke framework is designed with security in mind, andoffers framework-level solutions to meet the most common concernsof extension developers. Through the judicious use of the DotNet-Nuke authorization, privacy, input filtering, policy, and exception-management services, developers may focus on the implementationof business functionality rather than often-tedious security details.Because of this, DotNetNuke developers are able to design anddeploy extensions that are more secure, more quickly, and with lessoverall development effort.

References1. Cullmann, Stefan. Upcoming Form and List Features: Private

Columns and Filters. DotNetNuke. [Online] November 15, 2008.[Cited: September 22, 2009.] http://www.dotnetnuke.com/Community/Blogs/tabid/825/EntryId/2081/Upcoming-Form-and-List-Features-Private-Columns-and-Filters.aspx.

2. Connolly, Cathal. DotNetNuke Module Security: Filtering User-Entered Text. The Mighty Blog. [Online] April 23, 2009. [Cited:September 25, 2009.]http://www.willstrohl.com/Blog/tabid/66/EntryId/377/DotNet-Nuke-Module-Security-Filtering-User-Entered-Text.aspx.

3. Kelly, S. Security Implications of Using the Data EncryptionStandard (DES). 2006. RFC 4772.

4. Eastlake III, D., Schiller, J. and Crocker, S. RandomnessRequirements for Security. 2005. RFC 4086.

5. The MITRE Corporation. 2009 CWE/SANS Top 25 MostDangerous Programming Errors. Common Weakness Enumera-tion. [Online] 1.3, July 27, 2009. [Cited: September 15, 2009.]http://cwe.mitre.org/top25/. •

Brandon Haynes

Brandon Haynes (brandonhay-nes.org) is a member of the Dot-NetNuke core team, and servesprimarily by providing security-rela-ted guidance. He is the chief execu-tive officer at Everysport.net Inc.,which delivers enterprise resourceplanning, web-presence, e-com-merce, and integration-related func-tionality to recreational facilities.

A graduate of the University of Illinois at Urbana-Champaign -consistently ranked among the top-five computer-science pro-grams worldwide - Brandon has a long history of intellectual cu-riosity and accomplishment. With more than twenty years ofexperience in software development, Brandon’s professional in-terests are currently focused on the nexus between intellectualproperty law, technology, and business. He is currently pursuinga graduate degree at Harvard University.

Windows 7 TIP:Windows 7: ZoomMet Windows-toets plus (+) en min (-) kun je inzoomenop gedeelten van je scherm, erg handig bij het geven vanpresentaties.

Advertentie 4DotNet

Page 45: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

INFORMATIONWORKER Paul Keijzers

Fig. 1: Google Maps documentatie

Er zijn 3 versies van de Google API beschikbaar. Versie 2 is de meestrecente productie versie. Versie 3 is een beta-versie en heeft met namevoor applicaties voor de mobiele telefoon een aantal leuk features.Dit artikel is gebaseerd op het gebruik van versie 2.De API's van Google Maps zijn goed gedocumenteerd. In dezedocumentatie staat ook dat er per website een API key aangevraagdmoet worden. Deze aanvraag geldt per root van de site. Aanvragen enregistreren van de site gaat via de signup:http://code.google.com/intl/nl-NL/apis/maps/signup.html.Hiervoor dien je de beschikking te hebben over een Google account(zie figuur 2).

Fig. 2: Aanmelden bij Google Maps

magazine voor software development 45

Create and use ofGoogle maps web partDit artikel beschrijft de mogelijkheden van een

Google Maps webpart in een SharePoint

Portal omgeving en hoe deze o.a. gebruikt

worden door het Spaarne Ziekenhuis. Het

webpart heeft als doel het inzichtelijk maken

van de huisartsen in de regio van het zieken-

huis. Een dergelijke webpart is niet beschik-

baar als standaard voor een MOSS omgeving

en is natuurlijk een leuke uitdaging om te

bouwen. Rest de vraag wat heeft men allemaal

nodig om dit webpart aantrekkelijk te maken

en meerwaarde te geven? Vragen die hierbij

naar boven kwamen waren onder andere: hoe

kan men de locaties ophalen, wat voor iconen

zijn intuïtief voor gebruiker en hoe wordt de

plaats aangeven ...

De vraag van de klantHet Huisartsen-portaal wordt, onafhankelijk van het ziekenhuis,aangeboden in een eigen, beveiligde omgeving (conform NEN-normen voor de zorg). Transport van data tussen de praktijken vanhuisartsen en zorginstellingen vindt plaats via een SSL-verbinding.Het portaal (gebaseerd op het Microsoft Office SharePoint Server 2007platform) is ontwikkeld en wordt beheerd door de afdeling ICT van hetSpaarne Ziekenhuis.Het Spaarne Ziekenhuis sponsort de ontwikkeling van dit portaalconform de wensen van de huisartsen, op basis van de bestaandetechnologie. Door gebruik te maken van al aanwezige techniek en ken-nis wordt het portaal kostenneutraal aangeboden aan de huisartsen.Het doel van het Spaarne Ziekenhuis ligt in de verbetering van de ke-tenzorg, waardoor zij haar interne processen verder kan optimaliseren.Het Google Maps webpart biedt de mogelijkheid om te zien welkehuisartsen in een bepaalde regio actief zijn. Daarmee toont het infor-matie van zorgverleners in de regio, zodat in geval van b.v. vakantie dehuisarts de zorg voor een cliënt tijdelijk kan overdragen.

Waar te beginnen?Het vertrekpunt om een Google Map webpart te bouwen is inzicht krij-gen in de werking, en hiermee API, van Google Maps. Google heeftuitgebreide informatie op de volgende site:http://code.google.com/intl/nl-NL/apis/maps/documentation/

Page 46: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

MAGAZINE46

INFORMATION

WORKER

Er zijn vier belangrijke punten waarop gelet moet worden bij hetbouwen en deployment van het webpart.Het eerste is dat het verwijderen of wijzigen van het webpart van/opde portal tot gevolg kan hebben dat er opnieuw een key aangevraagdmoet worden. Omdat versie 3 nog in beta is, is daarvoor geen keynodig.In deze business case wordt er de portal aangeboden via een SSL-verbinding en wordt de kaart opgevraagd in Internet Explorer 8. Indeze situatie is een Premium Membership verplicht. Google heeft alsdoel de maps voor iedereen zichtbaar te maken.Het derde punt is dat Google Maps voornamelijk werkt met Java-Script, wat voor het webpart inhoudt dat er HTML gerenderd moetworden.Tenslotte worden plaatsbepalingen binnen een Google Map opgege-ven (of uitgelezen) via de latitude- en longitude-coördinaten. Latitudebeschrijft de locatie van een plaats op aarde ten Noorden of tenZuiden van de evenaar, en longitude beschrijft de locatie van eenplaats op aarde ten Oosten of ten Westen van een Noord-Zuid lijn (denul meridiaan).Tom Tom en andere navigatie apperatuur werken ook met dezegegevens om je naar de juiste plaats te brengen.

Vervolgens ben ik voor de zekerheid nog even op Codeplex gaankijken of er niet al een kant en klare oplossing was die mij veelontwikkeltijd zou kunnen schelen. Na het testen van verschillendemogelijkheden kwam ik elke keer met hetzelfde resultaat. Het resultaatwas dat er een grijs vlak werd getoond met Google erin maar nergenseen Map (dit komt waarschijnlijk omdat er wijzigingen zijn gedaan dieniet getest zijn bij Google)?

Omdat de adressen van de huisartsen bekend zijn, kunnen dezecoördinaten opgehaald en opgeslagen worden. De coördinatenworden bij het gebruikersprofiel van de huisarts opgeslagen(huisartsen zijn de gebruikers van het portaal).

Fig. 3: MyGeoPosition levert de coordinaten voor een Google Mspslocatie

Het webpart zelfHet maken van het webpart kan eenvoudig via Visual Studio 2008.Hierbij is het aan te raden om met WSP-Builder te werken. Wanneerje WSP-Builder geïnstalleerd hebt, krijg je de mogelijkheid om projec-ten aan te maken van het type WSP.Zo’n project bestaat uit de volgende elementen:• een feature, bestaande uit het manifest (feature.xml) en eenelements-file (elements.xml);

• de webpart definitie (HiszMaps.webpart);• de webpart class (de logica).

Het vertrekpunt is het maken van een feature waarmee de webpartgeïnstalleerd kan worden. Het voordeel van een feature is o.a. deherbruikbaarheid. Het manifest beschrijft de applicatie (in dit geval hetwebpart) en geeft aan welke elementen (files) er nodig zijn om hetwebpart goed te installeren.

Het manifest van de feature ziet als volgt uit.

<?xml version="1.0"encoding="utf-8"?><Feature xmlns="http://schemas.microsoft.com/sharepoint/"Id="D37F0226-5712-44b3-AF52-4E3CADB63A77"Version="0.0.0.1"Title="SpaarneZiekenhuis HiszMaps Webpart"Description="Toont artsen in een Google Map."Scope="Site"ImageUrl="SZFeatureImage.gif"ImageUrlAltText="SpaarneZiekenhuis Feature"Hidden="FALSE"><ElementManifests><!-- Verwijzingen naar element-file en webpart-file beide

in feature directory→<ElementManifest Location="elements.xml" /><ElementFile Location="Webparts/HiszMaps.webpart" />

</ElementManifests></Feature>

In dezelfde map als het feature-manifest dient een elements-file ge-plaatst te worden. Hierin staat aangegeven dat het een webpart is datin de webpartlijst beschikbaar moet komen. Deze ziet er als volgt uit:

<Elements xmlns="http://schemas.microsoft.com/sharepoint/"><Module Name="WebParts" List="113"

Url="_catalogs/wp" Path="Webparts"><File Url="HiszMaps.webpart" Type="GhostableInLibrary">

<Property Name="Group" Value="SpaarneZiekenhuis" /></File>

</Module></Elements>

En als laaste het webpart-file:

<?xmlversion="1.0"encoding="utf-8"?><webParts><webPart xmlns="http://schemas.microsoft.com/WebPart/v3"><metaData><type name="SpaarneZiekenhuis.Core.WebParts.HiszMaps,

SpaarneZiekenhuis.Core, Version=1.0.0.0,Culture=neutral,PublicKeyToken=11a665981f0e5261" />

<importErrorMessage>Cannot import HiszMaps Web Part.

</importErrorMessage></metaData><data><properties><property name="Title" type="string">

HiszMaps Web Part</property><property name="Description" type="string">Toont artsen in een Google Map.

</property></properties>

</data></webPart>

</webParts>

IW TIP:Een goede website om snel de coördinaten te vinden op basisvan een adres is http://mygeoposition.com/

Page 47: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

magazine voor software development 47

INFORMATION

WORKER

Het webpart-file geeft aan wat de eigenschappen zijn van het webparten welke assembly deze moet gebruiken (type). Bij de Type Namestaat de verwijzing naar de code class, in dit geval dus “SpaarneZiekenhuis.Core.Webparts.HiszMaps”.

Het totaal plaatje van de feature ziet er nu zo uit:

Fig. 4: Naam van het webpart-file

De Webpart ClassDe class Hiszmaps erft over van deSystem.Web.UI.WebControls.WebParts.WebPart.In de class zijn de volgende properties gedefineerd.• apiKey: key die Google nodig heeft om te kunnen valideren;• mapWidth: breedte van het webpart in totaal;• mapHeight: hoogte van het webpart in totaal;• zoomLevel: dit is in hoeverre de map ingezoomd is tussen 1 en 19;• infoWindowHtml: dit is om de HTML van de getoonde ballon aan tekunnen passen;

• Longitude: de longitude van de beginplek;• Latitude: de latitude van de beginplek;• MapType: de manier waarop Google de kaart laat zien (road,satelite of hybride).

Indien het mogelijk moet zijn om een van de eigenschappen van hetwebpart te kunnen wijzigen via het (web)interface, kun je de volgendecode gebruiken:

[Personalizable(PersonalizationScope.Shared),WebBrowsable(true),Category("Hiszmaps"),WebDisplayName("google Api key"),WebDescription("google api key")]

Public string APIKey{

Get {return _apiKey; }Set {_apiKey = value; }

}

Uiteindelijk ziet het editor-window er dan zo uit:

Fig. 5: Editen van properties van hetwebpart

Om de Google Map op het webpart tetonen dient eerst een instantie van hetGooglemapControl.GMapControl aan-gemaakt te worden. In de Create-ChildControls-functie wordt de classGMapControl aangeroepen en wordende properties van de GMapControl ge-vuld. Vervolgens wordt de control toe-gevoegd aan de controls-collectionvan de pagina.

Protected override void CreateChildControls(){// add mapGooglemapControl.GMapControl gM = newGooglemapControl.GMapControl(MapWidth,MapHeight);gM.GoogleMapLicense = APIKey;gM.WidthMap = MapWidth;gM.HeightMap = MapHeight;Width = MapWidth;Height = MapHeight;gM.Enabled = true;gM.InfoWindowHtml = InfoWindowHtml;gM.Markers = GetHuisartsAddresses();gM.zoomLevel = ZoomLevel;gM.mapThemeType = mapThemeType;Controls.Add(gM);base.CreateChildControls();

}

De eigenschappen van het GMapControl zijn instelbaar, doordat dezevia de webparteigenschappen doorgegeven worden. De werkingwordt verderop uitgelegd dit artikel.

De volgende eigenschappen zijn van belang voor de GMapControl:• GoogleMapLicence: licentie die je aan kunt vragen bij Google (hiereen Premium Member licentie);

• WidthMap: breedte van het Google Map kaartje;• HeightMap: hoogte van het Google Map kaartje;• Enabled: mogelijkheid om in/uit te zoomen, te scrollen binnen hetkaartje;

• InfoWindowHtml: stukje tekst (in HTML) met informatie over hetkaartje;

• Markers: posities die in het kaartje moet worden aangezet;• ZoomLevel: standaard percentage waarop ingezoomd wordt;• MapThemeType: manier waarop het kaartje getoond moet worden;hier kan gekozen worden voor Hybrid, Satellite en Normal.

Om de huisartsenposten te laten zien in de kaart wordt bij gM.Markersde methode GetHuisartsAddresses() aangeroepen. Deze methodegeeft een Arraylist terug van alle namen en posities van de huisartsen.Vervolgens, om de HTML en bijbehorende JavaScript te genererenvan het webpart wordt, de Render-functie aangeroepen.

Protected override void Render(HtmlTextWriter writer)

{

Try

{

string str = "";

writer.Write(str);

RenderChildren(writer);

ClientScriptManager csm = Page.ClientScript;

csm.RegisterStartupScript(this.GetType(), "refreshMap",

"<script>map.checkResize(); </script>");

}

catch (Exception ex)

{

//log to file splogger…

}

}

Door een ClientScriptManager toe te voegen aan de pagina wordt deuiteindelijke Javascript beschikbaar gemaakt voor de gebruiker.Nu de webpart-class klaar is kunnen we verder met de GmapControl-class.

GMapControl-classBovenaan de class wordt de Control gegenereerd ,in dit geval dus deGmapControl.De class erft over van de Webcontrol.

Page 48: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

MAGAZINE48

INFORMATION

WORKER

[DefaultProperty("Text")][ToolboxData("<{0}:GMapControl runat=server></{0}:GMapControl>")]

//generates custom control

Public class GMapControl : WebControl

In deze control worden dezelfde eigenschappen opgenomen als in hetwebpart, zodat het kaartje met de juiste informatie wordt gegenereerd.In deze class wordt in een functie het hele script voor de Google Mapcontrol opgebouwd. De JavaScript code wordt middels een String-Builder opgebouwd.

Een Google Map wordt middels een JavaScript- include op hetscherm geplaatst. Het script begint met het toevoegen van dezereference-url:

Script.Append(string.Format(CultureInfo.InvariantCulture,@"<script

src=""http://maps.google.com/maps?file=api&v=2&key={0}""type=""Text/javascript""></script>",

GoogleMapLicense))

Om de map te tonen is het nodig om in de pagina de locatie aan tegeven. Dit gebeurt middels een DIV-tag met een bepaalde Id.De Google Map wordt op de locatie van deze DIV-tag getoond.

Script.Append(string.Format(CultureInfo.InvariantCulture,@"<div

id=""large-google-map""style=""width:{0}px;height:{1}px;""></div>",

WidthMap, HeightMap));

Voor de posities van de adressen (markers) wordt een hidden textboxgeplaatst.

Script.Append(string.Format(CultureInfo.InvariantCulture,@"<input name=""markers"" runat=""server""

id=""markers"" type=""hidden"" value=""""><input name=""marks"" runat=""server"" id=""marks""type=""hidden"" value="""">));

Vervolgens wordt een blokje JavaScript gegenereerd waar het Array ineen variabele wordt geplaatst. Hiervoor wordt door de profielen van dehuisartsen gegaan en de informatie in het array geplaatst.

Script.Append(string.Format(CultureInfo.InvariantCulture,<script type=""Text/javascript"">

//Global variablesvar gmarkers = [];var map;var data = ["));

//loop trough all the huisartsen for creation//of the markersforeach (HuisArtsProfile huisArts in Markers){

Script.Append(string.Format(CultureInfo.InvariantCulture,

@"{{account:""{0}"", naam:""{1}"", adres:""{2}"",postcode:""{3}"", plaats:""{4}"" , tel:""{5}"",email:""{6}"", latitude:""{7}"",longitude:""{8}""}},",huisArts.Account,huisArts.Name,huisArts.Address,huisArts.PostalCode,huisArts.City,huisArts.WorkPhone,huisArts.WorkEmail,huisArts.Latitude,huisArts.Longitude));

}Script.Append("];");

De volgende stap is het opbouwen van de JavaScript functie Goog-leMapLoad(). Dit is een standaard functie die GoogleMaps nodig heeftom de kaart te tonen op de pagina.Belangrijk is dat de grootte van de nieuwe map wordt meegegeven;als deze namelijk vergeten wordt, is het niet mogelijk de map netjes tecentreren. Dit resulteert in een grijze layer en de standaard lokatie(home) wordt niet op de juiste plaats aangegeven:

Script.Append(string.Format(CultureInfo.InvariantCulture,@"function GoogleMapLoad() {{if (GBrowserIsCompatible()){{var map = new GMap2(document.getElementById(""{3}""),{{ size: new GSize({5}, {6}) }});var zoomLevel = parseInt({4});var point = new GLatLng(52.325243,4.653537);map.setCenter(point,zoomLevel, {7});map.addControl(new GMapTypeControl());map.addControl(new GLargeMapControl());var geocoder = new GClientGeocoder();showMarker(map, geocoder, """",""Spaarne Ziekenhuis"", ""Spaarnepoort 1"", """",""Hoofddorp"", """", """",52.325243, 4.653537, spaarneicon);

for(var i = 0; i < data.length; i++){{var account = data[i].account;var name = data[i].naam;//etc..showMarker(map, geocoder, account, name, address,postalcode, city, phone, email, latitude,longitude, icon);

}}}};

}};",GoogleMapLicense, //0longtitude,//1latitude, //2"large-google-map", //3zoomLevel, // 4WidthMap.ToString(), //5HeightMap.ToString(),//6mapThemeType));//7

Hier komt ook de referentie terug op basis van het Id naar de DIV-tag,die we eerder hebben toegevoegd.In deze code word de Showmarker-functie aangeroepen. Dit is eenstandaard functie van GoogleMaps waar de marker (positieaandui-ding) wordt geplaatst. Deze functie wordt voor 2 doeleinden aange-roepen: 1 keer voor het plaatsen van de hoofdvestiging, het SpaarneZiekenhuis (spaarneIcon), en 1 keer in de array (dus gebeurt bij elkeloop) voor het bepalen van de posities van de huisartsenposten, methet huisartsenicoon.

IW TIP:TIP: string.Format is een goede manier om code goed lees-baar te houden en fouten te voorkomen; let op dat als je deaccolade wilt gebruiken in je script dat je ze dan dubbelneerzet, anders gaan ze verloren in het generen van je code.

Page 49: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

magazine voor software development 49

INFORMATION

WORKER

Het ShowMarker()-script voegt de latitude en longitude samen in eennieuwe variable GlatLng. Deze wordt gebruikt om de CreateMarkerfunctie aan te roepen; als deze terugkomt, kan hij toegevoegd wordenaan de Map via Map.AddOverlay.

Script.Append(string.Format(CultureInfo.InvariantCulture,@"function ShowMarker(map,geocoder,account,name,

address,postalcode,city,phone,email,latitude,longitude,icon)

{{"));

Script.Append(string.Format(CultureInfo.InvariantCulture,@" var loc = new GLatLng(latitude, longitude);var marker = createMarker(loc,account,name,address,

postalcode,city,phone,email,icon);map.addOverlay(marker);

}}GoogleMapLoad()</script>"));

GoogleMapLoad() dient aangeroepen te worden op het moment datde pagina wordt geladen. Dit wordt aan het einde van het scripttoegevoegd.

In de CreateMarker-functie wordt het icoon op de juiste positie gege-nereerd. Aan de marker kan een event toegevoegd worden. Door eenlistener toe te voegen aan zo’n event is bekend welke functie moetworden aangeroepen om te reageren op mouseovers van een marker.

Script.Append(string.Format(CultureInfo.InvariantCulture,@"function CreateMarker(loc,account,name,address,

postalcode,city,phone,email,icon){{

var marker = new GMarker(loc,icon);GEvent.addListener(marker, ""mouseover"", function()

{{"));

Aan deze mouseover wordt een functie toegevoegd die een Popup-window toont met de informatie die aan het webpart wordt meegevenin de eigenschap "InfoWindowHtml".

Script.Append(string.Format(CultureInfo.InvariantCulture,@" var html = ""<b><a

href='#'>""+name+""</a></b>""+""<br/>""+address+""<br/>""+postalcode+""<br/>""+city+""<br/>""+phone\nmarker.openInfoWindowHtml(html);"));

}Script.Append(string.Format(CultureInfo.InvariantCulture,@"}});

return marker;}}"));

Rest nog de definities van de iconen. De iconen worden opgeslagenin de 12 hive, waardoor deze altijd aanspreekbaar zijn en security-problemen voorkomen worden, waar je ook bent binnen SharePoint:

Script.Append(string.Format(CultureInfo.InvariantCulture,@"// create marker iconvar icon = new GIcon();icon.image = ""/_layouts/images/huisarts.png"";icon.iconSize = new GSize(30, 30);icon.iconAnchor = new GPoint(30, 30);icon.infoWindowAnchor = new GPoint(30, 30);

Tenslotte wordt de opgebouwde string teruggegeven aan deHTMLwriter.

output.Write(Script.ToString())

Na het compileren en installeren van het webpart is dit heteindresultaat:

Fig. 6: eindreslutaat

ConclusieHet is vrij éénvoudig Google Maps te integreren in een SharePointwebpart, en de vraag daarnaar ziet men dan ook steeds meertoenemen.De functies die beschreven zijn, maken deel uit van de basisfunctiesvan Google. Van hieruit is het mogelijk andere functies toe te voegenzoals een routeberekening. Zoals altijd is het van belang dat de Java-Script klopt, anders wordt er niets weergegeven. Dit kan ook resulte-ren in StringBuilder fouten.Ik heb ook de tegenhanger van Google Maps gemaakt, namelijk BingMaps. De structuur is nagenoeg gelijk, en voordeel is dat er hier geenkey benodigd is. Persoonlijk vind ik dat de map ook mooier weerge-ven wordt. Binnenkort toon ik een voorbeeld van de Bing-map op mijnwebsite. •

Paul Keijzers

Paul Keijzers is werkzaam voor, entevens eigenaar van het bedrijfKbWorks . Nadat hij zich met eenaantal generieke ontwikkelmetho-dieken heeft beziggehouden heefthij sinds een geruime tijd zijn focus100% op SharePoint gericht. Doordeze specialisatie zijn de share-pointcompetenties van Paul zeer

goed ontwikkeld waardoor hij zowel als consultant, architect, ofdeveloper wordt ingehuurd. Paul Blogt regematig op zijn blog datte vinden is via www.kbworks.nl.Momenteel werkt Paul aan een opdracht bij het Spaarne Zieken-huis te Hoofddorp

Page 50: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

DevTweet: SoftwareDevelopment with a wink

DevTweet’s zijn de conversaties tussen Marianne van Wanrooij en Sander Hoogendoorn overde (on)zin die IT-ers bezig houdt: Software-ontwikkeling met een knipoog. Regelmatig zullenook gasten worden uitgenodigd. Volg ze ook op Twitter via @mariannerd en @aahoogendoorn!

@aahoogendoorn Where are you???? :-)

@mariannerd I'm here. How was Vegas?

@aahoogendoorn #SPC09 was great! Great conference! Goodsessions, good speakers and wow... The SharePoint community isenthusiastic! Loved it!

@mariannerd So we can finally deliver actual applications on Share-Point? Would it be a good idea for die hards like me to have a look?

@aahoogendoorn Absolutely! Some nice new features. New versionof SharePoint is coming soon. They really did a great job at Microsofton this version.

@aahoogendoorn Although it's going to be a long wait until they'llrelease the public beta

@mariannerd Incredible how they can fill a whole week ofconference just on SharePoint..

@mariannerd So with SharePoint's new version, will it increaseflexibility to custom develop code with it?

@aahoogendoorn Definetly! The Visual Studio 2010 integrationwith SharePoint is great! Just too bad it only works for SP2010.

@mariannerd What does Visual Studio integration mean? Cool thatI can use Visual Studio to develop SharePoint of course, but does ite.g. come with software architecture?

@aahoogendoorn Deployment scenarios are horrible in this version.Visual Studio 2010 takes care of that!

@aahoogendoorn To create custom applications based onSharePoint you can use the web services and / or API.

@mariannerd Use a web service API? I suppose with a modelsimilar to .NET RIA Services? So where does that leave my businesslogic?

@aahoogendoorn I don't know the RIA services .. but forSharePoint it's hard to explain.. Depends on what kind of solutionyour writing.

@aahoogendoorn E.g. building Internet sites using WCM (webcontent management) publishing pages or adding WF to documentlibraries.

@mariannerd And what about if my "data" comes from elsewhere,such as SAP CRM, or Exact, or even Twitter?

@mariannerd (How) Can I do that in a SharePoint application?

@aahoogendoorn Ah... there is the BCS (Business ConnectivityServices). You can connect to external data and display it likeSharePoint data.

@aahoogendoorn And the BCS adds the CRUD methods, so youdon't have to worry about writing code ;-)

@mariannerd In my world, data (from where ever) is absorbed bymy domain layer and presented from there. The domain has thebusiness logic.

@aahoogendoorn In "your" world.. wow.. do you have to take a redpill to get into "your" world? LOL

@mariannerd Haha. Let's see how deep the rabbit hole really goes.I meant in custom n-tier software development.

@aahoogendoorn In the SharePoint world (that must be the bluepill) it's not written in a Domain Driven Design (DDD) style. But youcan implement it in your own code to some extent.

@aahoogendoorn For client-side business logic you can useJaveScript or JQuery.

@mariannerd JQuery? JavaScript? What's wrong with C#? Leadsto my original opinion, that SharePoint is basically intended for 2 tier.

@aahoogendoorn No... no... there is a new Client Model forSharePoint .. But haven't had the chance to look at it yet (too muchto look at).

@aahoogendoorn So what if I get data from a source I don'tcontrol (such as SAP), and I want validation, business rules etc.in SharePoint?

@aahoogendoorn I guess you never should compare customdevelopment with development for/adds on products.

@mariannerd I guess so. Think I'll stick on the custom side of thematrix for now. The answer is out there, Neo.

@mariannerd Though it would be highly interesting mixing customsoftware development and SharePoint in a domain driven designstyle, I think. Would allow for more types of sources.

@aahoogendoorn Well... I think we could do that... We can makeit a conference session.. Getting you coding again ;-)

@mariannerd I know what you're thinking, cause right now I'mthinking the same thing. Why oh why didn't I take the BLUE pill?

@aahoogendoorn Follow the white rabbit... and you might becomea SharePoint fan!

@mariannerd Sure hope your white rabbit doesn't appear 2 bethe Holy Grail’s Killer Rabbit. "Oh, it's just a harmless little *bunny*,isn't it?"

Follow the white rabbit!Exploring customer software development in SharePoint

MAGAZINE50

Page 51: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

ARCHITECTURE Andre Boonzaaijer

CaseLaten we het volgende modelfragment onder de loep nemen. Wehebben een bepaalde business die werkt vanuit geografischegebieden (Area’s) waarin zich klanten (Customer’s) bevinden. Een klantbestaat alleen binnen een gebied. Elk van deze klanten heeft eenaantal niet nader te specificeren transacties aan zich geassocieerdmet een bepaalde waarde en een datum (Transaction’s).

Fig. 1: Class-model van de case

Eén bepaalde vraag aan hetsysteem is het geven van deopgetelde waarde van de trans-acties binnen een gebied van hethuidige jaar. Dit zijn vormen vangegevensaggregatie die in heelveel businessdomeinen op eenbepaalde manier terugkomen envaak real-time vanuit een systeemmoeten kunnen worden samen-gesteld. De methode is gedefini-eerd in de Area class alsGetTransactionValueThisYear().

Volgens de verantwoordelijk-heidsgedreven ontwerpmethode– met het uitgangspunt dat ob-jecten slechts één verantwoorde-lijkheid mogen hebben – ontstaaner vaak iteratieve sequenceszoals in figuur 2 weergegeven.

Zodra er een aggregatievraag gesteld wordt aan bijvoorbeeld de Areadan wordt er een iteratie gestart over de geassocieerde Customerobjecten. Figuur 2 geeft twee sequences weer; die van hettoevoegen van een transactie door de business-actor, en die van hetopvragen van een totaalcijfer door de business-actor.

De AddTransaction() aanroep waarmee de eerste sequence begint isrechttoe rechtaan. Het Customer-object krijgt bepaalde gegevensbetreffende de transactie binnen, creëert het object en associeert hetmet zichzelf. Er vindt verder geen iteratie plaats en deze sequenceschaalt dus lineair.

In de tweede sequence stelt de business-actor de vraag GetTrans-ActionValueThisYear() aan een Area-object. Deze area start een itera-tie over al zijn customers met de vraag GetTransactionValueForYear(2009); we zijn immers uitgegaan van het doorgeven van devraag als daar zelf geen afdoende antwoord op gegeven kan worden.Op zijn beurt zal deze customer een iteratie starten over al zijngeassocieerde Transaction-objecten met een datum in het jaar 2009met de vraag GetValue(). De customer houdt immers zelf geentransactiewaarde vast zelf en vraagt het na bij de daarvoor verant-woordelijke objecten. Dat zijn in dit geval de transactions die aan debetreffende customer geassocieerd zijn.

Fig. 2: Normale strategie

magazine voor software development 51

Domeingedreven ontwerp heeft tot doel een zo accuraat mogelijke afspiegeling te maken vande context waarin bepaalde bedrijfsprocessen draaien in een model. Tijdens het maken vandeze modellen wordt nauwelijks of geen rekening gehouden met zaken als responsetijden ofgeheugengebruik. Dat is in het vroegste stadium ook niet interessant.In tweede instantie, bij het daadwerkelijk executeren van een model in een productiesysteem,dienen deze aspecten wel degelijk meegenomen te worden. In dit artikel ga ik in op een aantalonderdelen binnen het domeinmodel zelf en hoe de keuzes die hierin gemaakt worden impli-caties kunnen hebben voor het uiteindelijke systeem als totaal. Een model dat – in eersteinstantie – een goede representatie vormt van de te automatiseren bedrijfsvoering is bijvoorbeeldniet per definitie schaalbaar. Ik zal twee afzonderlijke benaderingen illustreren aan de hand vaneen veelvoorkomende praktijksituatie en deze benaderingen vergelijken op schaalbaarheid.

Objecten mogen slechts éénverantwoordelijkheid hebben

Schaalbaremodellen

Page 52: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

ARCHITECTURE

MAGAZINE52

De verantwoordelijkheden zijn mooi verdeeld en ieder object is klein enschoon, met een eigen verantwoordelijkheid. Toch leidt deze benade-ring in de praktijk soms tot problemen.

Stel dat we voor een bepaalde Area N klanten hebben. Deze klantenhebben gemiddeld M transacties. Als we de vraag GetTransAction-ValueThisYear() stellen aan het systeem zullen er dus N X M objectengeraakt worden. Dit kan inhouden dat er bij bijvoorbeeld 100 klantenmet ieder 1000 transacties (heel kleine aantallen eigenlijk) toch al snel100.000 objecten geraakt worden om de vraag te beantwoorden.Bij een in-memory operatie is dat geen groot probleem, maar helaasis het vaak zo dat niet alle objecten in het geheugen geladen zijn. Lazyloading, het principe van pas ophalen van objecten als dat nodig is,biedt hier overigens geen uitkomst. Het gehele composiet Area wordthier tot in de bladeren (de Transaction objecten) geraakt. Het stellenvan de vraag GetTransactionValueThisYear() verandert de toestandvan het systeem, alleen binnen de context van het model, niet. Als weeen stap verder kijken dan het model zien we dat er onder waterontzettend veel verandert aan de toestand van bepaalde objecten.Het is duidelijk dat deze benadering valide is, maar niet schaalbaar.

Alternatieve strategieBertrand Meyer heeft bij de ontwikkeling van de taal Eiffel eenprincipe gehanteerd dat ook wel Command-Query Separation ge-noemd wordt. Dit principe gaat uit van twee soorten vragen die gesteldkunnen worden aan een systeem: een command of een query. Bij eencommand, in feite een opdracht aan het systeem, is er een bepaaldeverandering in toestand. Bij een query wordt er enkel informatieopgevraagd. Deze vraag heeft nooit een toestandsverandering totgevolg.

Als we alleen naar het model kijken dan geldt dit principe in de voor-gaande oplossing. Omdat ons model echter in een bepaalde contextleeft, is het in dit geval zo dat de vraag GetTransactionValueThisYear()zodanig veel objecten raakt dat het wel degelijk een toestandsveran-dering tot gevolg heeft. We kunnen deze toestandsveranderingvanuit het model elimineren.Uitgaande van het Command Query Separation principe dienen wehet ‘werk’ te doen in het command – in dit geval dus de AddTransac-tion() methode. We notificeren op moment van toevoegen van eentransaction meteen het root-object, de area. Dit kunnen we doen dooreen TransActionAdded() message met de binnengekomen gegevenste sturen naar de area. In de area dient nu wel een lokaal attribuut inde vorm van een lookup table of iets dergelijks opgenomen te wordenom het object zelf de vraag te kunnen laten afhandelen. Dit is in figuur1 ook al wel opgenomen in de vorm van het TransactionValues-object. We zien nu de volgende twee sequences ontstaan:

Fig. 3: Alternatieve Strategie

We nemen hiermee een kleine penalty qua complexiteit van deAddTransaction() message naar de customer (het notificeren van dearea via TransactionAdded()) voor lief. Deze strategie biedt namelijkeen zeer groot voordeel bij de aanroep van GetTransActionValueThisYear(). Het area-object kan dit nu lokaal afhandelen: bij het stellenvan deze vraag zal er dus geen delegatie naar andere objecten meerplaatsvinden.Het voordeel dat we hiermee in het productiesysteem kunnenbehalen kan zeer significant zijn. Toch moet deze minimaletoegevoegde complexiteit niet onderschat worden. In feite wordt erredundante informatie aan het model toegevoegd om een soort cachein te bouwen. Ga hier voorzichtig mee om en definieer de interfacesvan de objecten eenduidig. Uiteraard is het uitvoerig testen van dezecollaboraties zeer aan te bevelen.

Een goed object-georiënteerd ontwerp kan hierbij wel het voordeelopleveren dat we tussen de twee geschetste strategieën kunnenschakelen. Als we de twee sequence-diagrammen naast elkaar leggenzien we dat vanaf de buitenwereld gezien er niets verandert aan devragen die we stellen.

ConclusieDe twee vergeleken modelleerstrategieën verschillen op verschillendevlakken. Hoewel de eerste strategie, die van het zoveel mogelijkdelegeren van verantwoordelijkheid, de meest pure en schoonste is,kleven er in de praktijk mogelijk nadelen aan. Zo is goede analyse vande hoeveelheden gegevens noodzakelijk om de schaalbaarheid tegaranderen.De tweede strategie, gebaseerd op het uitgangspunt van command-query separation, kan schaalbaarheidsproblemen helpen te voorko-men. Het impliceert in dit geval wel het toevoegen van redundanteverantwoordelijkheden. Of deze nadelen opwegen tegen de schaal-baarheidsvoordelen die deze benadering met zich meebrengt, moetper geval bekeken worden. De praktijk wijst uit dat vooral in systemendie schaalbaar van opzet moeten zijn, zoals webapplicaties, devoordelen ruimschoots opwegen tegen de nadelen. •

Command-Query Separation principe:er kunnen twee soorten vragen gesteldworden, nl. een command of een query

Voor de buitenwereld iser niets veranderd…

André Boonzaaier

André Boonzaaijer is werkzaambij Sogyo als Senior Software Engi-neer. Naast software ontwikkelinghoudt hij zich bezig met modellering,ontwerp en architectuur van syste-men. Tevens is hij betrokken bij hetverzorgen van trainingen en master-classes op het gebied van zijnexpertise.

.Net TIP:Aan de slage met WF/WCF?Aan de slag met Windows Communication Foundation ofWindows Workflow Foundation .NET Framework 4, Beta 2?Hier zijn de nieuwe voorbeelden te downloaden: http://go.microsoft.com/fwlink/?LinkId=150780

Page 53: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

Advertentie Sogeti

Page 54: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

GENERAL Eric Denekamp

• Logboeken met duidelijke events, het liefst Windows eventlogs engeen platte tekstbestanden;

• Performance-counters die applicatiespecifieke informatie geven endie een aanvulling zijn op de reeds bestaande Windowsperformance counters;

• Goede, ‘verbose’ foutmeldingen.

LogboekenAangezien een beheerder niet de hele dag de tijd heeft om te blijvenkijken wat er allemaal gebeurt op een server, is het voor hem nood-zakelijk dat de uitzonderlijke dingen die plaatsvinden op die server,vastgelegd worden in een logboek. Dit logboek kan dan in geval vaneen melding van vreemd gedrag geraadpleegd worden. De meldin-gen in dit log kunnen variëren van b.v. het geslaagd starten van eenservice tot een foutmelding omdat een gebruiker niet goed inlogt opde applicatie. Voor de meeste beheerders is een dergelijk logbestandgenoeg om fouten binnen het systeem op te sporen en te elimineren.

Fig. 1: Voorbeeld van een logentry die voor een beheerder zinlozeinformatie bevat, maar wel als foutmelding geregistreerd staat.

MAGAZINE54

MonitoringIedere beheerder kent ze wel, de applicaties die liever niemand in beheer wil nemen omdat de

applicatie niet beheerbaar is, maar toch gebruikt moeten worden. Iedere ontwikkelaar kent ze

wel, die beheerders die komen klagen dat de applicatie die net opgeleverd is, niet voldoet aan

de standaarden, niet beheerbaar is of om een andere reden terug over de schutting gegooid

wordt. In dit artikel hoop ik deze mensen bij elkaar te brengen en in ieder geval vanuit het

gezichtspunt van een beheerder aan te geven wat de verwachting is van deze beheerder. Eerst

zal het probleem uitgewerkt worden vanuit het gezichtspunt van een beheerder en daarna zal

ik proberen een aantal punten te bespreken die bijdragen aan een oplossing.

Het probleemEen beheerder is de persoon waar de gebruikers komen klagen(al dan niet via een helpdesk), dat een applicatie voor hun gevoel nietgoed functioneert. In zulke gevallen zal een beheerder willen gaanonderzoeken wat er aan de hand is. Dit onderzoek moet dan handenen voeten krijgen: evenementen in een log, performance counters,foutmeldingen die hout snijden. Deze informatie kan gebruikt wordenom een goede inschatting te maken waar het gedrag aan zou kunnenliggen. Indien deze informatie geheel of gedeeltelijk ontbreekt, is deapplicatie een zwarte doos waar de beheerder weinig mee kan. Eensnel gekozen oplossing zal in dat geval ook zijn: herstart de machinemaar en hoop dat het opgelost zal zijn. In een heleboel gevallen zal ditook het geval zijn voor de kortere termijn, maar een structurele oplos-sing zal er in een dergelijk geval niet komen. De beheerder zal in eendergelijk geval gaan praten over een slechte applicatie en er zal weer-zin ontstaan om meer van dergelijke applicaties in beheer te nemen.

Jammer genoeg wordt bij het specificeren van de eisen voor eenapplicatie vaak wel nagedacht over de functionele specificaties en depunten vanuit een invalshoek die te maken hebben met de bedrijfsin-zet van de applicatie. Een set van specificaties met betrekking tot hetbeheer wordt echter zelden opgenomen in de eisen voor een maat-werkapplicatie. Vaak leidt dit tot een discussie of een applicatie wel ofniet (goed) in beheer kan worden genomen. Het achteraf aanpassenvan een applicatie aan de eisen van de beheerders is meestal meerwerk dan het in een keer tijdens het ontwikkelen van de applicatiegoed beschrijven van de punten waar de beheerder om vraagt.

OplossingenIn het algemeen zijn er drie categorieën te bedenken waarin deoplossingen te verdelen zijn. Deze drie categorieën zijn uiteindelijk eenaanvulling op elkaar. Deze categorieën zijn:

Beheerders nemen geen slechtbeheerbare applicaties in beheer

Page 55: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

magazine voor software development 55

GENERAL

Een logentry hoeft natuurlijk niet een volledig boekwerk te zijn, maarinformatie over de reden van de entry en de randvoorwaarden waaromdeze entry bestaat is het minimum aan informatie dat erin zoumoeten staan. Deze logentry wordt namelijk ergens in de applicatiegegenereerd, omdat er bepaalde randvoorwaarden bestaan. Een

melding van deze randvoorwaarden en de impact ervan maakt hetvoor een beheerder een stuk makkelijker om ze op te heffen.Ook zou het voor een geautomatiseerde beheertool handig zijn alsiedere foutmelding een eigen foutcode meekrijgt. Dit maakt hetmakkelijker om te filteren in de eventlogs, maar ook om in eenvervolgstadium met geautomatiseerde tooling zoals System CenterOperations Manager te monitoren op foutcodes die optreden en opbasis daarvan op te treden. Dit kan dan zowel reactief als proactief.Voor het maken van goede eventlogs, met name de Windowseventlogs, is binnen Visual Studio de namespace System.Diagnosticsen System.Diagnostics.Eventing aanwezig waarmee het mogelijk isom gestandaardiseerde logs te bouwen.

Performance countersIedere applicatie is anders, iedere applicatie heeft andere puntenwaarop de performance gemeten kan worden. Threads wordengestart, queries worden gestart, threads worden afgesloten, geheugenwordt gealloceerd en weer vrijgegeven, en zo is er nog veel meer teverzinnen. Natuurlijk is het mogelijk om de algemene zaken te meten,zoals processorgebruik, algemene geheugenallocatie en netwerk-gebruik, maar voor het goed beheren en inregelen van een applicatieis ook de applicatiespecifieke informatie nodig. Middels deze

counters kan een beheerder kijken in hoeverre bijvoorbeeld deschaling van de server goed is of dat er opgeschaald moet worden.Ook kunnen performance counters een indicatie zijn dat er iets mis ismet de server of applicatie. Hiervoor is een logische inzet vanperformance counters nodig op een plek waar processen, threads ofandere zaken gestart en gestopt worden. Met name de invulling vaneen applicatie waar componenten van de applicatie met elkaarcommuniceren zijn plekken waar de beheerder grip op wil hebben.Zeker als het gaat om applicaties met meerdere lagen en componen-ten die op verschillende machines draaien, is het kunnen meten inwelke component het probleem of de bottleneck zit, enorm vanbelang. Aangezien de beheerder niet de mogelijkheid heeft om in deapplicatie te kijken wat waar wanneer hoe gebeurt, moet deapplicatie deze informatie op de een of andere manier aanbieden.Ook kan een beheerder op deze manier zijn werkterrein deelsverschuiven van reactief beheer naar proactief beheer. Op hetmoment dat een organisatie de stap naar deze vorm van beheer kangaan maken is er voor de gebruiker een heel groot voordeel tebehalen. Symptomen van problemen kunnen in een vroeg stadium,soms nog voor de problemen zich openbaren, gesignaleerd en be-streden worden. Hierdoor is het heel goed mogelijk dat de problemenzich helemaal niet meer voordoen.Voor het aanmaken van deze counters in Visual Studio kan ook weergebruik gemaakt worden van System.Diagnostics en System.Diagnostics.Eventing.

Goede FoutmeldingenIn het geval van een client-applicatie is het voor een beheerder nood-zakelijk om te kunnen werken met de informatie van de gebruiker.Hiervoor is het dan ook essentieel om die gebruiker goed in te lichtenals er iets mis gaat en ook een mededeling te geven die de gebruikerkan doorgeven aan de beheerder. De foutmelding “An unknown errorhas occurred” is dan niet erg informatief. Natuurlijk is niet iedere foutte ondervangen met een uitgebreide mededeling van wat er mis is,maar enige duidelijkheid en een richting waarin de beheerder van deapplicatie kan gaan zoeken zou handig zijn. In de code van deapplicatie zit iets wat de foutmelding triggert en deze trigger zouomschreven kunnen worden. Een belangrijke reden dat gebruikersfoutmeldingen wegklikken is dat de beheerder van hun omgeving ofapplicatie meestal niets met de foutmelding doet of kan.

ConclusieEen van de dingen die een beheerder moet doen en uiteindelijk ookgraag doet, is het helpen van zijn gebruikers. Hiervoor is hij natuurlijkafhankelijk van de gereedschappen die hij daarvoor beschikbaar heeft.Deze gereedschappen zijn voor een groot gedeelte de beheertools dehij krijgt bij applicaties en de besturingssystemen. Hij heeft echter ookhandvaten nodig om de applicaties die hij beheert goed te kunnenbehandelen. Hiervoor is hij voor een groot gedeelte aangewezen op dehandvaten die de applicatie hem biedt: events die duidelijk zijn,performance counters waar hij relaties uit kan halen en goede fout-meldingen.Een tweede stuk gereedschap dat een beheerder zou kunnen enwillen inzetten, is System Center Operations Manager (SCOM),waarvoor de in dit artikel genoemde zaken als bron kunnen dienenom nog sneller en eventueel geautomatiseerd problemen te tracerenen op te lossen. Ook hiervoor wordt informatie van u als ontwikkelaargevraagd. In een volgende editie van dit blad zal uitgelegd worden hoeu de beheerders die daarom vragen, kunt bedienen met de benodigdeinformatie en gereedschappen. •

Een logentry moet minimaal de redenen randvoorwaarden bevatten

Beheer verschuift dan van reactiefbeheer naar proactief beheer Eric Denekamp

Eric Denekamp is trainer/consultantbij InfoSupport. Hier is hij verant-woordelijk voor het infrastructuurcurriculum en geeft hij technischetrainingen op het gebied van de be-sturingssystemen Windows 7,windows Server 2008 R2, de Sys-tem Center product groep en de Fo-refront productgroep. Daarnaast

werkt hij ook aan de hosted omgevingen die Info Support voor zijnklanten beheert. Ook ontwerpt hij omgevingen voor klanten vanMicrosoft en Info Support in binnen en buitenland. Eric is eengevraagd spreker op evenementen van Microsoft.

Visual Studio 2010 TIP:Visual Studio 2010: Call HierarchyAls je een methode selecteert, dan kun je de Call Hierachyopvragen ("Ctrl+K, T" of via het contextmenu). Het resultaat laatdan alle Calls To, Calls From en Overrides zien.

Page 56: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

DATABASES Marcel Meijer

Wat is SQL Azure?Microsoft SQL Azure Database is het cloud-based relationale data-base-platform, gebouwd op SQL Server technologieën. Met SQLAzure Database kun je eenvoudig relationale database-oplossingen inde cloud realiseren. Hierdoor maak je gebruik van de voordelen van dewereldwijde gedistribueerde datacenters, die hoge beschikbaarheid,schaalbaarheid en beveiliging bieden, met daarnaast ook de voorde-len van de ingebouwde databeveiliging, zelf herstellende mogelijk-heden en disaster recovery (MM: vrij vertaald van de website).

RondleidingOp de Azure Services site krijg je er een SQL Azure tabje bij. Deze tabis eigenlijk schrikbarend leeg, want er staan niet veel zaken op: enkelde database-servernaam en de username plus twee opties, nl. omeen nieuwe database te maken en de bijbehorende connection-stringsop te vragen. Dat is het dan.

Fig. 1: Het SQL Azure tabje

Fig. 2: Het maken van een nieuwe database

Fig. 3: Het bekijken van de connection-strings

En daarmee is het eigenlijk wel gedaan op de site. Tot zover dus derijke user interface ;-) Toegegeven moet worden, dat de mogelijkheidtot het bekijken van de connection-strings wel handig is; dat bespaartje een zoekactie op http://www.connectionstrings.com.

Zoals je ziet heeft de server wel een hele rare naam. Dit zal wel komenomdat het gaat om een CTP en in de toekomst zullen hier wel min ofmeer normale namen voor in de plaats komen. De huidige naam lijktin ieder geval gegenereerd te zijn. Op de Azure services pagina’s zijndus geen mogelijkheden om Tabellen, Stored Procedures, indexen,etc. aan te maken. Daarvoor moet je teruggrijpen op de bekende SQLServer Client tools, zoals Vi-sual Studio (via de ServerExplorer) of Microsoft SQLServer Management Stu-dio.Bij deze laatste zit weleen addertje onder het gras.Je kunt niet zomaar de NewConnection Wizard gebrui-ken. Je moet een NewQuery maken en dan eenverbinding gaan opzetten.Wat je dan zeker niet moetvergeten, is het invullen vande default database. Anderswijs je naar de Master data-base en tja … daar kun jeniet veel mee.

Fig. 4: Verbinden vanuit SQL Server Management Studio

MAGAZINE56

SQL AzureToen Azure vorig jaar op de PDC geïntroduceerdwerd, was iedereen uiterst geïnteresseerd in demogelijkheden. De component voor dataopslag endan met name databases was voor iedereen danook een teleurstelling. In de eerste dagen waren demogelijkheden beperkt tot blobs, hiërarchischedata en files, terwijl vele van onze huidige systemenjuist gebaseerd zijn op relationele databases. Dezekritiek heeft het Azure-team zich dan ook aange-trokken en al gauw werd SQL Azure aangekondigd(het had eerst nog enkele andere namen). Langwas onzeker wat er werkelijk mogelijk zou zijn,maar recentelijk kwam er een eind aan deze onze-kerheid en zag SQL Azure het levenslicht. In ditartikel een kleine impressie van de mogelijkhedenen onmogelijkheden.

Page 57: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

magazine voor software development 57

DATABASES

Fig. 5: Niet vergeten default database in te vullen!

Het is wel grappig om te zien dat in de dropdown met “AvailableDatabases” dan “CloudeNode” staat. Dat is dan nog de enigeverwijzing dat het gaat om een database in de cloud.

Fig. 6: Database is een CloudeNode

Als je boven het tabje met de query hangt, dan krijg je natuurlijk devolledige tekst te zien. Deze is beduidend langer dan bij een normalelokale of remote database.PS: Als je op Connect drukt, krijg je onderstaande fout. Niets ernstigs,maar wel vreemd…

Fig. 7: Foutmelding

Ik heb de volgende standaard SQL-dingetjes uitgeprobeerd:• een tabel gemaakt;• een primary key op de tabel;• een insert op de tabel;• een select (uiteraard);• een stored procedure (een simpele versie om een select van detabel te retourneren);

• en een view op de tabel.

Bij het aanmaken van tabellen kun je uiteraard niet geen FileGroup enPartitioning Scheme aangeven. Deze zullen door de cloud geregeldgaan worden.Bij het maken van een index lijk je geen ROW_LOCKS ofPAGE_LOCKS te kunnen opgeven. Dit is natuurlijk ook min of meergekoppeld aan de fysieke storage.

ALTER TABLE dbo.MyDemoTable ADD CONSTRAINTPK_MyDemoTable PRIMARY KEY CLUSTERED(ID) WITH(

STATISTICS_NORECOMPUTE = OFF,IGNORE_DUP_KEY = OFF )

/*, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)

ON [PRIMARY]*/GO

Bij de overige kleine testjes kwam ik geen gekke dingen tegen.

Wat je wel mist, zijn alle bekende system stored procedures, zoalsSP_WHO, SP_HELP en SP_LOCK. Er is wel een aantal SYS-tabellenbeschikbaar, waaronder sys.databases, en daarmee kom je natuurlijkook een heel eind.

Doordat de tools nog een beetje Spartaans zijn, mis je een aantalhandigheden uit de bekende gereedschappen zoals auto-completeen intellisense. Dat gaat vast in de toekomst opgelost worden. Dit blijktal wel uit het feit, dat er al verschillende tools voor SQL Azurebeschikbaar zijn. Zo kun je database, entiteiten en artifacts gewoonmaken in een lokale database. Op deze manier heb je alle mogelijkehulp en hulpmiddelen tot je beschikking. Als je dan klaar bent, dangebruik je de SQL Azure Migration Wizard tool (http://sqlazuremw.co-deplex.com) om een SQL Azure script te maken. Deze tool filtert danalles wat (nog) niet mogelijk is, uit het script.

Ook het gebrek aan een Object Explorer is min of meer opgelost metde SQL Azure Explorer (http://sqlazureexplorer.codeplex.com).Deze plugin voor Visual Studio 2010 komt een beetje aan dit gemistegemoet.

Fig. 8: SQL Azure Explorer object browser

Fig. 9: SQL Azure Explorer SQL window

Tot slotHet ziet er allemaal erg aardig uit. Het is zeker een verbetering aanmogelijkheden ten aanzien van de Databases in de cloud de eerstedagen van Azure. Maar ik moet je eerlijk bekennen, dat dit alles mij

Page 58: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

Core Systems TIP:SEARCH-statement (COBOL)Het verkeerd gebruik van het SEARCH-statement kan nadeligegevolgen hebben voor de performance. Gebruik SEARCH ALL(binary search) voor tabellen met meer dan 50 entries enSEARCH (lineaire search) voor kleinere tabellen. Voor tabellenmet minder dan 20 entries wordt een inline PERFORMaangeraden.

DATABASES

redelijk bekend voorkomt. Bij de website hoster waar ik mijn blog host,heb ik ook een SQL Server tot mijn beschikking. Ook deze kan ik viaverschillende gereedschappen benaderen en voor mijn gevoel is datdus niet heel veel anders. Ook daar heb ik niet de vrijheid van file-groups, etc. Oké, daar kan ik niet ongestraft een database aanma-ken, maar in hoeverre is dit anders dan b.v. databases in een managednetwerk? Toch voegt SQL Azure wel een extra dimensie toe aan hetAzure Services platform, waarmee het platform toch weer een stukjevolwassener en completer wordt. Ik denk dat we in de toekomst nogwel het een en ander aan nieuws over deze Azure-telg zullen horen.Voor meer informatie: kijk op http://www.microsoft.com/azure. •

NB: Dit artikel is gebaseerd op een preview. De huidige SQL Azure isal iets uitgebreider, hierover tijdens het SDN Event van december meer.

Marcel Meijer

Al meer dan 15 jaar begeeft deze 40jarige zich in de wereld van de ICT.Hij heeft een vriendin Jose, tweekinderen (Wouter en Tamara) en eenhondje Joep. Op dit moment houdthij zich voornamelijk bezig met C#,BizTalk, SharePoint, Software Ont-wikkeling en Architectuur in hetalgemeen. Hij werkt als SoftwareDeveloper / Solution Architect bij VX

Company. In zijn vrije tijd is hij .NET track owner voor de SDN.Binnen de SDN is hij verantwoordelijk voor het regelen van spre-kers voor de SDN Events (SDE) en het regelen/redigeren van ar-tikelen voor het SDN Magazine. Hij is te bereiken [email protected] of [email protected].

Windows 7 TIP:Windows 7: Shake it!In Windows 7 is het mogelijk om te shaken met de titelbar vaneen scherm. Als je dat doet, dan minimaliseren alle overige ge-opende schermen. Of als alle schermen al geminimaliseerd zijn,dan komen ze allemaal weer terug. Op een Touch scherm oflaptop kan dat ook met de vingers.

Advertentie Sybase iAnywhere

Page 59: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

UX Emile van Ewijk

wireframes, en relaties tussen verschillende schermen, vertaaldkunnen worden naar een interactief prototype. Dit geeft een goedbeeld van de wijze waarop Blend al in een vroeg stadium kan onder-steunen bij de werkzaamheden van de ontwerper.

Silverlight-animaties en -applicaties zullen doorgaans opgebouwd zijnuit vectorillustraties. Vandaar dat er in dit boek ruimschoots aandachtis voor dit onderwerp. Daarbij wordt om te beginnen de algemenetheorie van vectorafbeeldingen behandeld, waarbij vooral wordtgekeken naar de verschillende typen figuren die getekend kunnenworden. Vervolgens worden de do’s en don’ts behandeld van hetprogramma Adobe Illustrator, wat voor veel vormgevers het standaardprogramma voor het werken met vectorillustraties is. Dit is gedaanmet het oog op de mogelijkheid om de illustraties te exporteren naarXAML, de markup-code die door Silverlight wordt gebruikt. Hierbijwordt er wel vanuit gegaan dat de basiskennis van Illustrator alaanwezig is. Binnen de Expression-familie is ook een vectorgebaseerdontwerpprogramma aanwezig: Expression Design. Een belangrijk deelvan het hoofdstuk over ontwerpen bestaat uit een beschrijving vanvrijwel alle mogelijkheden van dit programma en de manier waarophet resultaat uiteindelijk geëxporteerd kan worden naar XAML.Dit wordt afgesloten met enkele handige stappenplannen voor het ex-porteren en importeren van XAML vanuit verschillende programma’s.

ProducerenWanneer de fase van het ontwerpen is afgerond, is het tijd om deapplicatie te produceren. Dit omvat alle werkzaamheden die tussenhet ontwerpen en het programmeren in zitten, wat het binnen eenSilverlight-project tot een belangrijk onderwerp maakt. In het boekwordt begonnen met een kort introductiehoofdstuk over het produ-ceren. Hierop volgt het hoofdstuk ‘XAML in vogelvlucht’. AangezienXAML de basis vormt voor Silverlight is er veel te vertellen over ditonderwerp, en dat is ook wat dit boek doet. De XAML-syntax, kleur-gebruik, shapes, opbouw van een lay-out, gebruik van controls, ani-maties, werken met states, stijlen en templates: dit is nog maar eenselectie van de onderwerpen die worden behandeld. Zoals de titel vanhet hoofdstuk vermeldt gebeurt dit in vogelvlucht. Alle onderwerpenworden dus wel behandeld, maar niet overal wordt zeer diep opingegaan. De auteur verwijst dan ook enkele malen naar zijn andereboek ‘Handboek XAML’ voor meer achtergrondinformatie over eenaantal onderwerpen. Hoe dan ook biedt dit hoofdstuk een bredebasiskennis van XAML, van waaruit verdere verdieping voor de lezeraltijd nog mogelijk is.

magazine voor software development 59

Boek Review:

Handboek Silverlight 3Wie aan de slag wil met nieuwe technieken als Silverlight 3, kan op het web een schat aan informatievinden op blogs, fora en andere informatieve sites. Toch is het vaak lastig om de informatie die je zoektop een prettig gebundelde wijze bij elkaar te vinden, zeker voor degenen die nog niet bekend zijn methet onderwerp. Als alternatief voor digitale informatie zijn uiteraard ook boeken beschikbaar waarin eenselectie van informatie door de schrijver bij elkaar is gezocht. In dit artikel wordt het onlangs uitgegeven‘Handboek Silverlight 3’ bekeken. Daarbij kijken we naar de inhoud van het boek en de mate waarin delezer zijn kennis over Silverlight kan uitbreiden door dit boek te lezen.

Opbouw van het boekZoals bij webdevelopment vaak het geval is, is ook Silverlight eentechniek waar diverse rollen binnen een organisatie mee in aanrakingkomen. Dit is goed terug te zien in de opbouw van het boek,waarbinnen de rollen van designer, producer en developer wordenonderscheiden. De inhoud richt zich voornamelijk op de werkzaam-heden van deze doelgroepen en de samenwerking die daarbij komt kij-ken. Daarmee wordt een brede selectie van onderwerpen behandeld.

AchtergrondHet boek begint met een theore-tische inleiding, waarin de histo-rie en achtergrond van Silverlightaan bod komen. Daarnaastwordt de positionering vanSilverlight ten opzichte van Flashen HTML uitgelegd en komenenkele actuele en toekomstigeontwikkelingen van het platformnaar voren. Dit is geen vereistekennis om aan de slag te kunnenmet Silverlight, maar zekerinteressant voor wie een indrukwil krijgen van de geschiedenisen toekomst van dit platform.

OntwerpenHet praktijkgedeelte van het boek begint in het hoofdstuk‘Ontwerpen’. Het boek houdt de volgorde van een regulier project aan,dus beginnen we hier met het concept en het design. Na eeninleiding over het creatieve proces waaruit een concept tot stand komt,wordt al snel overgegaan op het schetsen. Aan de hand van eenaantal voorbeelden wordt hier uiteengezet hoe wireframes gemaaktkunnen worden op papier of achter de computer en wat het belanghiervan is. Dit verhaal loopt naadloos over in informatie over Sketch-Flow, een interessant onderdeel van Expression Blend waarmee

Zoals bij webdevelopment vaak hetgeval is, is ook Silverlight een techniekwaar diverse rollen binnen eenorganisatie mee in aanraking komen

Page 60: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

MAGAZINE60

UX

Een groot deel van het produceren in Silverlight zal doorgaans wordenuitgevoerd in Expression Blend. In Blend worden alle deelproducten,van ontwerp tot programmacode, samengevoegd tot één geheel,zodat de uiteindelijke applicatie tot stand komt. Niet voor niets is eencompleet hoofdstuk van het boek gewijd aan dit programma. In dithoofdstuk worden de verschillende optiepanelen en de menuoptiesvan Blend doorgenomen. Enkele veelgebruikte procedures, bijvoor-beeld voor het maken van animaties en het gebruik van de Visual StateManager, worden aan de hand van een stappenplan beschreven. Dezestappenplannen zijn een goede reden om het boek later nog eensterug te pakken wanneer je dit soort werkzaamheden daadwerkelijk uitmoet gaan voeren. Al met al wordt dus een duidelijk en compleet beeldgeschetst van Blend, zodat je hier na het lezen direct mee aan de slagkan.

Het hierop volgende hoofdstuk gaat over het gebruik van beeld en ge-luid. Voor het bewerken van video’s wordt de werking van ExpressionEncoder uitgelegd. Met dit programma kunnen video’s in allerleiverschillende formaten geschikt worden gemaakt voor het gebruik inSilverlight. Deze uitleg is op een vergelijkbare manier opgebouwd alshet hoofdstuk over Expression Blend, dus er zijn weer diversestappenplannen en een uitleg van de verschillende opties in hetprogramma aanwezig. Verder wordt de MediaElement controltoegelicht, wat binnen Silverlight de standaard control is voor deweergave van beeld, geluid of een combinatie hiervan. Het gaat danniet alleen om de pure weergave van deze media, maar ook om demogelijkheden om het afspelen vanuit het interface te kunnen regelen.Tot slot komt de Deep Zoom techniek met de bijbehorende DeepZoom Composer aan bod. Met deze techniek is het mogelijk omschaalbare afbeeldingen te maken waarop zeer ver ingezoomd kanworden. Dit is een interessante en veelgebruikte toepassing vanSilverlight, dus is het prettig dat de informatie hierover in het boekaanwezig is.

ProgrammerenNa het produceren zal er een applicatie staan die al behoorlijk op hetgewenste eindresultaat lijkt. Om het geheel echt compleet te makenzal echter nog geprogrammeerd moeten worden, voornamelijk voor deafhandeling van de data. Binnen een Silverlight project zullen designersen developers nauw samen moeten werken. Het hoofdstuk overprogrammeren opent daarom met verschillende aanpakken diegekozen kunnen worden voor deze samenwerking. Dit wordt gevolgddoor algemene informatie over Visual Studio en de programmeertalendie gebruikt kunnen worden. Dit zal gesneden koek zijn voorontwikkelaars die al met het .Net-framework werken, maar voor an-deren zal dit weer een nuttige basis op instapniveau bieden. De daaropvolgende informatie gaat over de communicatie tussen de HTML-pagina en het Silverlight-object op de pagina, en zelfs tussenSilverlight-objecten onderling. Tevens wordt het opslaan van bestan-den, navigatie tussen verschillende XAML-bestanden, formulier-validatie, het programmeren van behaviors en het bouwen van usercontrols toegelicht.

Een belangrijk deel van het programmeren heeft te maken met hetweergeven en opslaan van data. Net zoals in andere .Net-toepassin-gen kan in Silverlight gebruik gemaakt worden van databinding,hoewel er kleine verschillen zijn in de manier waarop dit wordttoegepast. In het boek wordt beschreven hoe databinding ingezet kanworden in het project. De data die je toont in de applicatie wordtmeestal ergens opgeslagen. Hierop hebben de onderdelen overIsolated Storage, webservices en databases betrekking. Daarbij is deIsolated Storage een handige toepassing om offline (bij de gebruiker)gegevens bij te houden, en worden webservices met een achterlig-gende database gebruikt om gegevens centraal op een server op teslaan.

Het onderdeel programmeren geeft voorbeelden van toepassingen dieveel gebruikt zullen worden bij het programmeren in Silverlight. Hetgaat dan vooral om zaken die niet zonder programmeren te bewerk-stelligen zijn. Om het praktijkgedeelte te kunnen begrijpen wordt erwel vanuit gegaan dat de lezer achtergrondkennis van .Net heeft.

PublicerenHet uiteindelijke publiceren heeft te maken met het live zetten van deapplicatie en alles wat daarmee samenhangt. De instellingen voor IIS(voor hosting op een Windows platform) worden daarbij genoemd,maar ook de mogelijkheden om op andere operating systems tehosten. Daarbij komt verder nog naar voren hoe een Silverlight-projectgepubliceerd kan worden en hoe een XAP-bestand is opgebouwd.Vanaf Silverlight 3 is het mogelijk geworden een applicatie ‘out ofbrowser’ te publiceren, waarmee een Silverlight applicatie met ééndruk op de knop op de desktop geïnstalleerd kan worden. Dit is eenzeer interessante feature, waarvoor ook in dit boek aandacht is.Tot slot is de informatie aanwezig over de doorzoekbaarheid,de toegankelijkheid en het aanpassen van het installatieproces van deSilverlight-plugin.

ConclusieDe inhoud van dit boek is gericht op een brede doelgroep. Het heleproces van concepten tot het publiceren op het web wordt besproken.Hierdoor komt een enorm scala aan onderwerpen aan bod, zodat jedoor het lezen van dit boek een brede basiskennis van Silverlightopbouwt. Zelfs wanneer ontwerpen of programmeren niet jouw eigenrol is, is het toch nuttig om te weten wat er speelt bij de mensen metwie je samenwerkt. Doordat er zoveel onderwerpen wordenbesproken, blijft de informatie per onderwerp in sommige gevallen vrijbeknopt. Met de handvatten die in die boek worden aangereikt, kanje vervolgens wel met een degelijke achtergrondkennis op zoek naarmeer specifieke informatie. De titel van het boek is treffend gekozen,want het kan inderdaad als een handboek worden gezien. Dit boek isdan ook geen typisch leer- of cursusboek met stap-voor-stap tutori-als en meerdere voorbeelden, maar eerder een boek dat veel theore-tische, maar wel praktisch toepasbare informatie biedt en waar je laternog eens op terug kan vallen wanneer je op zoek bent naar specifiekeinformatie. Dus voor wie met Silverlight aan de slag wil, maarop internet dreigt te verdrinken in het informatieaanbod, of voor wiezijn kennis van Silverlight wil verbreden, biedt dit boek een goedeuitkomst. •

Titel: Handboek Silverlight 3 Auteur: Antoni Dol Uitgever: Van Duuren Media ISBN: 978-90-5940-388-8 Pagina’s: 380 pagina’s

Emile van Ewijk

Emile van Ewijk is .Net ontwikkelaarbij Amercom, waar hij met mensenuit verschillende disciplines samen-werkt aan het ontwikkelen vanwebapplicaties. Hij is geïnteresseerdin alles wat met web developmentte maken heeft, vooral wanneer hetgaat om het inzetten nieuwetechnieken.

Page 61: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

.NET Marcel Peereboom

Architectuur 101Design patterns worden gebruikt om applicatie-architecturen vorm tegeven. Welke architectuur echter ook wordt gebruikt, elke architec-tuur streeft uiteindelijke naar één doel: “loose coupling and highcohesion”, ofwel “verdergaande ontkoppeling en toenemendesamenhang” in goed Nederlands. En dàt is nu waar het MVP designpattern om gaat.

De geschiedenisIn de tijd dat applicaties van traditionele client-server architecturennaar 3- of meer lagen applicaties evolueerden, ontstond intoenemende vraag behoefte aan het antwoord op de vraag: hoescheid ik de (G)UI code van de business layer code? Het "Separationof Concerns" principe, zoals beschreven door Edsger Wiebe Dijkstra(zie http://en.wikipedia.org/wiki/Separation_of_concerns) was hieropeen antwoord. Het Model-View-Controller (MVC) design pattern waseen design pattern dat op dit principe werd ontwikkeld.Het MVC design pattern is al in 1979 beschreven voor SmallTalk, enin de volgende 30 jaar is er natuurlijk veel veranderd. In de loop van detijd zijn er verschillende variaties op dit thema ontstaan. Het ASP.NETMVC Framework is geen MVC-pattern in de originele zin; dertig jaargeleden bestond web-development nog helemaal niet.Dit framework maakt gebruik van het Model2 design pattern(http://en.wikipedia.org/wiki/Model2); een MVC web-variant.In het begin van 1990, toen OO al iets verder was uitgebouwd, is uiteen joint venture van Apple, HP en IBM om een nieuw OS te ontwik-kelen (genaamd “Taligent”) het MVP pattern ontstaan, wat later doorde Java-wereld werd overgenomen.

Het MVP-pattern werd pas echt beroemd toen Martin Fowler zichermee bemoeide. Nadat Fowler enige tijd had nagedacht over hetMVP-pattern kwam hij tot de conclusie dat het MVP-patternopgesplitst zou moeten worden in twee afzonderlijke patterns:Supervising Controller(http://www.martinfowler.com/eaaDev/SupervisingPresenter.html)en Passive View(http://www.martinfowler.com/eaaDev/PassiveScreen.html).De term MVP was inmiddels echter zo ingeburgerd dat het MVPdesign pattern als zodanig is blijven bestaan.Een WPF variatie op het MVP design pattern is het PresentationModel: http://www.martinfowler.com/eaaDev/PresentationModel.htmlof Model-View-ViewModel pattern(zie http://en.wikipedia.org/wiki/Model_View_ViewModel).Weet je nu niet meer wanneer je welk design pattern kunt gebruiken,raadpleeg dan de onderstaande matrix:

magazine voor software development 61

MVP:Most Valuable Pattern?Met het .NET framework 4.0 in het vooruit-schiet is er een nieuwe loot aan de ASP.NETtechnologie boom: het ASP.NET MVC Frame-work (MVC = Model-View-Controller). En metdit framework ontstaat er weer discussie overeen oud design pattern, maar daarmee wordteen wellicht belangrijker design pattern overhet hoofd gezien: het Model-View-Presenterpattern. Laat ik eens uitleggen waarom MVPeen "Most Valuable Pattern" is.

InleidingOver design patterns is veel geschreven, maar ik zie dat deze in depraktijk nog onvoldoende worden toegepast. Waarom dat zo is vraagik mij geregeld af. Toen bij een SDE van enige tijd geleden de sprekervroeg wie het MVP pattern kende, stak slechts een handje volmensen hun hand op. Ergo: het is tijd om wat kennis met jullie te delenen toe te lichten waarom het Model-View-Presenter design pattern(hierna MVP genoemd) een "Most Valuable Pattern" is.

Design patterns 101Wat zijn design patterns? Ik definieer een design pattern als eensjabloon dat een standaard oplossing beschrijft van een standaardprogrammeerprobleem. Begin daarom bij het toepassen van designpatterns ook met het benoemen van het probleem.Een bekend voorbeeld is het probleem dat er maar één instantie vaneen bepaalde klasse in de applicatie mag voorkomen. Het antwoordis het singleton pattern (http://en.wikipedia.org/wiki/Singleton_pattern).Het singleton pattern beschrijft hoe je realiseert dat je van een klasseslechts één instantie kunt maken.Maar design patterns zijn vooral sjablonen: hoe je een pattern preciesimplementeert, wordt niet dwingend voorgeschreven maar men geeftalleen advies over hoe je het zou kunnen doen.Design patterns hebben als doel standaard oplossingen voor teschrijven voor standaard programmeerproblemen. Het voordeel vanstandaard oplossingen is dat deze al in de praktijk zijn uitgetest. Hettweede doel van design patterns is vooral te kunnen communicerenover de architectuur van een applicatie. Om bij dit voorbeeld te blijvenkan een software-architect zeggen: van deze klasse mag in deapplicatie maar één instantie voorkomen en om dit te bereiken dientvan het singleton-pattern gebruik te worden gemaakt.

Het Model-View-Presenter patternis een Most Valuable Pattern

Architectuur streeft naar“loose coupling and high cohesion”

Page 62: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

MAGAZINE62

.NET

Tabel 1: Wanneer gebruik je welk design pattern?

Hoe werkt MVC?In het MVC-pattern beschrijft het “Model” de data in de business layeren de “View” de representatie ervan in de user interface. De “Control-ler” verzorgt de communicatie tussen de twee andere lagen, veelaldoor middel van Observer- of Publish/Subscribe-patterns. Eenvervanging voor deze twee patterns in .NET zijn "events" (eventEventHandler<EventArgs>). Zie figuur 1.

Fig. 1: Eenvoudig diagram dat de relatie beschrijft tussen Model,View en Controller.Noot: De bloklijnen geven een directe associatie weer en de stip-pellijnen een indirecte associatie (observer pattern / events).

Eén van de grootste nadelen van het MVC pattern is dat zowel deModel, de View en de Controller concrete klassen, concreteimplementaties zijn. Een wijziging in één van de klassen leidt direct toteen hercompilatie van alle drie de klassen en dus van de heleapplicatie. Er is dus geen sprake van “loose coupling”.

Hoe werkt MVP: de theorieHet MVP-pattern is voornamelijk een presentation layer designpattern. Een presentation layer in een applicatie bestaat uit twee lagen:• een view/GUI• presentatie logica

De technologie die gebruikt wordt voor de view/GUI bepaalt vaak watvoor soort context er beschikbaar is in de client (rich-client / web-client). En dit heeft vaak weer veel impact op hoe de presentatielogicawordt ontwikkeld. Maar het is tegenwoordig niet ongewoon om in éénapplicatie zowel een web-client als een rich-client te moeten onder-steunen. En juist dan zou je de presentatielogica willen hergebruiken.Bij een goede MVP-implementatie is dit dan ook zeer wel mogelijk.

In object-oriëntatie is het werken met interfaces *de*manier om loosecoupling te verwezenlijken, en dit is o.a. het verschil tussen hetMVC-pattern en het MVP-pattern. In een MVP-implementatie praatde presenter tegen een interface, waarbij het interface geïmplemen-teerd wordt door de view.

Het MVP-pattern bestaat dus uit:• Een "Model": een concrete klasse die de data voorstelt. Deze komtmeestal uit de Business Layer. Een webservice/WCF proxy klassevoldoet ook;

• Een "View": een concrete klasse die de GUI voorstelt. Dit kan eenWindows Forms klasse, een aspx-pagina, een WPF-Forms klassezijn. Voor WPF en/of Silverlight is de variatie "Presentation Model"beschikbaar;

• Een "View Interface": een interface die de data (in de vorm vanproperties) beschrijft waar de GUI iets mee moet doen. Deze inter-face moet geïmplementeerd worden door de "View";

• Een "Presenter": een concrete klasse die de data uit de "ViewInterface" (die weer wordt geïmplementeerd door de "View") leest enschrijft en deze aan het "Model" (de business layer) geeft.

In object-oriëntatie is het werkenmet interfaces *de* manier omloose coupling te verwezenlijken

Dit betekent dat je per weer te geven object werkt met drie klassen enéén interface:1. De business layer "Model" klasse: dit object vormt een onderdeelvan het domeinmodel (of een proxy daarvan) waarvoor je eenapplicatie maakt en bevat alle gegevens (properties) en gedrag(methoden en events) die dit object nodig heeft in het domein-model;

2. Een View klasse. Dit is een WinForms-, WPF-, of ASPX-paginaklasse die de GUI moet gaan voorstellen voor de gebruiker. In eenMVP implementatie bepaalt de view alleen maar hoe iets getoondmoet worden: of een eigenschap van een buisness object nu wordtweergegeven in een textbox, een label, combobox, radio buttons ofom het even wat voor control(s), dat is de verantwoordelijkheid vandeze klasse. Ergo: deze klasse is alleen maar verantwoordelijk voorde rendering van de te tonen objecten;

3. De interface: deze schrijft dwingend voor wat er getoond moet wor-den d.m.v. property definities (op het gedrag kom ik later terug). Deinterface moet worden geïmplementeerd in de view klasse (punt 2);

4. De presenter klasse: deze kent de Model klasse (via een referentienaar de betreffende assembly of d.m.v. gegenereerde proxy klas-sen) en kent alleen de interface. De presenter krijgt de data van eenbusiness layer klasse en schrijft deze data naar de properties in deinterfacedefinitie. De presenter heeft dus geen weet van wat voortype GUI (webclient of rich client) hij bedient. De presenter is alleenverantwoordelijk voor wanneer iets getoond moet worden.

GUI klassen kennen vaak iets van een run-time context waar je in deniet-GUI lagen geen weet van wil hebben; denk hierbij bijvoorbeeldaan de HttpContext die je indirect meekrijgt met een ASPX-pagina ofhet feit dat een textbox control in WinForms statefull is. Doordat depresenter alleen met de view communiceert via een interface, ontstaater een verdere ontkoppeling tussen de GUI en de manier waarop dedata wordt verwerkt. De presenter heeft dus geen weet van in watvoor soort context hij zit.

ASP.NET WinForms WPF

MVC web / Model2 •

Model View Presenter • • •

Presentation Model •

Geen Loose Coupling is hetnadeel van het MVC-pattern

Een applicatie met zowel een Web alsRich-Client interface is zeer gebruikelijk

Page 63: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

magazine voor software development 63

.NET

Omdat iedere klasse/interface zijn eigen verantwoordelijkheid heeft,wordt het “Single Responsibility Principle” als vanzelf toegepast (zieook: Separation of Concern vs Single Responsibility Principle ophttp://weblogs.asp.net/arturtrosin/archive/2009/01/26/separation-of-concern-vs-single-responsibility-principle-soc-vs-srp.aspx).

Het verschil tussen een Supervising Controller (SVC) en een PassiveView (PV) is dat bij een Supervising Controller implementatie (meestal)complexe objecten in de interface worden gedefinieerd en in de View(GUI klasse) gebruik gemaakt kan worden van geavanceerdere tech-nieken als databinding, terwijl bij een passive view implementatie in deinterface definitie de eigenschappen van complexe business layerobjecten worden gedefinieerd als een reeks van simple type proper-ties (string, int, bool, DateTime, etc.).Dit alles lijkt misschien nog wat abstract, dus laten we dit eens in eencodevoorbeeld uitwerken. De code voor dit artikel is beschikbaar viade website en bevat een ASP.NET en een WinForms voorbeeld in eenPV- en een SVC implementatie.

Hoe werkt MVP: de praktijk, deel 1Het voorbeeld business layer model bestaat, om het eenvoudig tehouden, uit één object: Person, met als eigenschappen "Name"(string) en "Age" (int) en methoden "Save" ,"Delete", "Get(int id)" en"GetAll". De oplettende lezer vermoed reeds het Active Record pat-tern. Commentaar is omwille van bondigheid achterwege gelaten (zielisting 1).

public class Person{public int ID { get;set;}public string Name { get;set;}public int Age { get;set;}

public void Save(){ Debug.WriteLine(

"Saving this person to a database..."); }

public void Delete(){ Debug.WriteLine(

"Deleting this person from a database..."); }

public static Person Create(){ return new Person {ID = (-1),Name = string.Empty, Age = (-1)} }

public static Person Get(int id){

Person person = new Person{ ID = id,

Name = string.Format("James Bond {0:000}", id),Age = (50 + id)

};

return person;}

public static List<Person> GetAll(){

List<Person> result = new List<Person>(9);for(int i = 1; i < 10; i++){

result.Add(Get(i));}return result;

}}

Listing 1 (C#): Het business layer object Person

Tot zo ver niets spannends. Dit object leeft op/in de server en komt opwat voor manier dan ook op de client terecht. De user interface, zowelwebforms als winforms, is ook niet spannend: zie figuur 2.

Fig. 2: De user interface om personen weer te geven

De interfacedefinitie bepaalt alleen dat er een integer met de naam"ID" in een GUI klasse gelezen en geschreven kan worden, evenalseen tekst property "Name" en een integer met de naam "Age". Er kanalleen een list van Person-objecten ‘geset’ worden (zie listing 2).Hoe deze properties getoond moeten worden, is niet de verantwoor-delijkheid van het interface. In de Windows-client wordt b.v. de ID pro-perty getoond met een numeric up/down control i.p.v. een textbox.

public interface IPersonView{int ID { get; set; }string Name { get; set; }int Age { get; set; }List<Person> Persons { set; }

}

Listing 2 (C#): het interface van Person

De GUI klasse, de view, moet het interface implementeren. De eersteopzet staat in listing 3.

public partial class PersonView : Form, IPersonView{public PersonView(){ InitializeComponent(); }

public int ID{get { return Convert.ToInt32(IDTextBox.Text); }set { IDTextBox.Text = value.ToString(); }

}

public int Age{get { return Convert.ToInt32(AgeUpDown.Value); }set { AgeUpDown.Value = Convert.ToDecimal(value); }

}

string IPersonView.Name{get { return NameTextBox.Text; }set { NameTextBox.Text = value; }

}

public List<Person> Persons{ set { PersonsBindingSource.DataSource = value; } }

}

Listing 3 (C#): de implementatie van het interface in de view

Het implementeren van de properties uit de interface lijkt erg voor dehand te liggen, maar toch wil ik twee opmerkingen maken:• Valideer altijd, altijd, altijd de user input ("All user input is evil").Gebruik dus nooit Convert.ToInt32() direct in een property get zoalsin dit code voorbeeld;

Page 64: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

MAGAZINE64

.NET

• Een Form-object kent al een property Name. Daarom wordt dename-property van Person expliciet geïmplementeerd door stringIPersonView.Name.

De presenter doet dienst als intermediair tussen de view en de model.Kijk eerst even naar de code in listing 4.

public class PersonPresenter{private IPersonView View;

public PersonPresenter(IPersonView view){

if(view == null){ throw new ArgumentNullException("view"); }

View = view;}

public void Delete(){

Person person = Person.Get(View.ID);person.Delete();

}

public void Save(){

Person person = new Person{ Name = View.Name, ID = View.ID, Age = View.Age };

person.Save();}

public void New(){

Person person = Person.Create();View.ID = person.ID;View.Name = person.Name;View.Age = person.Age;

}

public void Get(){

Person person = Person.Get(View.ID);View.Name = person.Name;View.Age = person.Age;

}}

Listing 4 (C#): de implementatie van de presenter

De presenter kent een variabele die een object-instantie bevat die hetinterface implementeert. Via de constructor van de presenter wordtdeze object-instantie "gevuld". De presenter weet dus niet wat voortype object dit is; hij weet alleen dat dit object het interfaceimplementeert.Het gedag van de presenter wordt bepaald door de beschikbaremethoden die de business-objecten (het model) aanroepen en deproperties vanuit de interfacedefinitie lezen.

Maar de grote vraag blijft nu ongetwijfeld: hoe werkt dit nu allemaalsamen? De magie van het MVP-pattern wordt gevormd in drie regels(1, 3 en 8) in listing 5. Er moet één variabele van het type presenter aande view-class worden toegevoegd die in de constructor wordtgeïnstantieerd.

1 public partial class PersonView : Form, IPersonView2 {3 private PersonPresenter presenter;45 public PersonView()6 {7 InitializeComponent();8 presenter = new PersonPresenter(this);

9 }// Andere properties methodes en events

}

Listing 5 (C#): de magie van het MVP pattern

De view-class bevat nu een private variabele van het type van depresenter (regel 3). In de constructor van de view-class wordt er eeninstantie van de presenter gecreëerd (regel 8). De constructor van depresenter vereist als parameter een object dat IPersonView imple-menteert. Dat doet de view-class (zie regel 1). Daarom wordt in deconstructor bij de creëren van de presenter een instantie van zichzelfmeegegeven. Door het gebruik van een interface wordt alle overbodigecontext in de presenter eruit gefilterd.

Het gedrag wordt nu heeft eenvoudig beschikbaar in de event-handlers van de knoppen op de view (zie listing 6). Kun je aan ditcodevoorbeeld zien uit welk type client deze komt?

private void NewButton_Click(object sender, EventArgs e){ presenter.New(); }

private void SaveButton_Click(object sender, EventArgs e){ presenter.Save (); }

private void DeleteButton_Click(object sender, EventArgs e){ presenter.Delete(); }

Listing 6 (C#): De implementatie van het gedrag in de interface.

Hoe werkt MVP: de praktijk, deel 2Op zich is het voorbeeld zoals hiervoor beschreven een valideimplementatie van het MVP-pattern, maar er is een logisch probleemmet deze implementatie: de view heeft nu expliciete kennis van depresenter en het gedrag dat deze aanbiedt. De view is nu ookverantwoordelijk voor het aanroepen van dit gedrag. In een MVC-implementatie communiceert de controller d.m.v. events met hetmodel en de view. Voor een logisch nettere implementatie van MVPzou je dit ook moeten doen.Je doet dit door het beschikbare gedrag als events vast te leggen inhet interface. Hiermee dwing je in een view niet alleen de beschikbaredata (d.m.v. property-definities) af, maar ook het gedrag (zie listing 7).

public interface IPersonView{event EventHandler<EventArgs> Get;event EventHandler<EventArgs> Save;event EventHandler<EventArgs> Delete;event EventHandler<EventArgs> New;

Person CurrentPerson { get; set; }List<Person> Persons { set; }

}

Listing 7: een beter interface van Person

In de GUI-klasse die dit interface zal implementeren, moeten de events"Get", "Save", "Delete" en "New" gedefinieerd zijn. De interfacebepaalt ook hier alleen dat er een bepaald gedrag zal zijn, niet hoe ditgedrag zal zijn (zie listing 8).

public partial class PersonView : Form, IPersonView{public event EventHandler<EventArgs> Get;public event EventHandler<EventArgs> Save;public event EventHandler<EventArgs> Delete;public event EventHandler<EventArgs> New;

private PersonPresenter presenter;

Page 65: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

magazine voor software development 65

.NET

public PersonView(){

InitializeComponent();presenter = new PersonPresenter(this);

}

private void NewButton_Click(object sender, EventArgs e){ if(New != null) { New(sender, e); } }

private void SaveButton_Click(object sender, EventArgs e){ if(Save != null) { Save(sender, e); } }

private void DeleteButton_Click(object sender, EventArgs e)

{ if(Delete != null) { Delete(sender, e); }

// Andere properties methodes en events}

Listing 8: een view met alleen signaleringen

Het mooie aan dit voorbeeld is, dat de view nu geen kennis heeft vande presentatie-logica. Het enige dat de view doet, is een eventafvuren als er iets gebeurt. Het gedrag (de event-definities) is in hetinterface afgedwongen en de view zegt: als er iets gebeurt, dan zal ikdat zeggen. Wat er vervolgens moet gebeuren en hoe, dat is aan depresenter en het model. De presenter abonneert zich op de eventsdie zijn gedefinieerd in het interface (nogmaals: de presenter kent deview niet, alleen het interface) en implementeert de event-handlers opdeze events, zoals in listing 9:

public class PersonSvcPresenter{private readonly IPersonSvcView svcView;

public PersonSvcPresenter(IPersonSvcView view){

if(view == null){ throw new ArgumentNullException("view"); }

svcView = view;svcView.Get += OnGetView;svcView.New += OnNewView;svcView.Save += OnSaveView;svcView.Delete += OnDeleteView;

}

private void OnDeleteView(object sender, EventArgs e){

// Do your presentation logic level validations herePerson person = svcView.CurrentPerson;person.Delete();

}

private void OnSaveView(object sender, EventArgs e){

// Do your presentation logic level validations herePerson person = svcView.CurrentPerson;person.Save();

}

private void OnNewView(object sender, EventArgs e){

Person person = Person.Create();svcView.CurrentPerson = person;

}

private void OnGetView(object sender, EventArgs e){

svcView.Perons = Person.GetAll();}

}

Listing 9: een nettere presenter

De implementatie in dit tweede deel leidt tot een verdere ontkoppelingvan de GUI met zijn presentatie-logica, wat vanuit architectuuroogpunt wenselijk is. Maar ik wil er een paar opmerkingen over maken:• Als je net met het MVP-pattern aan de gang gaat, lijkt het ergondoorzichtig. Dat is echter van tijdelijk aard. Als je dit pattern eenpaar keer hebt toegepast, gaat het allemaal vanzelf;

• Als je Resharper gebruikt (of wellicht een andere tool), dan klaagtResharper dat de presenter in de view alleen maar wordtgeïnstantieerd, maar verder niet wordt gebruikt. Negeer die klacht.

De coding guidelines van IDesign.Net (Juval Lowy) schrijven voor datin een interface-definitie geen event-declaraties zouden moetenvoorkomen. Waarom dat is, weet ik niet (ik zou het op prijs stellen alsiemand het mij kon vertellen). Een event-definitie in een interface is welgebruikelijk in het MVP-pattern.In sommige coding guidelines geldt een write-only property als een"design flaw". Als je het daarmee eens bent, definieer dan in deinterface een aparte set-methode i.p.v. een property set.

Tips & TicksHieronder staat een aantal aanwijzingen en overdenkingen voor goedgebruik.• Naamgeving: geef je GUI-classes de naam van het object dat zemoeten weergeven en suffix deze met "View", b.v. class Person-View : Form;Voor het interface geldt dat deze heten als de GUI-class met een "I"prefix, b.v. interface IPersonView;De presenter heet "MyObject"Presenter, b.v. class PersonPresenter.

• De presenter wordt samen met de interface-definitie waar depresenter op acteert, in een aparte assembly geïmplementeerd;

• Gedrag wordt gedefinieerd d.m.v. events van meestal dit type: eventEventHandler<EventArgs>. De data die je mogelijkerwijs nodig hebtbij het verwerken van een event kun je het best definiëren in eenproperty in je interface;

• Die properties die read-only in de GUI zijn, worden gedefinieerd alseen set property in de interface (b.v. teksten van labels). Write-onlyproperties in de GUI worden gedefinieerd als een get property in deinterface (b.v. een wachtwoord);

• Het MVP-pattern leent zich erg goed om complexe objecten incustom user controls te implementeren;

• Wanneer de GUI-class meerdere complexe objecten moet tonen(omdat je een tabpage-control gebruikt om verschillende objectente tonen) kan je GUI-class meerdere interfaces implementeren.Multiple inheritance wordt niet ondersteund in .NET, maar meerdereinterfaces kunnen wel in één class worden geïmplementeerd (maarwellicht zou ik dan toch voor custom user controls kiezen);

• Als je niet iedere keer de volgende code in je event handlers wilschrijven:if(Save != null) { Save(sender, e); }maar in één keerSave.Raise(sender, e);lees dan de blog entry "Eventing made easy: MyEvent.Raise(this,EventArgs.Empty);" van Pieter-Joost van der Sande op:http://born2code.net/blog/1-general/15-eventing-made-easy-myeventraisethis-eventargsempty.html

ConclusieHoewel het MVP design pattern erg ingewikkeld kan lijken als je ervoor de eerste keer naar kijkt en de complexiteit van de code iets toe-neemt, acht ik het MVP design pattern een "Most Valuable Pattern"omdat dit pattern kan worden gebruikt in zowel WPF, WinForms als

Page 66: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

Windows 7 TIP:Windows 7: Pinnen naar TaskBarIn Windows 7 is het nog eenvoudiger om applicaties op detaskbar te pinnen, zodat je ze binnen handbereik hebt. Je sleepthet icoontje van de applicatie gewoon naar de TaskBar.

Visual Studio 2010 TIP:Visual Studio 2010: ZoekfunctieDe zoekfunctie van Visual Studio 2010 laat nu alles zien watvoldoet aan de ingetypte string. Je kunt ook meerdere woordenintypen en dan krijg je alle voorkomens met beide woorden.Ook kun je de letters van Pascal casing gebruiken.

.NET

ASP.NET. Met het MVP pattern krijg je bijna automatisch het "Sepa-ration of Concerns" principe en het "Single Responsibility Principle"cadeau. De presentatie-logica is beter herbruikbaar. Tevens is depresentatie-logica beter testbaar via frameworks als Rhino.Mocks(http://www.ayende.com/projects/rhino-mocks.aspx), omdat depresenter op een interface acteert. Maar bovenal bereik je met hetMVP-pattern een verdergaande ontkoppeling en een toenemendesamenhang (loose coupling and high cohesion). Dat wil jij toch ookbereiken in je code? Op de website staat de code uitgewerkt metcommentaar in een SVC- en een PV-implementatie ,zodat je er zelfeens mee kunt spelen.

Om zelf te lezen:• Martin Fowler:

http://www.martinfowler.com/eaaDev/ModelViewPresenter.html• Wiki MVP: http://en.wikipedia.org/wiki/Model_View_Presenter• Wiki MVC: http://en.wikipedia.org/wiki/Model-view-controller• MVC#: http://www.mvcsharp.org/

Marcel Peereboom

Marcel Peereboom is programmeur.Punt. Zijn streven is TOPBEV-code(zie SDN mag 97). Zijn motto: kennisdelen = macht! SQL Server, C# engoede wijn zijn zijn passie. Hij werktbij Integer (http://www.integer.nl).

Op de onderstaande site wordt m.b.v. webcasts uitgelegd hoe MVPwerkt:• Design Patterns Bootcamp: Model View * Patterns:

http://www.polymorphicpodcast.com/shows/mv-patterns/ •

Advertentie Barnsten/Embarcadero

Page 67: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

DELPHI Peter van der Sman

Het schermtoetsenbordWat niet iedereen blijkt te weten is dat Windows de mogelijkheid biedtom een visuele weergave van het toetsenbord op het scherm te tonen.Als je onder Start - Programma's - Bureau-Accessoires - Toeganke-lijkheid kiest voor “Schermtoetsenbord” dan krijg je een venster metde weergave van het toetsenbord. Het aardige is dat we meteen zienwat het effect is van een toetsaanslag. Zo krijgen we als we de shiftindrukken meteen alle hoofdletters te zien. En zo kom je er eenvoudigachter dat je een “®” eenvoudig kan maken met CRTL+ALT+R (inieder geval op mijn computer en met mijn toetsenbord instellingen).

Fig. 1: Schermtoetsenbord met CTRL+ALT (of alleen RECHTERALT) ingedrukt

Achter de schermen wordt hiervoor het programma OSK.EXE gestart,dat we kunnen vinden in de SYSTEM32-directory. OSK staat overi-gens voor On-Screen Keyboard.Er zitten wel een paar beperkingen aan OSK.EXE. Zo kan het maaréén keer opgestart worden. Dat maakt het lastig om het vanuit je eigenprogramma op te starten: je weet immers nooit of de gebruiker het alniet opgestart heeft. En het staat het altijd op de voorgrond, maar datis wel logisch, want het is immers bedoeld als hulp bij het invoeren.Daarnaast kijkt het programma niet echt hoe het fysieke toetsenborderuit ziet: het kent een aantal basistoetsenborden waarmee je kuntproberen iets te vinden wat zoveel mogelijk op je eigen toetsenbordlijkt. Maar voor het moment is het een prima hulpmiddel om te zien water allemaal gebeurt.

Een ander toetsenbord gebruikenLaten we het simpel houden en doen alsof we een medewerker heb-ben die uit België komt en niet goed overweg kan met het “qwerty”toetsenbord, omdat in België nu eenmaal het “azerty” toetsenbordstandaard is. Het is heel eenvoudig om voor die persoon het toetsen-bord van “qwerty” om te zetten in “azerty”. In het configuratieschermkunnen we onder “Landinstellingen” aangeven dat we Frans alsinvoertaal willen gebruiken: klik in de tab “Talen” op “Details” en gebruikdaar de knop toevoegen en kies voor “Frans” met de toetsenbordin-deling “Frans”. Even op “Toepassen” klikken en klaar zijn we!Controleer ook even bij de “Voorkeursinstellingen” onder “Taalbalk”zodat deze wordt weergegeven op het bureaublad.

En nu kunnen we eenvoudig van invoertaal wisselen; door degewenste invoertaal te kiezen in de taakbalk of door de sneltoets tegebruiken (standaard wordt Shift+Alt gebruikt om naar de volgendeinvoertaal over te schakelen). Dit omschakelen is de reden dat ikhierboven koos voor Frans als invoertaal en niet “Nederlands (België)”.Nu kun je veel eenvoudiger de invoertaal wijzingen.Ieder programma wordt gestart met het toetsenbord zoals datgespecificeerd is bij “Standaardinvoertaal”. Daarna kunnen we de taal(dat wil zeggen de te gebruiken lay-out van het toetsenbord) voor iederprogramma afzonderlijk instellen. Zo kunnen eenvoudig omschakelennaar “Frans” en dit artikel verder op zijn Frans intikken.Hier merken we overigens nog een beperking van OSK.EXE: als wevan invoertaal wisselen heeft het schermtoetsenbord dat niet meteenin de gaten. We moeten er even met de muis overheen om hetactuele toetsenbord in te stellen.Overigens kun je ook gewoon bij de taal “Nederlands” kiezen voor een“Frans” of een willekeurig ander toetsenbord. Dvorak schijnt insommige kringen populair te zijn. Het is een goede manier om tezorgen dat anderen niet meer soepel op jouw computer kunnenwerken. Dat kan zowel een voordeel als een nadeel zijn!

Windows en toetsenbordenWindows identificeert toetsenborden met HKL’s (Handle KeyboardLayouts). Een HKL is een longword en bestaat uit twee delen: eenspecificatie van de invoertaal en een specificatie van de gekozentoetsenbord lay-out. De specificatie van de invoertaal bestaat ookweer uit twee delen, de taal zelf en het dialect. Zo staat “$0413” voorNederlands, “$0813” staat voor “Belgisch” (Vlaams dus). “$0409” is“US”, “0809” is Engels.De specificatie van de gekozen lay-out is feitelijk een volgnummer.“0000” is het standaard toetsenbord en zo wordt er verder geteld.

magazine voor software development 67

Het Magische ToetsenbordVol verwachting keek ze naar mijn handen toen ik vertelde dat het programma wist welke invoerhet verwacht en zelf van toetsenbord wisselt. Alsof er onder mijn handen echt een andertoetsenbord tevoorschijn getoverd zou worden… maar dat gebeurde natuurlijk niet. In ditartikel wordt een aantal procedures besproken om het toetsenbord te manipuleren.De voorbeelden zijn in Delphi, maar aangezien het eigenlijk vooral aanroepen van de WindowsAPI zijn zullen ze betrekkelijk eenvoudig naar andere talen omgezet kunnen worden.

En nu kunnen we eenvoudig vaninvoertaal wisselen: door de gewensteinvoertaal te kiezen in de taakbalkof door de sneltoets te gebruiken

Fig. 2: Registry entries voor invoertaal Nederlands

Page 68: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

MAGAZINE68

DELPHI

De lijst met geïnstalleerde talen kunnen we in de Registry vinden onder“HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts”. Daaronder vinden we een lijst met beschikbareHKL’s. Onder die HKL’s kunnen we de specificatie, waaronder een“Layout Text”, vinden.

Een voorbeeldapplicatieOm te laten zien hoe het werkt met verschillende toetsenborden hebik een voorbeeldprogramma gemaakt waarmee je invoer in 4 ver-schillende talen kunt doen. Het programma heet “MultiKbd” en is tevinden in de download. In het scherm zijn 4 TMemo’s opgenomenwaarvoor de taal kan worden ingesteld. Hieronder volgt een voorbeeldvan 4x “querty” intypen met vier verschillende toetsenborden:

Fig. 3: Voorbeeldapplicatie

Bij het opstarten zet het programma 4x een combinatie van TComboen TMemo op het scherm. Daar zou ik natuurlijk een mooiecomponent van hebben kunnen maken, maar eerlijk gezegd heb ik erzelf een hekel aan om voor een voorbeeld eerst allerlei componentente moeten installeren. Dat vermijd ik door de componenten pas bij hetopstarten op het form te zetten.In de TCombo’s wordt de lijst met beschikbare toetsenbordenopgenomen (die worden dus uit de Registry gehaald, zie hierboven),en er wordt een “willekeurig” toetsenbord gekozen. En de TMemo’sweten nu welk toetsenbord ze moeten gebruiken! En het mooiste vanallemaal: we hoeven die toetsenborden niet eens vooraf via desettings beschikbaar te stellen!

Bij het “willekeurig” kiezen van een toetsenbord heeft het programmawel degelijk een voorkeur. Er wordt geprobeerd een Nederlands, eenFrans, een Russisch en een Grieks toetsenbord te kiezen. Daarbijwordt gebruik gemaakt van het feit dat de basistaal is opgenomen inde HKL. Wat het programma doet is alle mogelijkheden aflopen totdater eentje met de gezochte taal gevonden wordt. Maar vaak wil je datnog wat specifieker opgeven. Zo krijg ik op mijn computer een“Belgian French” toetsenbord als ik “Frans”, met code $080c, als taalopgeef. Geen idee wat het verschil is, maar meestal zitten deverschillen in speciale tekens en hoe je letters met accenten kuntkrijgen. Om die te selecteren kan naast de taal ook de rest van deHKL getest worden.Het kan nog iets specifieker gemaakt worden. Als de gebruiker al eentoetsenbord met taalcode “Frans” heeft is het natuurlijk wel zo aardigdie dan ook maar te gebruiken.Om er achter te komen of, en zo ja met welk toetsenbord, een taal isgeïnstalleerd, kunnen we de functie “GetKeyboardLayoutList” gebrui-ken. Die geeft ons een lijst met de geïnstalleerde toetsenborden.

Of beter: de functie geeft ons terug hoeveel toetsenborden er zijngeïnstalleerd en geeft de specificatie daarvan in een de “array of HKL”die we als parameter meegegeven hebben. Die lijst kunnen wegebruiken om te testen of er een geschikt toetsenbord aanwezig is.

Een ander toetsenbord gebruiken/toevoegenDe (Windows) procedure die nodig is om een ander toetsenbord in testellen heet “LoadKeyboardLayout”. Deze procedure kent tweeparameters: de HKL en een optie parameter.Om het ons niet al te eenvoudig te maken moeten we de HKL nu nietals getal maar als string (of beter gezegd, een PChar) doorgeven. Debelangrijkste opties zijn KLF_ACTIVATE en KLF_SETFORPROCESS.De eerste activeert het toetsenbord, en als we KLF_SETFORPRO-CESS opgeven, dan wordt het toetsenbord alleen voor het betreffendeprogramma geïnstalleerd. Altijd handig voor een demoprogramma: hetzorgt ervoor dat je na afloop niet blijft zitten met een heleboelgeactiveerde toetsenborden!Overigens is de constante KLF_SETFORPROCESS om een of anderereden niet opgenomen in de bij Delphi meegeleverde Windows Unit,dus moeten we die zelf even declareren, met de decimale waarde van256.

lHKLstr :=’00000413’;

FHKL :=LoadKeyboardLayout(PWideChar(lHKLstr),

KLF_ACTIVATE OR KLF_SETFORPROCESS);

Listing 1: Een invoertaal instellen

Een andere optie die handig kan zijn is KLF_REPLACELANG. Dezevervangt een eventueel eerder geïnstalleerd toetsenbord met dezelfdetaal. Zo kun je er dus voor zorgen dat je per taal maar één toetsenbordinstalleert. Andere opties zijn eenvoudig in de bij Delphi (2009)geleverde helpbestanden te vinden, en anders via MSDN.De procedure “LoadKeyboardLayout” blijkt redelijk “hufter-proof” tezijn. Als je een ongeldig toetsenbord opgeeft wordt automatischgekozen voor het standaardtoetsenbord “04090409”. Dat kan in hetvoorbeeldprogramma eenvoudig worden getest: als we de tekst vande TCombo wijzigen dan wordt direct het betreffende toetsenbord ge-activeerd. Om te laten zien dat er iets gebeurt maak ik gebruik van de“poor mans debugger”: in de caption verschijnt het geïnstalleerdetoetsenbord.En wellicht is het ook handig om te weten dat je met de procedure“UnloadKeyboardLayout” een HKL weer kan deactiveren. Dat voor-komt dat je met een hele lijst toetsenborden komt te zitten. Een nadeelis wel dat ook de vooraf geïnstalleerde toetsenborden moeiteloosworden verwijderd, en dat is natuurlijk weer iets wat je niet wilt. Met denodige zorgvuldigheid toepassen dus.

Je eigen toetsenbord makenNiet tevreden met de lay-out van het toetsenbord? Maak dan gewoonje eigen toetsenbord! Dat gaat verrassend eenvoudig. Het gaat alsvolgt … Als eerste moet je bij Microsoft de “Microsoft KeyboardLayout Creator” (MSKLC.EXE) downloaden en installeren. Daarna startje het programma en kun je beginnen met een leeg toetsenbord. Hethandigst is een bestaand toetsenbord als uitgangspunt te nemen endat aan te passen. Als je klaar bent met aanpassen, genereer jeeen Setup. Die even runnen en je kunt je eigen toetsenbord hetgebruiken.Natuurlijk een geweldige manier om je collega dwars te zitten, maar erzijn ook meer praktische toepassingen te bedenken. Zo geeft mijntoetsenbord met CTRL+ALT+5 een euro-teken. Volgens het scherm-toetsenbord krijg ik met CTRL+ALT+”-“ een yen-teken (wat overigensniet werkt binnen Word). Het pond-teken is helemaal niet terug te vin-den. Maar als je die regelmatig nodig hebt kun je dus zelf een toet-senbord maken waar het pondteken wel op staat. Een anderetoepassing is om je toetsenbord echt tweetalig te maken. Dat kan

Wat het programma doet is alle moge-lijkheden aflopen totdat er eentje metde gezochte taal gevonden wordt

Page 69: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

magazine voor software development 69

DELPHI

nuttig zijn als je “af en toe” iets moet intypen in een andere taal engeen zin hebt dan steeds van toetsenbord te wisselen. Laten wegewoon even aannemen dat je in een wiskundig gebied werkt enregelmatig α, β, γ etc moet gebruiken. Je kunt nu eenvoudig een toet-senbord maken met ALT+a=α, ALT+b=β, ALT+g=γ, enz. Om het tedemonstreren doe ik bij de download een setup voor een compleetNederlands-Grieks toetsenbord.

Bij het toekennen van de karakters kun je meer dan één karakter ge-bruiken. Hoeveel is afhankelijk van welk karakter, maar het komt eropneer dat de gehele karakterreeks niet langer mag zijn dan 4 bytes.Dus als we vaak “SDN” moeten typen dan kunnen we dat gewoonachter een toets plaatsen. Probeer maar eens ALT+3 in het meegele-verde toetsenbord. Daarbij geldt dat hier de RECHTER ALT gebruiktmoet worden. De LINKER ALT activeert het (hoofd)menu van de ap-plicatie. Dus LINKS-ALT+H activeert de help in het hoofdmenu (indienaanwezig), RECHTER-ALT+H genereert het karakter “η” (feitelijk is deRECHTER ALT gelijk aan CTRL+ALT)

Een kleine waarschuwing is hier wellicht op zijn plaats. Je moet weleen beetje oppassen met het toekennen van toetsen die binnenWindows een speciale betekenis hebben. Iets aan CTRL+Ctoekennen lijkt dus een minder goed idee. Zie ook het hiervoorgenoemde voorbeeld met de yen: ALT+CLTR+”-“ heeft kennelijk een,mij onbekende, betekenis binnen Word en levert dus binnen Wordgeen yen-teken op. En dan nog een opmerking: je kunt degeïnstalleerde toetsenborden de-installeren via het configuratiescherm.Het blijkt echter dat ze dan nog wel in de Windows-registry blijvenhangen. Die entries moet je dus zelf even weghalen (onder “KeyboardLayouts”). Je kunt ze eenvoudig herkennen: het zijn de entries diebeginnen met een ‘a’.

Een beperking van MSKLC is dat je de SHIFT, ALT, enz. niet kuntherdefiniëren. Op zich natuurlijk geen probleem, waarom zou je ook?Er is echter een veelgenoemd voorbeeld waarbij het wel zinvol kanzijn: de CAPS-LOCK. Ik heb het zelf ook wel op mijn laptop: je wil eenSHIFT doen en raakt per ongeluk met je vingertop ook de CAPS-LOCK aan. Heel irritant. Er is een oplossing voor: je kunt in de registryeen ingang maken die van de CAPS-LOCK een gewone SHIFT maakt.De code is (met dank aan vele bronnen op internet):

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\

Keyboard Layout]

"Scancode Map"=hex:00,00,00,00,00,00,00,00,03,00,00,00,\

2a,00,3a,00,3a,00,46,00,00,00,00,00

Listing 2: Code om van de CAPS-LOCK een SHIFT te maken

Wel eerst even opnieuw opstarten (het is tenslotte Windows).En tja, als je die collega nu echt eens flink dwars wilt zitten, dan is ditwel een geschikte manier. Als je wilt maak je een toetsenbord met al-leen maar SHIFT-toetsen. Zorg er wel voor dat je het nog ongedaankunt maken! De manier om het ongedaan te maken is om betreffendeentry in de registry geheel te verwijderen.

Het wijzigen van het toetsenbord detecterenAls we zelf, dat wil zeggen binnen het programma, een andertoetsenbord activeren, dan zijn we daar natuurlijk van op de hoogte.In bepaalde situaties echter zou het handig kunnen zijn om te kunnen

detecteren wanneer het toetsenbord van buitenaf wordt gewijzigd.Er blijken twee messages van belang:• WM_INPUTLANGCHANGE om aan te geven dat de invoertaal isgewijzigd;

• WM_INPUTLANGCHANGEREQUEST voordat de invoertaal gewij-zigd gaat worden.

Als we dat testen op een leeg TForm werkt het prima. Maar op hetmoment dat we een button, een edit of een ander control die de focuskan krijgen op het form zetten dan krijgen we deze messages nietmeer. De reden is dat deze messages terecht komen bij de compo-nent met de focus. Nu kunnen we natuurlijk in alle componenten diemessages afvangen en die dan zelf doorsturen naar het Form, maardat is niet erg handig. Een hoop werk en voor je het weet ben je erweer een vergeten. En andere manier is om te proberen de messagesaf te vangen via TApplication.OnMessage. Als we dat doen dan krijgenwe wel het REQUEST te zien, maar de echte CHANGE niet. Maareigenlijk is de REQUEST wel zo goed. Deze message komt vlak voor-dat de echte CHANGE wordt uitgevoerd. En het aardige is dat we opdat moment kunnen besluiten de CHANGE te verbieden. En als wehem wel toestaan, dan weten we ook dat er binnenkort een CHANGEplaats zal vinden!Het op deze manier niet toestaan van een wijziging blijkt nog met denodige zorgvuldigheid te moeten gebeuren. In eerste instantie had ikeen TCheckbox op het form gezet om te bepalen of er wel of niet ge-wijzigd mag worden. Het blijkt een zeer effectieve manier om te voor-komen dat je programma goed opstart! Maar op zich werkt het wel.Om het te laten zien zit in het programma de volgende verborgenoptie: als je in de TMemo links boven staat en daarin “toevallig” detekst “xxx” staat, dan kun je de taal niet veranderen met CTRL+ALT.

procedure TForm1.OnApplicationMessage(var aMsg:TMsg;var Handled: Boolean);

begincase aMsg.Message ofWM_INPUTLANGCHANGEREQUEST:beginHandled:=FMemo1.Focused AND (FMemo1.Text='xxx');

end;end;

end;

Listing 3: Wijzigen van de invoertaal verbieden

Het afvangen van de TApplication.OnMessage moet wel met enigezorgvuldigheid gebeuren. Zolang we een applicatie hebben met maaréén form die één keer de OnMessage gebruikt. is er niets aan de hand.Maar als we meerdere forms hebben die allemaal de OnMessagewillen gebruiken, moeten we op een of andere manier een ketenmaken en ervoor zorgen dat het allemaal goed blijft gaan als er eenform ergens in de keten wordt opgeruimd.Er schijnt in Delphi 2010 een CM_ INPUTLANGCHANGE opgenomente zijn die mogelijk een betere oplossing voor het afvangen van de taal-verandering is. Maar ik heb, in ieder geval op het moment van hetschrijven van dit artikel, Delphi 2010 nog niet in bezit.

Toetsenborden en EventsBinnen Delphi hebben we drie events die te maken hebben met eentoetsaanslag: OnKeyDown, OnKeyPress en OnKeyUp. De volgendetabellen laten zien wat er gebeurt als ik een “w”, “z” en “2” aantik(de parameter die we doorkrijgen wordt getoond als karakter en alsdecimale waarde).

Tabel 1: Waardes voor de toets “w”

Iets aan CTRL+C toekennen lijkt duseen minder goed idee …

00000413Dutch

0000080cBelgian French

00000419Russian

00000408Greek

FormKeyDown W(87) Z(90) W(87) W(87)FormKeyPress w(119) z(122) %(1094) &(962)FormKeyUp W(87) Z(90) W(87) W(87)

Page 70: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

MAGAZINE70

DELPHI

Tabel 2: Waardes voor de toets “z”

Tabel 3: Waardes voor de toets “2”

Om bij de laatste tabel te beginnen: het azerty toetsenbord heeftstandaard accenttekens waar wij de cijfers hebben, cijfers krijg je metSHIFT+cijfer.En nee, in de tabellen voor “w” en “z” is géén fout gemaakt. Toevalligzit de “z” op een “azerty” toetsenbord op de plaats van een “w” op het“querty” toetsenbord, en omgekeerd. Wat duidelijk wordt, is dat alswe voor een “Frans” toetsenbord kiezen Windows doet alsof er echt,via een soort Hans Klok act, een ander toetsenbord wordt gebruikt, endat voor de meer exotische toetsenborden “alleen maar” een vertalingvan de toetsaanslagen wordt gemaakt.

In eerste instantie lijkt het wellicht merkwaardig, of misschien wel fout,dat er in de OnKeyDown bij de “exoten” geen vertaling naar het echteinvoerkarakter wordt gemaakt. Maar dat valt wel mee: dit is precies dereden dat ook CTRL+C en CTRL+V gewoon blijven werken!Bovendien, ook voor ons normale toetsenbord is de code feitelijkonjuist: we krijgen immers een “W” als we op de “w” drukken!Dit maakt dus duidelijk dat je geacht wordt de KeyDown/KeyUp eventsvoor andere doeleinden te gebruiken dan het KeyPress event. Maarwat nu als je oudere code hebt, waarin het verschil minder helder was,en als je in het KeyDown event al wilt weten om welk karakter het gaat,kun je daar dan achter komen? Ja, dat kan met de Windowsprocedure “ToUnicode”. Daarbij speelt een kleine complicatie: dezeprocedure verwacht als parameter de “KeyboardState”. Dat is eenarray van 256 bytes waarin de status van het toetsenbord wordtweergegeven. Die is nodig om te bepalen of er een SHIFT is ingedruktof dat wellicht de CAPS-LOCK aanstaat, dat soort dingen. Gelukkigkunnen we de huidige status eenvoudig opvragen met de procedure“GetKeyboardState”. En zo kunnen we bij het KeyDown event alachterhalen welke toets we te pakken hebben. In het voorbeeld-programma wordt de “Poor Mans Debugger” gebruikt om hetwerkelijke karakter in de de KeyDown te tonen (in de caption van hetform dus).

ToUnicode werkt met het huidige toetsenbord. Maar wat nu als wehet effect willen weten van een toets op een ander toetsenbord. Datkun je achterhalen met de procedure “ToUnicodeEx”. Er is wel eenbeperking: het werkt alleen met een toetsenbord dat geactiveerd is.Liefhebbers kunnen dat in het voorbeeldprogramma doen door debetreffende regel in de code te activeren.

Een schermtoetsenbord-componentMet de bovenstaande kennis zijn we in staat onze eigen schermtoet-senbord-component te bouwen. Als basis gebruik ik een TPaintboxwaarop de toetsen worden getekend. Het voordeel is dat hier hettoetsenbord eenvoudig wat groter, of kleiner, geschaald kan worden.Om een toetsenbord te definiëren maak ik een lijst van toetsen methun positie in een grid en die lijst wordt dan gebruikt om hettoetsenbord netjes op het scherm te tekenen binnen de beschikbareruimte. Om niet voor iedere toets de plaats in het grid op te hoevengeven zitten er in de component allerlei procedures om het watmakkerijker te maken. Zo maak ik de regel toetsen met “querty” alsvolgt:

AddNextKey(VK_Tab,clBtnFace,6);AddNextKey(VK_Q);AddNextKey(VK_W);AddNextKey(VK_E);AddNextKey(VK_R);AddNextKey(VK_T);AddNextKey(VK_Y);AddNextKey(VK_U);AddNextKey(VK_I);

AddNextKey(VK_O);

AddNextKey(VK_P);

AddNextKey(VK_OEM_4);

AddNextKey(VK_OEM_6);

AddNextKey(VK_OEM_5,clBtnFace,6);

Listing 4: Toevoegen van de QWERTY regel op het toetsenbord

En omdat dat nog best veel code is, mag ik dat ook schrijven als

AddNextKey(VK_Tab,clBtnFace,6);

AddNextKeys([VK_Q,VK_W,VK_E,VK_R,VK_T,VK_Y,

VK_U,VK_I,VK_O,VK_P,VK_OEM_4,VK_OEM_6]);

AddNextKey(VK_OEM_5,clBtnFace,6);

Listing 5: Alternatief voor de QWERTY regel

Zoals de code laat zien gebruik ik voor de toetsen de standaard“Virtual Keys” zoals die ook terugkomen in de KeyDown en KeyUp.De VK_A t/m VK_Z zijn niet opgenomen in Delphi en die moeten weeven zelf definiëren voor we ze kunnen gebruiken. Voor de TAB-toetsgeef ik een afwijkende achtergrondkleur en breedte mee (standaard isde achtergrondkleur “clWhite” en de breedte “4”). Het uiteindelijkeresultaat is een form, met het keyboard als onderdeel van het form:

Fig. 4: Voorbeeldapplicatie met schermtoetsenbord

Om te achterhalen welke tekst we op een knop moeten zetten om deknop te krijgen, maak ik gebruik van de functie “ToUnicode”. Dezefunctie geeft voor een Virtual Key, gegeven de keyboardstate, decaption voor die Key. Het gaat echter mis bij de dode toetsen, zoalsde accenttekens. De truc is de functie twee keer achter elkaar aan teroepen. De toetsen waarvoor dit geen resultaat geeft geef ikvervolgens zelf een caption.

Als we dat willen kunnen we achterhalen wat het geïnstalleerdetoetsenbord is. Daarvoor kunnen we de functie GetKeyboardTypegebruiken. Daarmee zijn het type, subtype en aantal functietoetsen teachterhalen. De vraag is alleen of je op het scherm wilt laten zien water onder de handen zit of juist een, al dan niet te kiezen,standaardtoetsenbord. Om te laten zien dat je echt elk willekeurigtoetsenbord kan maken heb ik een toetsenbord gedefinieerd met alle

00000413Dutch

0000080cBelgian French

00000419Russian

00000408Greek

FormKeyDown 2(50) 2(50) 2(50) 2(50)FormKeyPress 2(50) é(233) 2(50) 2(50)FormKeyUp 2(50) 2(50) 2(50) 2(50)

00000413Dutch

0000080cBelgian French

00000419Russian

00000408Greek

FormKeyDown Z(90) W(87) Z(90) Z(90)FormKeyPress z(122) W(119) '(1103) ((950)FormKeyUp Z(90) W(87) Z(90) Z(90)

Page 71: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

magazine voor software development 71

DELPHI

Virtuele codes (0..255). Het ziet er als volgt uit. Dit keer als een zelf-standig form.

Fig. 5: Virtueel toetsenbord met 256 keys

Werken met het virtuele toetsenbordOm het toetsenbord zover te krijgen dat het laat zien wat de huidigetoetsen zijn, moeten we op een of andere manier een melding krijgenals er wijzigingen zijn. Zoals eerder aangegeven is het afvangen van debenodigde events problematisch. Om alle problemen voor te zijn ge-bruik ik een TTimer die iedere 0,1 seconden afvuurt. Natuurlijk zou ikiedere keer dat de timer een event genereert meteen opnieuw kun-nen tekenen, maar om al dat tekenen wat te beperken vraag ik eerstde status en de invoertaal op. Als één van die twee is gewijzigd tenopzichte van de vorige keer dan is er (mogelijk) een wijziging in de be-tekenis van de toetsen en teken ik het toetsenbord opnieuw.

Natuurlijk is het de bedoeling dat als we op ons virtuele toetsenbordergens op een toets klikken, dat er dan gedaan wordt alsof er ook opdie toets wordt gedrukt. Dat is een kwestie van een paar keer deprocedure “keybd_event” (of beter: “SendInput”) aan te roepen. In hetvoorbeeld is de code gebruikt die ook gebruikt is in het NumPad voor-beeld zoals dat op de site van CodeGear te vinden is.

Het blijkt te werken. Toch is er wel iets over op te merken. Zoalseerder aangegeven is er een mogelijkheid om van de CAPS-LOCKeen gewone SHIFTt te maken. Als je dat hebt gedaan, kun je met ditvirtuele toetsenbord alsnog de CAPS-LOCK aan en uit zetten.Een andere opmerking betreft het gebruik van de SHIFT-, CTRL- enALT-toetsen. De demo leest vanaf het toetsenbord of deze zijn inge-drukt of niet. Natuurlijk is het mogelijk de demo zodanig uit te breidendat je op een of andere manier de SHIFT op het virtuele toetsenbordingedrukt kunt houden (alsof het een CAPS-LOCK was!) en kun je diestatus vervolgens gebruiken. Dat gaat echter voorbij aan het doel vandit artikel.De oplossing zoals hier beschreven lijkt te werken. Op één uitzonde-ring na: bij de events is aangegeven dat Windows bij het instellen vaneen AZERTY toetsenbord doet alsof er echt een ander toetsenbord isaangesloten. En het gevolg is dat ons toetsenbord dat niet in de gatenheeft. Gelukkig is er een relatief eenvoudig oplossing. In plaats van devirtuele codes kan je ook gebruik maken van de Scan Codes. Dat zijnhardware codes die betrekking hebben op de locatie van de toets ophet toetsenbord. Zo heeft de “q” code 16, “w” code 17, “e” code 18,enzovoorts. Dat is natuurlijk ook precies wat Windows achter deschermen gebruikt als je een AZERTY toetsenbord instelt. Gelukkigis er een functie die Scan Codes omzet naar Virtual codes. Op diemanier is het relatief eenvoudig het toetsenbord aan te passen. Ik hebhet zo gemaakt dat je de beide codes door elkaar heen kuntgebruiken. Om ze uit elkaar te houden gebruik ik voor de Scan Code

de negatieve waarde. Bij het gebruik zet ik die negatieve waarden omnaar een Windows Virtuele Key. De procedure die we daar voor nodighebben heet MapVirtualKey. De bijbehorende parameters krijgen weniet van Borland, Codegear, Embarcadero of hoe het ook heet als udit artikel leest, maar die zijn wel te achterhalen. Wat wij nodig hebbenis de parameter “MAPVK_VSC_TO_VK” en dat is de numeriekewaarde “1”.

De aanleiding voor dit artikel was om de mogelijkheid om van invoer-taal te wisselen te laten zien. Alle methoden die hier beschreven zijnmaken, al dan niet indirect, gebruik van het toetsenbord. Een voor dehand liggende vraag is of het ook buiten het toetsenbord om kan. Metandere woorden: kan ik een Russisch schermtoetsenbord hebben engebruiken, zonder dat Russisch als invoertaal is gedefinieerd.Het beste antwoord is dat het niet kan. Wat zou er bijvoorbeeld in demessage van het KeyDown event als key moeten komen? Maar insommige gevallen kan het handig zijn om zo’n invoermogelijkheid tehebben. De component in het voorbeeld is er op voorbereid.De afhandeling van deze toetsen gebeurt door middel van een“OnInput”-event waar de applicatie een handler aan kan koppelen. Enom het helemaal algemeen toepasbaar te maken heb ik de definitievan de toets niet beperkt tot een enkel karakter. Het toevoegen van devolgende toetsenbalk behoort dus tot de mogelijkheden.

Fig. 6: Geheel alternatief toetsenbord

ConclusieIn dit artikel is een aantal aspecten van het toetsenbord beschreven.En hoewel het toetsenbord het meest standaard onderdeel is van decomputer, blijkt dat we er veel meer uit kunnen halen dan we meestaldoen. De aanleiding van dit artikel was het beschrijven hoe om te gaanmet meertalige invoer, maar de technieken kunnen ook toegepastworden voor ééntalig gebruik, met name als er regelmatig metspeciale tekens (zoals valuta tekens of wiskundige symbolen) gewerktmoet worden. Alle aanleiding dus om er toch nog maar eens naarte kijken. •

Bij de events is aangegeven datWindows bij het instellen van eenAZERTY toetsenbord doet alsof erecht een ander toetsenbord isaangesloten

Peter van der Sman

Peter van der Sman begon op demiddelbare school met programme-ren, in een tijd dat dit nog met pons-kaarten gebeurde. De introductievan de PC maakte hij mee als che-misch analist en later als statisticus.Twee werkvelden waarin de compu-ter een nuttig hulpmiddel is om degrote hoeveelheden (meet)data te

verwerken. Midden jaren ’90 besloot hij, na zijn studie informatica,zich geheel te gaan wijden aan de automatisering. Via PrismanConsultancy houdt hij zich bezig met het maken van software enconsultancy.

Page 72: SOFTWARE DEVELOPMENT NETWORKMaurice de Beijer, Anko Duizer, Paul Gielens,ChristiaanHeidema,Marcelvan Kalken,StefanKamphuis,MarcelMeijer, MirjamvanOlst,JohanParent,JoopPecht, ... van

Advertentie Microsoft