MAGAZINE - SDN · Nummer100februari2009...

72
Nummer 100 februari 2009 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network www.sdn.nl 100 IN DIT NUMMER O.A.: SnelWebsites Ontwikkelen met ASP.NET Dynamic Data < Metadata in JPG bestanden < Betrouwbare Services Bouwen met SQL Server < Tips voor Mobile Webdesign < Getting Started with Delphi DataSnap 2009 < SDN MAGAZINE EDITIE SDN MAGAZINE EDITIE 100

Transcript of MAGAZINE - SDN · Nummer100februari2009...

Page 1: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

Nummer 100 februari 2009 SDN Magazine verschijnt elk kwartaal en is een uitgave van Software Development Network

www.sdn.nl100

IN DIT NUMMER O.A.:

SnelWebsites Ontwikkelen met ASP.NET Dynamic Data <

Metadata in JPG bestanden <

Betrouwbare Services Bouwen met SQL Server <

Tips voor MobileWebdesign <

Getting Started with Delphi DataSnap 2009 <

SDN

MAGAZINE

EDITIE

SDNMAGAZINE

EDITIE

100

Page 2: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

Advertentie Macaw

Page 3: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

magazine voor software development 3

Colofon

AdverteerdersMacaw 2iAnywhere Solutions/a Sybase Company 8Microsoft 13Avanade 18Sogeti 22Barnsten/Embarcadero 26Bergler Nederland b.v. 35Aladdin 474DotNet b.v. 57MI Consultancy BV 57SIRA Holding BV 61Twice-IT 66Sybase iAnywhere / Elmo ICT Systems71Bridge Incubation Group b.v. 72

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

Uitgave:Software Development NetworkPostbus 506 7100 AM [email protected] www.sdn.nltel. 0543 518 058 fax 0543 515 399Achtiende jaargangNo. 100 • februari 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, Mark Blomsma, RolfCraenen, Marcel van Kalken, Stefan Kamp-huis, Marcel Meijer, Johan Parent, JoopPecht, Maarten van Stam, Bob Swart, Louisvd Tol, Sandra de Ridder, Marianne vanWanrooij, Rob Willemsen en natuurlijk alleauteurs!

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.

Voor u ligt het 100e nummer van ons magazine, een bijzondere mijlpaal in de historie van deSDN-community. Toen ik in 1995 toetrad tot het SDGN, zoals het toen nog heette, alsredactielid heb ik niet kunnen vermoeden dat ik nu als voorzitter een column zou schrijven voornummer 100 voor ons blad.

Zodra een nieuw nummer op de mat valt, trek ik het cellofaan eraf, blader het initieel sneldoor en selecteer de artikelen die ik op een ander, rustiger tijdstip voornemens ben te lezen.Dit scenario zal voor velen van jullie waarschijnlijk herkenbaar zijn. Soms is het rustigertijdstip niet eens in dezelfde week (of maand), en toch lees ik de geselecteerde artikelen openig moment.De SDN Events en SDN Conference zoals we ze tegenwoordig noemen zijn net als het ma-gazine door de jaren heen veranderd qua aanbod (networks/secties/tracks/…). De kwaliteitis echter door de jaren heen hoog gebleven en die garantie geven wij u ook voor de toe-komst.

Wat ooit begon als CDGN (Clipper Developer Group Netherlands) is via SDGN (SoftwareDeveloper Group Netherlands) geëvolueerd naar SDN (Software Development Network). Dezediverse namen symboliseren ieder ook een periode in de afgelopen 19 jaar.CDGN speelde in de tijd waarin met name de xBase-talen als Clipper, dBase en FoxPropopulair waren. Met de intrede van Delphi, Office Development en Visual Basic is CDGNomgedoopt tot SDGN. Onder die vlag hebben we diverse secties opgetuigd, waaronder eenInternet-sectie. Ja, je leest het goed … een Internet-sectie. Sommige van deze secties zijninmiddels weer afgevoerd – de Internet-sectie b.v. - of opgegaan in andere, maar Delphi b.v.is nog steeds een op zichzelf staande track.

De huidige naam SDN is gebaseerd op de gedachte dat de talenoorlog (‘mijn taal is lekkerbeter dan de jouwe’) geluwd is en strominglobbyisten (Java vs .Net) een staakt-het-vurenhebben afgesproken. Het landschap verandert door de steeds verder oprukkende interoptussen systemen, talen en platformen. En er zijn producten ontstaan die als basis dienen vooroplossingen, zoals SharePoint en CRM maar ook nieuwe initiatieven als Cloud Computing &Storage en DSL (Domain Specific Languages). Dit alles bij elkaar heeft in onze beleving defocus verlegd van puur taalgeoriënteerd naar development in bredere zin.

Al deze ontwikkelingen hebben ook hun effect op het dagelijks werk van de moderneontwikkelaar, en daarom ook op de wijze waarop wij als SDN ons aanbod afstemmen op decommunity. In 2009 en uiteraard ook de daarop volgende jaren zullen wij ons aanbod blijvenactualiseren aan de werkelijkheid van het moment.De kans dat ik voor nummer 200 weer het toetsenbord zal hanteren om een column teschrijven lijkt me niet heel groot. Tegen die tijd wordt er wellicht zelfs gelachen om hetfenomeen toetsenbord, wie zal het zeggen…

Ik wens je veel leesplezier, nu en de komende jaren, en hoop je te mogen verwelkomen opeen van de evenementen in 2009, 2010, ...

Remi Caron,voorzitter SDN •

Nummer 100...

Page 4: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

SDN EVENT

inclusief ALV30 maart 2009De Bergse Bossen,Driebergen

Inhoud03 Voorwoord: nummer 100Remy Caron

04 Inhoudsopgave

05 Snel Websites Ontwikkelen metASP.NET Dynamic Data

Klaas Depenbrock

09 Metadata in JPG bestandenPeter van der Sman

14 Rapporteren in de 21e EeuwDennis Vroegop

19 Train of Thought: Confessions of aConference Speaker

Cary Jensen

23 ASP.NET onder de Motorkap:Heeft ASP.NET nog Toekomst?

Michiel van Otegem

24 Tips voor Mobile WebdesignSandra de Ridder

27 Betrouwbare Services Bouwen metSQL Server

Frans van der Geer en Andre van Leeuwen

36 SDN: nummer 100Ernst Peter Tamminga,Ton Hofstede,Ad van de Lisdonk, Mark Blomsma en Remi Caron

38 Fun met WebParts in ASP.NetBert Dingemans

43 Interesting Things: Why Newton was Agileand the Titanic was Not

Sander Hoogendoorn

44 Keystroke Combinationsin Delphi's code Editor

Cary Jensen

46 Smartmem, Zo Smart Als de Naam Zegt?Maurice de Beijer

47 Agenda

48 ASP.NET WebapplicatiesEindelijk Unit-Testbaar

Henry Cordes

52 IBM Rational Business Developer withEnterprise Generation Language -Java zonder Java

Ulf Büchner

58 LINQ to SQL and DotNetNuke:A Perfect Fit for Rapid Development

Brandon Haynes

62 How Aspects MakeMultithreaded WPF Easier

Gael Fraiteur

67 Getting Started with Delphi DataSnap 2009Pawel Glowacki

Page 5: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

magazine voor software development 5

.NETASP

Als je de Dynamic Data Website Wizard template hebt gekozen, dancreëert Visual Studio een project met daarin een folder ”Dynamic Data”en een aantal subfolders. Figuur 2 toont de initiële solution structuurvan een Dynamic Data website.

Fig. 2: Dynamic Data project structuur

Een aantal van deze folders bevatten de templates en controls diegebruikt worden bij het genereren van de website. De volgende tabelbeschrijft de structuur van de folder “DynamicData”.

Tabel 1: Folders in een Dynamic Data project

Naast de folder “DynamicData” creëert Visual Studio ook nog enkeleandere bestanden voor een Dynamic Data Website; dit zijn:• Web.Config; het configuratiebestand met o.a verwijzingen naarDynamicData assemblies

• Default.aspx; in dit bestand wordt het menu opgebouwd voor hetinitieel tonen van de lijst met tabellen uit het datamodel

• Global.asax; in dit bestand worden bij het Application_Start event deroutes gedefinieerd

• Site.css; de stylesheet voor de gegenereerde website• Site.Master; de masterpage voor de gegenereerde website metdaarin een contentplaceholder waarin de gegenereerde pagina’sworden getoond.

Klaas Depenbrock

Snel Websites Ontwikkelen met

ASP.NET Dynamic Data

InfrastructuurAls je een Dynamic Data website wilt gaan ontwikkelen, dan start jedoor een specifieke template te kiezen, zie figuur 1.

Fig. 1: Visual Studio project templates

Met de oplevering van ASP.NET 3.5 SP1 is hetDynamic Data framework beschikbaar geko-men voor de webontwikkelaar. Dynamic Datais een framework voor het snel ontwikkelen vandata-driven websites. Op basis van een data-model wordt runtime een website gegene-reerd. Het opmerkelijke hierbij is, dat hetframework gebruik maakt van zogenaamdetemplates voor het tonen en muteren van web-pagina’s. Deze templates kunnen aangepastworden aan de eigen eisen en wensen. HetDynamic Data framework is nog volop in ont-wikkeling; regelmatig wordt op Codeplex eennieuwe update vrijgegeven met daarin nieuweof verbeterde functionaliteit.In dit artikel ga ik in op hoe het Dynamic Dataframework is opgebouwd, zodat we een beterinzicht krijgen in de werking van dit nieuweframework.

Het Dynamic Data framework is nogvolop in ontwikkeling

Map Omschrijving

Content Deze folder bevat de controls en images die gebruiktworden voor het genereren van de webpagina’s

CustomPages Dit is een lege folder, in deze folder worden de templatesgeplaatst die de pageTemplates vervangen voor bepaaldetabellen.

FieldTemplates Deze folder bevat de templates voor het tonen en mute-ren van data types.

PageTemplates Deze folder bevat de templates voor het tonen en mute-ren van pagina’s.

.

Page 6: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

Naast deze bestanden bevat de folder “DynamicData” ook eenaantal subfolders. Deze subfolders bevatten de templates voor hetgenereren van pagina’s en controls.

Page templatesDynamic Data kent twee verschillende type templates; page templa-tes en field templates. Page templates zijn gewone ASPX pagina’s metdaarin voorzieningen om Dynamic Data te ondersteunen. Er wordenvijf page templates gedefinieerd:• List.aspx• Details.aspx• ListDetails.aspx• Insert.aspx• Edit.aspx

In iedere template is een DynamicDataManager klasse gedefinieerd;deze is verplicht om Dynamic Data ondersteuning mogelijk te makenin het .NET framework. Deze klasse wordt in het Page_Init event vande template geinitialiseerd.

<%@ Page Language="C#" MasterPageFile="~/Site.master"

CodeFile="List.aspx.cs" Inherits="List" %>

<%@ Register src="~/DynamicData/Content/GridViewPager.ascx"

tagname="GridViewPager" tagprefix="asp" %>

<%@ Register src="~/DynamicData/Content/FilterUserControl.ascx"

tagname="DynamicFilter" tagprefix="asp" %>

<asp:Content ID="Content1"

ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">

<asp:DynamicDataManager ID="DynamicDataManager1"

runat="server" AutoLoadForeignKeys="true" />

……

<asp:DynamicValidator runat="server" ID="GridViewValidator"

ControlToValidate="GridView1" Display="None" />

Listing 1: Fragmenten uit een page template met DynamicData-Controls

In listing 1 is een fragment uit de template “List.aspx” te zien. Erworden onder andere twee controls geregistreerd uit de “Dynamic-Data/Content” folder. Vervolgens wordt ook de DynamicDataManagergeïnitialiseerd. Daarnaast zijn er enkele specifieke controls die gebruiktkunnen worden bij het ontwerpen van ASP pagina’s; dit zijn onderandere een validator control (DynamicValidator) en een filter control(DynamicFilter). Voor de rest kan een template ontworpen worden metde bestaande ASP.NET controls.

Door het aanpassen van de templates aan je eigen wensen is hetmogelijk om de website volledig te customizen. Er zijn twee manierenom een Dynamic Data Website te customizen. Ten eerste door depage templates zelf aan te passen. Je kunt dit doen door in de folder“DynamicData\PageTemplates” één van de vijf templates te wijzigen.Alle wijzigingen die in de page templates gedaan worden gelden voorde gehele website.

Daarnaast kunnen de templates aangepast worden voor eenspecifieke tabel. Dit doe je door in de folder “DynamicDate\Custom-Pages” een subfolder te maken met de tabelnaam van de klassewaarvoor deze specifieke template gebruikt moet worden. Figuur 3verduidelijkt dit:

6 MAGAZINE

Fig. 3: Custom pages

In bovenstaande situatie geldt dat voor de customers tabel eenlokale template gebruikt wordt om een klant (customer) te muteren,namelijk de Edit.aspx template in de folder “CustomPages\Custo-mers”. Voor alle andere tabellen wordt de Edit.aspx template uit defolder “PageTemplates” gebruikt.

Field templatesNaast page templates kent Dynamic Data ook field templates; eenfield template verzorgt de mapping tussen de data op het scherm endiezelfde data in het datamodel. Een field template overerft zijn ge-drag van de klasse “System.Web.DynamicData.FieldTemplateUser-Control”. Deze klasse zorgt voor de toegang tot de informatie in hetdatamodel. De bestaande field templates kunnen aangepast worden,maar je kunt ook zelf field templates ontwikkelen.Dynamic Data kent een aantal standaard field templates. Dit zijntemplates voor het tonen en/of muteren van booleans, één op veelrelaties, foreign key relaties, datums en numerieke waarden. Als je eenbestaande field template wijzigt, dan geldt deze wijziging voor degehele website. Wil je dit niet, dan is het alternatief om een nieuwefield template te creëren.

Een nieuwe field template kan op verschillende manieren gebruiktworden binnen een Dynamic Data website. Allereerst kan de fieldtemplate gebruikt worden om b.v. in een page template in eengridview een kolom te tonen. De “DynamicData” control heeft eenproperty “UIHint” waarin de naam van de field template ingevuld wordt.Listing 2 toont dit.

<asp:DynamicControl runat= "server" DataField="Phone"

UIHint="ShowPhone" />

Listing 2: UIHint property van DynamicControl

Daarnaast is het ook mogelijk om met de attribuutklasse UIHint in hetdatamodel voor bepaalde properties aan te geven hoe deze getoondmoeten worden. Dit wordt in listing 3 verder uitgewerkt.

Templates aanpassen om je website tecustomizen

Een field template laat je een dataveldcustomizen

.NETASP

Page 7: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

using System.Web.DynamicData;

using System.ComponentModel.DataAnnotations;

/// <summary>

/// Summary description for Customer

/// </summary>

[MetadataType(typeof(CustomerMetadata))]

public partial class Customer

{}

public class CustomerMetadata

{

[UIHint("ShowPhone")]

public object Phone;

}

Listing 3: UIHintAttribuut in datamodel

Het voordeel van listing 3 is dat de field template “ShowPhone”gebruikt wordt in alle schermen waar “Phone” getoond moet worden,dit in tegenstelling tot het voorbeeld in listing 2. Hier zal de betreffendetemplate het attribuut “Phone” met deze UIHint tonen.

Data sourcesWe hebben nu een idee hoe Dynamic Data een website genereert,maar om echt een website te genereren hebben we een datasourcenodig. In ons voorbeeld doen we dit met een Linq to SQL datasource,maar Linq to Entities werkt ook. Om een Linq to SQL datasource tekoppelen aan Dynamic Data, voeren we de volgende stappen uit:1. Creëer een folder App_Code2. Voeg een nieuw “Linq to SQL classes”-item toe aan deze folder3. Noem dit item NorthWind.dbml4. Dubbelklik op NorthWind.dbml5. Dubbelklik op Server Explorer6. Selecteer een database en sleep de tabellen naar

NorthWind.dbml

Als we dit gedaan hebben, dan ziet de folder “App_Code” er uit als infiguur 4:

Fig. 4: NorthWind Datasource

Het enige wat we nu moeten doen is deze datasource koppelen aanDynamic Data. Dit doen we op de door het bestand “DynamicData.cs”voor een aantal regels de commentaartekens te verwijderen.

public static void RegisterRoutes(RouteCollection routes) {

MetaModel model = new MetaModel();

// IMPORTANT: DATA MODEL REGISTRATION

// Uncomment this line to register LINQ to SQL classes

// or an ADO.NET Entity Data model for ASP.NET Dynamic Data.

// Set ScaffoldAllTables = true only if you are sure

// that you want all tables in the data model to support

// a scaffold (i.e. templates) view.

// To control scaffolding for individual tables,

// create a partial class for

// the table and apply the [Scaffold(true)] attribute

// to the partial class.

// Note: Make sure that you change "YourDataContextType"

// to the name of the data context

// class in your application.

model.RegisterContext(typeof(NorthWindDataContext),

new ContextConfiguration()

{ ScaffoldAllTables = true });

Listing 4: Registreren NorthWindDataContext in DynamicData.cs

De laatste regel in listing 4 geeft aan dat we de “NorthWindDataContext” registreren bij DynamicData. Dit is alles we moeten doen; wekunnen nu het project compileren en runnen.

RoutingHet allereerste wat opvalt als je de website opstart die met DynamicData gegenereerd is, is dat het lijkt alsof het framework gebruik maaktvan ASP.NET pagina’s bij het tonen van deze website. Als je naar figuur5 kijkt, zie je de volgende URL:

http://localhost:52620/WebSite3/Orders/ListDetails.aspx.

Fig. 5: Dynamic Data URL

Hierboven heb ik aangegeven, dat het Dynamic Data framework eenwebsite genereert op basis van templates. De navigatie tussen deverschillende pagina’s in deze website gebeurt op basis vanzogenaamde routes. Deze routes worden in het project gedefinieerd.Zo’n route stelt ons in staat om url’s te definiëren die niet direct aan eenspecifiek bestand op het file systeem gerelateerd zijn. Als de url aaneen bepaalde routedefinitie voldoet, dan wordt hier een actie opondernomen. Voldoet de url niet aan een routedefinitie, dan wordtaangenomen dat de url naar een bepaald bestand refereert, bijvoor-beeld een .aspx pagina. Hieruit volgt dat Dynamic Data ook teintegreren is met een ‘gewone’ ASP.Net website. Een routedefinitiebestaat uit paramaters die gescheiden worden door een “/”. Zo’nroutedefinitie kan er als volgt uitzien:

{parameter1}/{parameter2}/{parameter3}

magazine voor software development 7

Routering is ook dynamisch

.NETASP

Page 8: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

Hierbij zijn parameter1, parameter2 en parameter3 zogenaamdeurl-parameters; deze url-parameters moeten altijd tussen “{“ en “}”staan om ze herkenbaar te maken voor het framework. Als de urlgeparsed wordt, dan worden de parameters geëvalueerd. Alle karak-ters in de url-string die ongelijk zijn aan het “/” -teken en niet tussen “{“en “}” staan, worden als constanten gezien en als zodanig geëvalu-eerd. Het is mogelijk om tussen twee scheidingstekens meerdere url-parameters te plaatsen. Deze moeten dan wel gescheiden zijn dooreen constante. Onderstaande tabel geeft enkele voorbeelden vanroute definities met bijbehorende voorbeelden.

Tabel 2: Route definities

In het eerste voorbeeld wordt waarschijnlijk een lijst met customersgetoond. In het tweede voorbeeld wordt waarschijnlijk customer metid=10 getoond. Deze routes worden vooraf gedefinieerd. Bij DynamicData wordt in het event Application_Start in de global.asax eenfunctie aangeroepen die de routes definieert. In de templates is defunctionaliteit ingevuld hoe er genavigeerd wordt, Dynamic Data vali-deert deze navigatie met de gedefinieerde routes en zorgt ervoor datde betreffende pagina gegenereerd wordt. Routing is niet specifiekvoor Dynamic Data. Ook het MVC framework maakt gebruik van rou-ting. Uit de namespace van routing (“System.Web.Routing”) volgt datrouting ook in een ‘normale’ ASP.NET website gebruikt kan worden.

ConclusieIn dit artikel heb ik meer inzicht gegeven in het Dynamic Data frame-work; ik heb de structuur besproken van een Dynamic Data project.Daarnaast heb ik de page en de field templates beschreven en

Klaas Depenbrock

Klaas Depenbrock werkt bij Capge-mini als software architect en houdtzich bezig met custom softwaredevelopment.Zijn interesse gaat uit naar nieuweMicrosoft technologieën en de inte-gratie van deze technologieën metde verschillende Microsoft produc-ten.

Route Definitie Voorbeeld

{table}/list.aspx /customer/list.aspx

{controller}/{action}/{id} /customer/Show/10

tenslotte de manier van navigeren tussen de gegenereerde web-pagina’s.

Niet alleen templates kunnen we aanpassen aan onze eisen en wen-sen,we kunnen de gehele website customizen naar onze eigen in-zichten. Dit maakt Dynamic Data een krachtig framework voor hetgenereren van data-driven websites. Zoals we gezien hebben is hetmogelijk om zonder zelf een regel code schrijven een website tegenereren. Het enige wat we gedaan hebben is een datamodeldefiniëren.Toepassingen waar Dynamic Data geschikt voor is, zijn bijvoorbeeldprototyping en het onderhouden van stamgegevens. Of DynamicData een concurrent voor bestaande generator tools wordt, is nog niethelemaal duidelijk. Wat natuurlijk in het voordeel van Microsoft spreektis, dat alle nieuwe functionaliteit direct met elkaar integreert. Zokan Dynamic Data gecombineerd worden met het door Microsoftontwikkelde MVC framework. Daarnaast wordt er nog volop aanDynamic Data gesleuteld en worden er regelmatig nieuwe updatesgereleased. •

.NETASP

Advertentie Sybase iAnywhere

Page 9: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

magazine voor software development 9

DELPHI Peter van der Sman

Metadata in JPG bestandenOmmijn foto’s, en vooral dia’s, te archiveren maakte ik tot nu toe allerlei lijstjes waarin ikbeschreef waar en wanneer de foto/dia was gemaakt en - vooral ;-) - wat het voor-stelde. Niet altijd het meest leuke werk maar wel nuttig. Eerst gewoon op papier en sinds1986 in bestandjes op de computer. Maar ja, hoe gaat dat? Zoek dat bestandje uit 1986maar weer eens op. En als je het dan gevonden hebt - dat lukt mij meestal nog wel -,kan je het dan nog wel lezen? Goede kans van niet! En als het wel lukt, dan zit je nogmet het probleem hoe de juiste dia aan de info uit het bestand te koppelen. Of andersom:waar zijn toch mijn oude dia’s van Delphi (die plaats in Griekenland) gebleven?

In de huidige tijd van digitale fotografie kunnen we het probleem vandie koppeling een stuk vereenvoudigen. We kunnen de informatiedirect aan de foto koppelen, en veel van de informatie krijgen we algratis mee. Bij de opname wordt al veel informatie aan het bestandgekoppeld en die kunnen we uitlezen en zelfs wijzigen.Daarbij gaat het dan met name om opname’s die als JPEG (=“JointPhotographic Experts Group”) worden opgeslagen. In de meestegevallen is dat voor ons, amateurs, goed genoeg.

En natuurlijk willen we de applicatie in Delphi 2009 kunnen latendraaien en willen we in staat zijn om echte Unicode teksten toe tevoegen.

De opbouw van JPEG bestandenEen JPEG bestand is opgebouwd uit een aantal segmenten. Iedersegment bevat een blok data. Schematisch ziet het er als volgt uit:

$FF$D8 //beginmarker (SOI: Start of Image)

$FF$xx$yyyy //specificatie segment 1 met ID $xx

. . . . . //data segment 1 ($yyyy -2 bytes)

$FF$xx$yyyy //specificatie segment 2 ID $xx

. . . . . //data segment 2 ($yyyy -2 bytes)

$FF$xx$yyyy //specificatie segment n ID $xx

. . . . . //data segment n ($yyyy -2 bytes)

$FF$D9 //endmarker (EOI: End of Image)

Het lezen van een bestand komt er dus op neer de segmenten stukvoor stuk te lezen en de voor ons interessante gegevens eruit te halen.In het kader van dit artikel zijn we vooral geïnteresseerd in de metadataen die is over het algemeen ergens vooraan in het bestand opgesla-gen, dat wil zeggen in de eerste segmenten. Dat betekent dat we inde praktijk maar een paar segmenten hoeven te lezen en de informa-tie over het plaatje zelf volledig kunnen negeren. Overigens volgt uitde specificatie dat er heel goed geldige JPEG bestanden kunnenbestaan zonder een grafische inhoud!

Bij het lezen van de segmenten zijn er een paar details die in de gatengehouden moeten worden:• Het eerste byte van het segment moet $FF (karakter 255) zijn. Alswe iets anders tegenkomen dan zitten we in de problemen. Vanafdat punt moeten we de data ongemoeid laten (feitelijk is hetbestand dan ongeldig).

• Het derde en vierde byte van het segment bevatten de omvang vanhet segment. En die omvang is inclusief deze twee bytes, maar ex-clusief de specificatie. Daarnaast is de byteorder anders dan wegewend zijn. Als we deze twee bytes in een “Word” inlezen, moetde bytevolgorde even omgekeerd worden, bijvoorbeeld door een“swap” aan te roepen.Uit het feit dat de omvang in twee bytes wordt opgeslagen volgtoverigens direct dat een segment nooit meer dan 65536 bytes kanbevatten.

Het inlezen van de metadata komt er dus eigenlijk op neer de data-segmenten in een loop te doorlopen en de bijbehorende data te de-coderen. Rest de vraag welke data dat is en hoe die te decoderen. Erzijn verschillende kandidaten. In dit artikel komen er twee aan bod:EXIF en IPTC.

Een basisimplementatieUit de bovenstaande tekst zou wellicht de suggestie kunnen zijn ont-staan dat het lezen van JPEG bestanden tamelijk triviaal is, maar datis het toch niet. Zoals dat wel vaker gaat, kom je er meestal laterachter dat de zaken die makkelijk lijken lastig blijken (andersom komtook wel voor maar toch niet zo vaak).Daarom is het meestal wel verstandig om als je met dit soort zaken be-gint eens rond te struinen op internet om te kijken wat anderen al voorje bedacht hebben. Daar is wel het een en ander te vinden, het enestukje info beter dan het andere. Maar ik heb geen info gevonden dieén in Delphi werkt én om kan gaan met Unicode, en dus ook niet metDelphi 2009. En ik zal het maar toegeven: ik had eerst eenimplementatie die zeer veelbelovend leek. Pas toen ik op eengegeven moment helemaal vastliep, en dus wist waar een specifiekprobleem zat en waarop ik verder moest zoeken, kwam ik terecht op

We kunnen de informatie direct aande foto koppelen, en veel van deinformatie krijgen we al gratis mee

Het inlezen van de metadata komter dus eigenlijk op neer de data-segmenten in een loop te doorlopenen de bijbehorende data te decoderen

Page 10: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

de website van Gerry McGuire (http://mcguirez.homestead.com). Dieheeft, al weer lang geleden, een implementatie gemaakt die wekunnen gebruiken als uitgangspunt.Die implementatie heeft echter één groot probleem als we hem willengebruiken in Delphi 2009: als basis voor de dataopslag is gebruikgemaakt van strings en chars. En daar zit nu net het probleem:karakters zijn in Delphi 2009 geherdefinieerd van 1 byte naar 2 bytes.Om de boel in eerste instantie aan de praat te krijgen moest ik van allestrings een AnsiString maken en van alle Chars een AnsiChar. Na nogwat kleinere aanpassingen draait het dan gewoon onderDelphi 2009. Dat is een truc die wel vaker werkt als je snel een oudeapplicatie wilt compileren onder Delphi 2009, maar het is natuurlijk nietwat je eigenlijk wilt. Het levert in ieder geval een spectaculair aantalcompiler warnings op.Je kunt het allemaal wel kloppend krijgen, inclusief het lezen enschrijven van Unicode teksten, maar fraai is het allemaal niet.Met dit als uitgangspunt heb ik dit artikel geschreven. Een deel vande code heb ik inmiddels al herschreven en tegen de tijd dat je ditleest, zal de download waarschijnlijk (bijna) geheel geconverteerd zijnnaar echte Delphi 2009 code.

EXIF tagsEXIF staat voor “EXchangeble Imagefile Format for digital still came-ras”. De oudste versie die ik heb kunnen achterhalen is versie 2.1 uit1998, en de nieuwste is versie 2.2 uit 2002. De informatie is allemaalte vinden in PDF bestanden op www.Exif.org. Het komt allemaal uitJapan en dat kunnen we merken aan de PDF’s. Die zijn weliswaar inhet Engels, maar kennelijk is er af en toe toch nog een Japans karak-ter blijven hangen. En Acrobat Reader geeft de betreffende pagina’s,in ieder geval op mijn computer, niet weer. Het zal wel zijn omdat iktoevallig de Japanse karaktersets niet heb geïnstalleerd, maar datgebeurt dan natuurlijk net op de pagina die je nodig hebt. Gelukkig iser dan nog internet. Google levert zo’n 70 miljoen hits op de zoekterm“exif”, dus nadere specificatie van wat je zoekt is wel zinvol.

Het segmentID voor de EXIF tag is $D8 (225). De tag heeft een heuseheader die er als volgt uit ziet:

type

TEXIFheader= packed record

Marker : word; //$FF$D8

Size : word; //Total segment size -2

ID : array[0..3] of AnsiChar; //'Exif'

NULL : AnsiChar; //#0

Padding : byte //#0

end;

Dit is dus inclusief de algemene segment header zoals hiervoorbeschreven, en met een size waarvan we de bytes moeten omdraaienen die begint te tellen bij zichzelf.Ik ben overigens geen implementaties tegengekomen die bij het lezendaadwerkelijk controleren of het ID ook echt op “Exif” gesteld is, maarbij het schrijven moet je de header natuurlijk wel netjes in orde maken.Als we de header hebben gelezen kunnen we beginnen met hetdecoderen van het segment.

De EXIF tag decoderenDe inhoud van een EXIF tag ziet er een beetje uit als een eenvoudigeharde schijf. Het komt er op neer dat er een “data directory” is, eentabel met data-ingangen, en een blok met “echte” data.

Het is allemaal opgebouwd volgens de TIFF specificatie. En dusbeginnen we met het lezen van een 8-byte TIFF-header:

type

TTIFFHeader = packed record

ByteOrder : Word;

i42 : Word;

Offset : Cardinal;

end;

De “ByteOrder” geeft aan hoe de gegevens zijn geschreven. Er zijntwee opties:• $4949 (‘II’) -little endian• $4D4D (‘MM’)-big endianDe veld i42 heeft geen andere betekenis dan dat het de waarde van42 moet bevatten.De offset geeft aan waar de data begint. Meestal zal dit veld de waarde“8” bevatten: de data begint dan direct na de header.

En vervolgens wordt de data gelezen. In eerste instantie ziet dat ereenvoudig uit. De data bestaat uit een aantal 10-byte records met devolgende structuur:

type

TIfdTag = packed record

ID : Word; //Tag number

Typ : Word; //Type tag

count : Cardinal; //Aantal elementen

Offset : Cardinal; //Offset

end;

Het ID geeft aan over welke informatie we het hebben. Zo geeft, alsvoorbeeld, de waarde 256 aan dat we het over de “ImageWidth”hebben.Het “Typ” geeft aan over wat voor type data we het hebben: is het eentekst, een byte, een word, een integer of wat dan ook. Er is eenaantal typen mogelijk (zie hieronder).De “count” geeft aan hoeveel gegevens er zijn opgenomen. Dat kanbijvoorbeeld het aantal karakters van de tekst zijn, maar er zijn ookgegevens die uit een reeks van getallen bestaan. En count bevat hetaantal elementen, en niet het aantal bytes. Een count van 10 betekentvoor een tekstveld dus 10 bytes (de basis is een 1 byte char), vooreen integerveld zijn het er 40.De “Offset” kan twee dingen betekenen: als de gegevens bij elkaarniet groter dan 4 bytes lang zijn, dan worden deze gegevens direct inhet veld “Offset” geschreven, en anders is het een verwijzing naar waarhet dan wel staat.

Wat het ingewikkeld maakt is dat sommige ID’s weer verwijzen naareen “nieuwe directory”. En dat betekent dat op de locatie van “offset”moet worden begonnen deze directory uit te lezen. Welke ID’s dat zijnvolgt uit de specificatie van EXIF2.2.En dan is er nog informatie die wijst naar data met een specifiekeopmaak. Het is een kwestie van de documentatie goed bestuderen ende juiste codes gebruiken. Het is allemaal geregeld in de download. Endan weet je ook waar je makkelijk vast kan lopen.

Unicode tekstenOm te laten zien dat we een Unicode tekst kunnen schrijven heb ikals voorbeeld een foto van Delphi genomen en daar de tekst Delphiaan toegevoegd. En om er een echt Unicode voorbeeld van te makendoe ik dat op zijn Grieks, dus “Δελφοἰ”. Moeten we alleen nog eenplekje vinden om die tekst kwijt te raken. Het standaard veld “User-Comment” is een geschikte kandidaat. Dit is een karakter veld. Deeerste acht karakters geven de codering aan. Voor ons zijn de vol-gende twee van belang:

10 MAGAZINE

Google levert zo’n 70 miljoen hits op dezoekterm “exif”, dus nadere specificatievan wat je zoekt is wel zinvol

DELPHI

Page 11: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

ASCII#0#0#0 + ASCII-tekst + #0

UNICODE#0 + Unicode-tekst + #0#0

Gewoon uitschrijven wat je wilt dus! Verder bestaan nog de Japansekarakterset en “ongedefinieerd”, gewoon 8 maal #0.

Een potentieel probleem is dat bij ASCII niet is gespecificeerd metwelke codepage is geschreven. Natuurlijk word je wel geacht met eenstandaard codepage te schrijven maar in de praktijk gebeurt dat dusniet (altijd). Bij het schrijven van de tekst is het een kwestie van kijkenof we Unicode nodig hebben. De juiste bytestring kunnen we met debetreffende TEncoding genereren. In de implementatie gebruik ik voorschrijven de standaardcodering. Bij het lezen kan gekozen wordenmet welke TEncoding de data gelezen moet worden. Voor meerdetails wordt verwezen naar de download.

De EXIF-tag wijzigenBehalve de “UserComment” kunnen we natuurlijk ook alle anderemetadata uit de EXIF tag wijzigen. Ik kan je echter aanraden dat alleente doen als je ook daadwerkelijk weet wat en waarom. Als voorbeeld:ik was eens in een programma tegengekomen dat je JPG foto’s“lossless” kon roteren. Een handige optie! Dus toen ik in de EXIFdocumentatie een optie “Orientation” zag dacht ik “HA!”. Mis dus. Jekunt aan dit veld wijzigen wat je wilt, je foto zal er niet van gaan draaien.En toen ik het maar eens met dat programma deed om te controlerenwat er gebeurde, bleek er nog veel meer te wijzingen. Zo worden develden “hoogte” en “breedte” omgewisseld, om maar iets voor dehand liggends te noemen.Wat verder ook opvalt in de documentatie is dat veel tekstveldenexpliciet in ASCII worden geschreven. Het veld “UserComment” is hetenige waarbij over Unicode wordt gesproken. Ik ben in ieder gevalgeen andere tegengekomen.

Nu kunnen we natuurlijk op eigen gezag velden toevoegen en dezebehandelen alsof het een “UserComment” is. Als we maar nietgebruikte codes gebruiken zal het voor onze eigen bestanden nog welgoed gaan. Alleen weet je natuurlijk nooit zeker of een code echtongebruikt is, en blijft. Dus misschien is het toch niet zo’n heel goedeoplossing.Standaardvelden met niet ASCII volschrijven kan natuurlijk ook, maaris niet handig als de informatie ook nog in andere programmatuur lees-baar moet zijn.

De IPTC-tagIn Photoshop krijg je, als je de metagegevens opvraagt, een aantalvelden te zien die meer aansluiten bij de wens om gegevens over delocatie waar de foto is genomen te bewaren. Zo zien we velden als“Omschrijving”, “Plaats” en “Land”. Het blijkt allemaal in het bestandterecht te komen als “IPTC”. IPTC staat voor “International PressTelecommunications Council”. We kunnen ze terugvinden opwww.iptc.org. Daar blijkt dat ze veel meer doen dan alleen maarmetadata voor foto’s specificeren.De data van het IPTC segment is relatief simpel. Het is een aantalrecords met de volgende opbouw:

Marker 1 byte - $1c

Groep 1 byte - de “groep” van het ID, meestal 2

ID 1 byte

Size 2 byte - een geswapt word

Data x - een aantal karakters (size-4)

Om het segment te lezen moeten we zoeken naar een marker ($1c,

ASCII 28), en vervolgens lezen we de bijbehorende data uit. Dan gaanwe naar de volgende, enz. De gedachte achter Groep is verschillendegroepen van gegevens te kunnen specificeren. De combinatie vanGroep en ID bepaalt dan over welke informatie we het hebben. Helaasis er geen handig overzicht beschikbaar van alle groepen en bijbeho-rende ID’s. Als je wat verder gaat zoeken kom je al snel tegenstrijdigeinformatie tegen.Ik ga dus maar uit van een stukje “reversed engineering”: ik kijkgewoon hoe de gegevens die ik in Photoshop invoer in het bestandterecht zijn gekomen en dan weet ik wat het betreffende ID en groepzijn. Meestal, altijd eigenlijk, hebben we te maken met informatie ingroep 2. In de download zijn de mij bekende velden opgenomen.Desgewenst kun je daar eenvoudig nieuwe informatie aan toevoegen.Officieel is de inhoud van de velden dan ook nog weer gebonden aanallerlei afspraken wat betreft lengte en opmaak (denk maar eens aanvelden met “datum” en “tijd”), maar het lijkt erop dat we in de praktijkredelijk vrij zijn om te schrijven wat we willen.

In de praktijk is het segment bijna altijd geschreven door Photoshop,en die voegt een header en footer toe aan het segment. Het ziet er alsvolgt uit:

Header 'Photoshop 3.0'#0'8BIM'#4#4#0#0#0#0

Data ……

Footer '8BIM'#$04#$0B#0#0#0#0#0#0

Dat zijn nog eens headers! Bij het schrijven van het segment is hetnatuurlijk wel handig die header en footer mee te schrijven, dan kanPhotoshop onze gegevens tenminste ook lezen! Naast deze header enfooter verwacht Photoshop ook een tag met een versiespecificatie.Het wordt allemaal voor je geregeld in de download.

IPTC en karaktersetsDe definitie van de IPTC voorziet in het specificeren van een karakter-set. Meestal wordt dat echter achterwege gelaten. En dan komt hetneer op raden hoe het is geschreven. Het kan fout gaan doordat eenRus of een Griek informatie heeft geschreven in zijn codepage, maarhet blijkt in de praktijk ook voor te komen dat Unicode of UTF-8 isgeschreven zonder dat te vermelden. Om het netjes te doen moet, bijafwijkend karaktergebruik, een record worden opgenomen waarin datwordt gespecificeerd. Meestal wordt dan in UTF-8 geschreven en danziet dat record er als volgt uit:

#$1c#1’Z’#0#3#$1b’%G’

Dat is dus een record met “groep=1” en “ID=90”. Als we dit recordtegenkomen dan weten we dat de data gelezen moet worden alsUTF-8. Het converteren van een string naar een reeks UTF-8 karaktersen weer terug kan eenvoudig met de betreffende TEncoding. Als voor-beeld volgt hieronder de code om een record “stad=Δελφοί” toe tevoegen aan het segment:

type THead=record Marker,Groep,ID,Size1,Size2:byte end;

var lHead:THead;

lBytes:TBytes;

begin

lHead.Marker:=$1c; //beginmarker

lHead.Marker:=2; //groep=2

lHead.Marker:=90; //ID=”city”

lBytes:=TEncoding.UTF8.GetBytes('Δελφοί');//genereer bytes

lHead.Size1:=length(lBytes) div 256;

//schrijf lengte

lHead.Size2:=length(lBytes) mod 256;

//van de databytes

aStream.write(lHead,5);

magazine voor software development 11

Het veld “UserComment” is het enigewaarbij over Unicode wordt gesproken

DELPHI

Page 12: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

//schrijf de header

aStream.write(lBytes[0],length(lBytes));

//schrijf de databytes

end;

Als we in een andere encoding zouden willen schrijven is het enigewat we moeten doen op dit punt de encoding wijzigen en alles blijftverder werken. Het is dan natuurlijk handig deze encoding ergens alsparameter of property op te geven zodat je die kunt wijzigen zonderdirect het hele programma te hoeven compileren. Dat is dan ook deaanpak zoals die in download terecht is gekomen.

IPTC implementerenHet goede nieuws is dat onze basisimplementatie (zie hiervoor) ookvoorziet in het lezen en schrijven van de IPTC tag, maar helaas

ontbreekt wel het stuk waarin je de tekstcodering kunt specificeren.Wat nog vervelender was, was dat er een bug bleek te zitten in hetschrijven van het segment. Het kwam erop neer dat ik ineens tweeIPTC segmenten in mijn bestand had zitten. En Photoshop maarsteeds de oude inlezen!Ik heb de procedure om te schrijven dus moeten aanpassen. Het komter op neer dat ik het bestand eerst inlees in een (invoer)stream, endaar lees ik vervolgens de segmenten uit. Als het een segment is datik zelf heb gewijzigd, dan schrijf ik mijn eigen versie van het segment,en anders dan schrijf ik (een kopie van) het segment uit het invoer-bestand. Dat blijkt goed te werken.

En nog veel meer tagsEXIF en IPTC zijn de twee segmenten die het meest gebruikt wordenom (gebruikers)gegevens aan JPEG bestanden toe te voegen. En ikkan er de informatie in kwijt die ik er in kwijt wil. Ik heb dus niet verdergezocht naar de specificaties van de vele andere segmenten die ineen JPEG bestand voorkomen. In de basisimplementatie wordt eenaantal gelezen, en dat is prima. Ik doe er echter niets mee. Ik zal er pasnaar gaan zoeken als ik ergens iets tegenkom wat ik graag wil wetenmaar niet in deze twee segmenten kwijt kan.

Wat me brengt naar het volgende: er zijn vele programma’s in omloopdie allemaal iets kunnen met de tags in JPEG. Maar ze hebben deneiging het allemaal net iets anders te doen, en het is altijd maar devraag of wat in jouw programma werkt ook functioneert in een anderprogramma. Ik zelf ga ervan uit dat het goed is als Photoshop het kanlezen, maar dat is geen garantie voor andere programma’s. In hetalgemeen blijken er maar teleurstellend weinig programma’s te zijn die

goed om kunnen gaan met Unicode. Als er al Unicode gebruikt kanworden, dan toch vaak met horten en stoten. Dan komt “Δελφοί”toch nog weer ergens als “?e?f??” tevoorschijn. Als dit gebeurt, danwordt er ergens toch nog een “Ansistring” gebruikt. Daarbij verbaasthet me altijd dat sommige karakters wel en andere niet omgezet wor-den naar een standaardkarakter. Waarom de “ε” wel en de “ο” niet, isvoor mij een volslagen raadsel. En dit geldt dus niet alleen voor pro-gramma’s die iets doen met JPEG tags…

Een voorbeeldprogrammaVoor de download heb ik een klein voorbeeldprogramma gemaakt.De meest algemene invoervelden staan als TEdit op het scherm endeze gegevens kunnen direct gewijzigd worden. De overige informa-tie uit EXIT en IPTC worden in een Memo gedumpt. Verder is het eenkwestie van een bestand lezen en schrijven.

Het is maar een voorbeeld. Desgewenst kunt je het programma metwat eenvoudige aanpassingen volledig naar je eigen inzichtenwijzigen.Het programma werkt als volgt: je opent een bestand met de daarvoorbedoelde knop. Het plaatje wordt getoond en de voorgeprogram-meerde velden worden gevuld met informatie. Rechts in het schermwordt een dump van de EXIF en de IPTC segmenten gegeven. Omgedonder met bestanden die in andere coderingen zijn geschreven tevoorkomen heb ik hier twee comboboxen opgenomen waarmee deencoding voor het lezen gewijzigd kan worden. Gewoon proberen enkijken of de informatie er beter uit komt te zien…Om de (gewijzigde) gegevens weer naar het bestand te schijven wordtde knop “Opslaan” gebruikt. Daarbij wordt expliciet om eenbestandsnaam gevraagd. Dat heeft het voordeel dat het zo mogelijkis dezelfde informatie in meerdere bestanden te schrijven. •

12 MAGAZINE

Er zijn vele programma’s in omloop dieallemaal iets kunnen met de tags inJPEG, maar ze hebben de neiging hetallemaal net iets anders te doen

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 teverwerken. Midden jaren ’90 besloot

hij, na zijn studie informatica, zich geheel te gaan wijden aan deautomatisering. Via Prisman Consultancy houdt hij zich bezig methet maken van software en consultancy.

DELPHI

Page 13: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

Advertentie Microsoft

Page 14: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

MAGAZINE

INFORMATION

WORKER

Het werk van een Information WorkerDe term Information Worker, kortweg IW’er, bestaat al een hele tijd.Microsoft heeft deze term bedacht om een groep mensen aan teduiden die met informatie werkt. Nou ja, de officiële definitie gaat watverder dan dat, maar in het kort komt het daar wel op neer.Voordat we gaan kijken wat een IW’er nu precies doet, is het wellichthandig om te definiëren wat informatie nu precies is. Immers: we zijnallemaal werkzaam in de ICT-sector, waarbij de C en T (communica-tie en technologie) termen zijn waar we wel een voorstelling bij kunnenmaken, maar de I van informatie … die blijkt voor veel mensen tochwat lastiger.Ik heb in een grijs verleden bedrijfskundige informatica gestudeerd.In die tijd heb ik veel geleerd (voornamelijk klaverjassen en 7 dagen inde week in de kroeg overleven) en ik ben het meeste daarvan al weervergeten. Toch is er één ding dat is blijven hangen: de definitie vaninformatie. Om je een 4-jarige studie te besparen zal ik die hier evenherhalen.

InformatieInformatie is een set met gegevens die voor de juiste persoon op de

Dennis Vroegop

Rapporteren in de 21e EeuwEigenlijk is het grappig. Er is bijna geen vakge-bied dat zo snel verandert als het onze; de ICTsector gaat met enorme stappen vooruit. Tochis er één gebied dat achterblijft: de rapportage.Als je kijkt naar hoe we vandaag de dag eenInformation Worker van gegevens voorzien, zieje dat er in de afgelopen decennia niet veel isveranderd. Vreemd, aangezien informatie inonze samenleving steeds belangrijker wordt.Je kunt je afvragen hoeveel kansen er blijvenliggen doordat de verantwoordelijke mensenbinnen een organisatie niet beschikken over deinformatie die ze nodig hebben. In de Compu-table stond laatst een artikel over het enormeaantal managers dat niet de juiste beslissingenneemt doordat ze niet tijdig over de juiste ge-gevens beschikt. Ik hoef je niet te vertellen hoe-veel geld dit een organisatie kan kosten.Gelukkig is er een lichtpuntje aan de horizon:de techniek staat niet stil. Ook de rapportage-technieken niet. De gereedschappen zijn er, wemoeten nu alleen even weten wat we gaanrapporteren en vooral, hoe we dat gaan doen.In dit artikel laat ik je een mogelijkheid zien. Doeer je voordeel mee!

juiste tijd op de juiste plek waarde toevoegt, mits deze gegevenscorrect en volledig zijn.

Lees de zin nog eens.

Als je deze definitie in je achterhoofd houdt, zul je zien dat heel veelgegevens ten onrechte informatie genoemd worden. Hoe vaak hoor jeniet iemand roepen dat de informatie onjuist was? Dat kan dus niet:gegevens moeten correct zijn voordat je van informatie kan spreken.“Ik heb de informatie te laat gekregen” is ook zo’n veelgehoorde klacht.Klopt niet. Gegevens die te laat aangeleverd worden zijn gegevens,geen informatie.Nog een voorbeeld: de aandelenmarkt stort in het derde kwartaal van2008 in elkaar. Tja. Dit klopt, alleen hebben wij er als ICT’ers niet zoveel aan. We zijn immers geen beurshandelaren. We zijn dus niet dejuiste persoon. En zelfs als we dat wel waren, dan nog is de tijdverkeerd. Ook is het niet volledig: er zijn fondsen overeind gebleven,iets wat voor een handelaar ook belangrijk is om te weten.

Een andere leuke term is ‘information overload’. Daarmee wordtgesuggereerd dat er zoveel informatie beschikbaar is dat we er geenchocola meer van kunnen maken. Ook in dat geval is er geen sprakevan informatie maar eerder van een (enorme) brij aan gegevens. VooralBI-toepassingen zijn goed in het genereren hiervan.Je ziet dat veel gegevens die we nu informatie noemen geeninformatie zijn. Het is erg belangrijk om het onderscheid tussengegevens en informatie te begrijpen.

Het doel van een IW’erLaten we eens teruggaan naar de IW’er. Een IW’er is iemand die metde juiste tools van gegevens informatie kan maken. Nu we hetverschil weten tussen gegevens en informatie, moet het ietsduidelijker zijn wat een IW’er doet. Een IW’er neemt een hoeveelheidgegevens en transformeert dat in informatie. De IW’er verzamelt,controleert, valideert en rapporteert deze gegevens aan iemand voorwie die gegevens waarde toevoegen zodat we over informatiekunnen spreken. Uiteraard kan die 'iemand' voor wie de informatiegegenereerd wordt ook de IW’er zelf zijn.

Is een ontwikkelaar een IW’er? Nee, de ontwikkelaar maakt tools enimplementeert systemen. De ontwikkelaar genereert dus geeninformatie.

Informatie is een set met gegevens dievoor de juiste persoon op de juiste tijdop de juiste plek waarde toevoegt, mitsdeze gegevens correct en volledig zijn

Een IW’er is iemand die met de juistetools van gegevens informatie kanmaken

14

Page 15: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

Als je echter de tabel omzet in een standaard Excel-grafiek, dan ziethet er opeens anders uit:

Fig. 1

In figuur 1 zie je dezelfde data weergegeven, maar nu in grafiekvorm.Opeens zie je meer: september ontbreekt, de omzet van mei 2007 ennovember 2006 zijn vele malen hoger dan je zou verwachten en deomzetten van 2008 zijn wel heel erg laag (dat heeft niets met dekredietcrisis te maken: die is pas echt begonnen in oktober en we ziendat de omzet in januari al erg laag is). Kloppen deze gegevens?Misschien is 2008 over het hele jaar erg slecht geweest en zijn mei2007 en november 2006 wel uitschieters. Misschien is dit bedrijf altijdin september gesloten waardoor de omzet op nul uitkomt.Bij de organisatie waar deze data vandaan komt was dit niet zo: dereden van deze uitschieters was domweg een foutieve invoer van data.Je ziet dat je in een eenvoudige grafiek al meer informatie staat dan ineen tabel. Of liever gezegd: een IW’er is sneller in staat om informatiete maken van de gegevens als deze als grafiek worden gepresenteerd,in plaats van als een brij met gegevens zoals in de tabel.

De derde dimensieDe grafiek in figuur 1 is al een enorme verbetering, maar het kan nogveel beter. Het is niet eenvoudig om de gegevens te vergelijken. Excelbiedt ons de mogelijkheid om een grafiek in 3D weer te geven. Dezeziet er dan als volgt uit:

Fig. 2

Het ziet er absoluut mooi uit. Maar handig? Nee: we kunnen degegevens van 2008 niet zien. Deze zijn verborgen achter de andererijen. Nu kunnen we rijen en kolommen omdraaien zodat het beterleesbaar wordt, maar dat levert weer andere problemen op. Je loopt

magazine voor software development 15

Is een secretaresse een IW’er? Volgens bovenstaande definitie duswel. Zij (meestal zij, soms hij) neemt de enorme hoeveelheid gegevensdie anders op het bureau van de leidinggevende terecht zou komen,filtert dit, sorteert en groepeert dit, valideert dit en geeft het inhapklare brokken door. Op die manier ontstaat informatie. Eensecretaresse is dus een IW’er.Zo is er nog wel een aantal beroepsgroepen dat aan de definitie vanIW’er voldoet, maar die kun je zelf wel bedenken.

De gereedschappenDe tijd dat een IW’er een krant kon pakken, deze naast het jaarverslagvan de organisatie kon leggen en daarmee genoeg gegevens had ominformatie te genereren ligt al jaren achter ons. Er zijn zoveel gegevensbeschikbaar dat een IW’er de goede gereedschappen nodig heeft omin die brij van data informatie te vinden. Het is de taak van de ICT’erom de IW’er van die gereedschappen te voorzien.Sterker nog, ik denk dat dit de hoofdtaak van een ICT’er is. In vrijwelalle gevallen maken of implementeren wij systemen die de IW’erhelpen zijn of haar werk goed te kunnen doen. De tools die de IW’ergebruikt moeten dus de enorme beschikbare hoeveelheid gegevensop een dusdanige manier presenteren dat er informatie van gemaaktkan worden.Natuurlijk is niet alleen de data in de systemen een bron; ook dekennis van de IW’er is een niet te verwaarlozen factor in dit proces.Een goede IW’er combineert zijn of haar kennis met de gegevens diebeschikbaar zijn. De juiste gereedschappen maken dit mogelijk.

Nu kennen we al een grote verscheidenheid aan gereedschappen.Er zijn verschillende rapportagetools beschikbaar (Crystal Reports,SQL Server Reporting Services, enz.). De BI-tools vallen ook onder degereedschapsset van de IW’er: data wordt in een andere vormgegoten en dusdanig gepresenteerd dat er iets zinnigs over te zeggenvalt. En dit is nu net waar het fout gaat. Bovenstaande rapportage-middelen zijn in wezen niet anders dan de tools die we al jarengebruiken. Oké, het werkt allemaal wat makkelijker dan ongeveer 10jaar geleden, maar het eindresultaat is hetzelfde.

Weergave van gegevensIn veel organisaties wordt data nog steeds in tabelvorm gepresen-teerd. Dat lijkt een efficiënte manier van presenteren, maar in demeeste gevallen werkt het niet. Onderzoek wijst uit dat 95% van demensen geen getallen kan lezen.Kijk eens naar de volgende tabel. Niet lezen, maar kijk er gewoon evennaar:

Deze tabel heb ik in het echt gezien in een rapport van ongeveer 50pagina’s dik. Dit rapport wordt iedere twee weken gemaakt, met daarintientallen van dit soort tabellen.Op het eerste gezicht is dit een enorm efficiënte manier van presen-teren: een hele hoop gegevens is beschikbaar op relatief weinig ruimte.Zonder de tabel echt te lezen kun je er al veel uit afleiden: het gaat omomzetten in de jaren 2006 tot en met 2008, ze zijn gegroepeerd permaand.

Een IW’er is sneller in staat om infor-matie te maken van de gegevens alsdeze als grafiek worden gepresenteerd

Maand Omzet 2006 Omzet 2007 Omzet 2008Januari 3254578 4215478 556544Februari 4254785 4531254 454784Maart 3214578 4577654 454478April 3214455 5412131 544745Mei 4512354 9474165 424544Juni 4521545 3211457 544458Juli 5451236 3221557 322548Augustus 4511253 4233364 321547Oktober 1556654 2457884 245447November 9233215 1222547 123154December 2878945 2311547 322152Totaal 46603598 44869038 4314401

INFORMATION

WORKER

Page 16: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

immers nu het risico dat andere rijen verborgen worden en dan ben jenet zo ver van huis als in het begin.Even een leuk weetje: vroeger, toen Excel nog veel verkocht werd alslos pakket, stond op de doos van Excel een screenshot van degeweldige grafische mogelijkheden van het pakket. Dat plaatje waseen grafiek die erg leek op het plaatje in figuur 2. Echter, op dat plaatjesteeg de omzet per jaar gestaag. Dat moest ook wel omdat anders dedata in de latere jaren niet leesbaar was. Anders gezegd: de 3Dgrafiek is een leuk plaatje, maar, zoals figuur 2 duidelijk maakt, is dezeweergave niet echt praktisch.

En wat nu?In de jaren negentig ontstond een nieuw fenomeen: de KPI’s, wat staatvoor Key Performance Indicators. KPI’s zijn een soort verzamelgroot-heid van een aantal sleutelwaardes waaruit je kunt afleiden hoe jeorganisatie het doet.Het idee, dat niet nieuw was, kreeg veel aandacht door het toepassenervan in balanced scorecards, zoals verwoord in het artikel “TheBalanced Scorecard” van Kaplan en Norton in 1992 (wat leidde tothun bestseller “The Balanced Scorecard: Translating Strategy intoAction” uit 1996).Een balanced scorecard (BSC) is niets anders dan een zeer vereen-voudigde weergave van een aantal meetpunten in de organisatie. Wekunnen de tabel uit figuur 1 dan ook als volgt gaan weergeven:

Fig. 3

We zien geen cijfers meer, maar symbolen. Een rondje betekent dat deomzet voor deze maand boven de €450.000 ligt, een driehoekjebetekent dat de omzet tussen €200.000 en €450.000 ligt en onderde €200.000 zien we een ruitje.We hebben nu geen inzage meer in de exacte cijfers. Maar is dat eenprobleem? Dat kan een probleem zijn als we een publicatiebalans voorde Kamer van Koophandel moeten maken, maar voor de dagelijksegang van zaken is dit niet erg. Een manager wil dagelijks kunnen zienhoe de zaken er voor staan. De rode ruiten vallen direct op en demanager weet nu meteen dat er gebieden zijn waar hij of zij aandachtaan moet besteden.Als het gaat om het krijgen van een gevoel over de stand van zaken,zijn BSC’s een geweldig gereedschap.Excel levert de mogelijkheden om BSC’s te maken, maar als je ditserieus wilt aanpakken, dan moet je uitwijken naar meer gespeciali-seerde tools, zoals Microsofts Performance Point Server. Samen metSQL Server Analysis Server heb je dan een zeer krachtig BSC tool inhanden.

We hebben nu wel informatie over de omzet, maar we missen tochnog iets. Zou het niet mooi zijn als we meer gegevens kwijt zoudenkunnen in een manier van weergeven, maar toch in staat zouden zijnom het directe inzicht te krijgen? We willen toe naar een situatie waarinwe meer details zien maar toch meteen een idee krijgen van de standvan zaken.Als jij deze wens ook koestert, dan heb ik goed nieuws: die manier iser!

3D Business VisualizationZoals we vastgesteld hebben zijn mensen zoals jij en ik veel beter instaat om plaatjes om te zetten in informatie dan rijen met getallen. Hetis een cliché, maar daarom niet minder waar: een plaatje zegt meerdan duizend woorden.Even een test: kun je mij vertellen hoe laat het is? Eigenlijk wil ik nietweten hoe laat het is (je leest dit artikel in het magazine dus je kunt hetme ook niet vertellen), maar ik wil graag weten wat voor horloge je omhebt. In de jaren tachtig van de vorige eeuw hadden we allemaaldigitale horloges. Vandaag de dag zie je die eigenlijk niet meer: we zijnallemaal weer terug naar analoge horloges. Waarom is dat? De redendaarvoor is dat de tijd 10:49 een getal is. We voelen er niets bij. Onzehersenen moeten dat vertalen in een tijd. Twee wijzers waarvan dekleine bijna op de 11 staat geeft ons echter het gevoel dat het bijna 11uur is, en dat is meestal voldoende informatie. We hoeven dat gevoelvan tijd niet meer om te zetten in onze hersenen, we weten meteenwaar we aan toe zijn.Maar met plaatjes alleen zijn we er nog niet. Onze wereld is niet plat,deze bestaat uit drie dimensies. Mensen zijn erg goed in staat om indrie dimensies te zien, we kunnen veel meer informatie uit driedimensies halen dan uit een plaatje met slechts twee dimensies. Tochhebben we gezien dat de 3D grafieken uit Excel niet echt helpen.Gelukkig kunnen we nu met de nieuwe tools, omgevingen, hardwareen software die ons ter beschikking staan daar iets anders op verzin-nen. We kunnen gegevens vanuit onze databronnen dusdanig weer-geven dat een IW’er er snel informatie uit kan halen. Zeker met WPFen Silverlight is het maken van deze applicaties relatief eenvoudig.

Nu is het weergeven van complexe data in een 3D omgeving nietsnieuws. In de 18e eeuw gebruikte Napoleon al maquettes van de slag-velden. Hij plaatste poppetjes die zijn legers voorstelden en die vande tegenstander in een model waar de veldslag plaats zou vinden. Opdie manier kon hij goed bedenken hoe hij zijn soldaten in moestzetten. De Engelsen werkten nog met (twee dimensionele) kaarten endaardoor ontbrak het hen aan een stuk inzicht. Dat is de Engelsenduur komen te staan (dat hebben ze later goed gemaakt, maar dat isweer een heel ander verhaal).

Stel je nu eens voor dat de data uit de eerste tabel een verzameling isvan een aantal databronnen. We hebben immers alleen de totalen permaand weergegeven, en dit zal waarschijnlijk een optelsom zijn van deomzetten per filiaal (als we er even vanuit gaan dat dit de omzet vaneen winkelketen is). We hebben door er een tabel van te maken duseigenlijk al gegevens weggelaten. Gegevens die wel degelijkinformatie kunnen bieden: hoe verhouden de verschillende regio’s inNederland zich tot elkaar?

16 MAGAZINE

We zijn allemaal weer terug naaranaloge horloges

Het grappige is dat uit onderzoek isgebleken dat mensen dan in hun hoofddie grafieken gaan samenvoegen toteen 3D-omgeving

INFORMATION

WORKER

Page 17: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

We kunnen dat weergeven door verschillende tabellen te maken: éénvoor iedere regio. Helpen doet dat niet echt: op die manier creëren wealleen maar meerdere, niet eenvoudig te interpreteren tabellen of gra-fieken. Het grappige is dat uit onderzoek is gebleken dat mensen danin hun hoofd die grafieken gaan samenvoegen tot een 3D-omgeving.Bij Business Visualization doen we dat alvast voor de gebruiker. Wemaken nu een andere grafiek, eentje die er als volgt uitziet:

Fig. 4

Nu is dit magazine helaas niet de beste manier om deze gegevensweer te geven. In de echte applicatie kun je inzoomen en roteren,zodat je de grafiek van verschillende kanten kunt bekijken. Wellicht isdit in magazine 200 opgelost: zouden we dan eindelijk digitalemagazines krijgen? ;-)Door de mogelijkheid om te roteren en te zoomen te geven voorkomenwe dat gegevens niet zichtbaar zijn doordat er andere elementen voorstaan.

Hoewel dit een 3-dimensioneel plaatje is, spreken we liever van eenmulti-dimensioneel plaatje. Ten eerste klinkt dat beter, maar het dektde lading ook beter. We hebben in dit plaatje een aantal verschillendedimensies weergegeven:1. De omzet wordt weergegeven door de hoogte van de kolommen.2. De regio waar de omzet is gerealiseerd zie je door de plaatsing van

de kolommen.3. De bijdrage aan de winst van de organisatie wordt weergegeven

door de kleur van de kolommen (hoe groener, hoe meer winst ergemaakt wordt in die regio).

4. De omloopsnelheid van het assortiment wordt duidelijk gemaaktdoor de breedte van de kolommen: hoe breder, hoe korter de pro-ducten in het magazijn blijven liggen.

Deze vier dimensies zijn op een dusdanige manier weergegeven datwe conclusies kunnen trekken uit het plaatje. De oostelijke provinciesdoen het goed: er wordt vooral in het noorden veel verkocht en weverdienen er ook veel. In het westen echter zijn de winsten aanmer-kelijk lager en ook de totale omzet blijft achter bij de rest. Zeeland enLimburg hebben een erg lage omloopsnelheid, de kolommen daar zijnvrijwel niet zichtbaar.Je ziet dat je erg veel informatie kunt halen uit een 3D-grafiek, iets watin de traditionele manier van rapporteren veel minder snel kan. En datzonder daadwerkelijke cijfers te tonen. In één oogopslag weet je hoehet met je organisatie gaat, zonder dagelijks dikke rapporten door temoeten lezen.

De applicatie moet uiteraard wel voorzien in een drill-down mogelijk-heid: door te klikken op één van de kolommen moet je details kunnenzien, zoals de gegevens per winkel, per maand of wat dan ook. Dooreen interactieve applicatie als deze te bouwen geef je de IW’er demogelijkheid om door de data heen te vliegen als ware het een virtualreality-achtig spel. Dat nodigt uit tot kijken en spelen. De gegevens diedaarmee inzichtelijk gemaakt worden, leveren veel sneller informatieop dan wanneer gebruik gemaakt wordt van de traditionele manieren.

De techniekenHet plaatje dat je ziet in figuur 4 is een screenshot van een applicatiedie ik voor dit artikel gebouwd heb. Het komt dus niet uit Photoshop!Deze applicatie is geheel gebouwd in .Net 3.5 en draait op het WPF-framework. Het is ook mogelijk om dit in Silverlight te bouwen, maarals je dat van plan bent wil ik je wel even waarschuwen. Silverlightondersteunt geen 3D-grafieken. Je zult alles dus zelf moeten tekenen.In WPF is het maken van een dergelijk systeem een fluitje van eencent. Goed, je moet wat basiskennis hebben over het programmerenvan 3D-omgevingen maar er zijn genoeg goede boeken over datonderwerp te verkrijgen. Ook op mijn blog doe ik helemaal uit dedoeken hoe ik dergelijke applicaties bouw. De broncode is vrijbeschikbaar. De truc zit hem ook niet in het daadwerkelijk bouwen vande 3D applicatie, maar wel in het onderzoeken van welke data je weerwilt geven. Dit is echter het werk van een analist en niet van deontwikkelaar. Naast een analist wil je er trouwens ook een graficus bijhebben; iemand die verstand van kleuren en vormen heeft. Mijnervaring is dat game-designers erg goed zijn in het opzetten van eenBusiness Visualization omgeving! En ja, ook met XNA kun je dergelijkerapportagetools maken (als proef heb ik dergelijke applicaties al opeen Xbox 360 laten draaien…)

ConclusieDoor gebruik te maken van slimme rapportages kan een InformationWorker veel sneller grote hoeveelheden gegevens omzetten in infor-matie. De tools die vandaag de dag beschikbaar zijn worden helaasnog niet genoeg ingezet in de meeste organisaties. Door slim om tegaan met de mogelijkheden van de tools en de mogelijkheden van demenselijke geest kunnen we echter de gegevens wel zodanigpresenteren, dat de IW’er zijn of haar werk veel efficiënter kan doen.Probeer eens te denken buiten de gebaande paden. Realiseer je dateen Information Worker een heel andere manier van werken en den-ken heeft dan een ontwikkelaar. Mensen willen graag ‘gevoel’ hebbenbij data zodat ze informatie krijgen. Als je dat in je applicaties voorelkaar kunt krijgen, zul je zien dat de IW’er waar jij je applicaties voorbouwt je enorm dankbaar zal zijn. En daar gaat het ons toch om? •

magazine voor software development 17

De applicatie moet uiteraard welvoorzien in een drill-down mogelijkheid

Mijn ervaring is dat game-designerserg goed zijn in het opzetten van eenBusiness Visualization omgeving

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 Nederlandse .NETgebruikersgroep.

INFORMATION

WORKER

Page 18: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

Advertentie Avanade

Page 19: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

As a regular contributor to the SDN Magazine, I have been asked tocontribute something more on the personal side. And although I havealways enjoyed sharing technical material, I am delighted to oblige thisrequest.I will, to put it simply, tell on myself. Specifically, I will share with you,dear reader, an embarrassing episode that I was at one time commit-ted to keeping secret forever. But secrets kept are lonely, at best. Andtherefore, I will celebrate this 100th issue by keeping this secret nolonger.

To begin with, I have a confession. Actually, I have two. The first is that,as a conference speaker, the conferences offered by the SoftwareDevelopment Network, an organization that has undergone a varietyof name changes over the years, are among my favorite.The reason for this affection is simple. It’s the people involved:organizers, attendees, and fellow speakers. I know of no reoccurringconferences that so consistently bring together such a good group ofpeople, and I appreciate it very much. Thank you for making me a partof this.

I was first introduced to this organization, which at the time wascalled the Software Developer Group Netherlands, in 1995. Followinga talk I gave at the annual Borland International Conference inAnaheim, California, Joop Pecht, SDGN Secretary, and Ad van derLisdonk, then President of SDGN, introduced themselves, duringwhich they gave me a call for papers for the upcoming SDGN event.The SDGN Conference to the Max 1996 was my first conference forthis organization, and I have since had the honor and pleasure tospeak at 12 of this organization’s major conferences, as well as anumber of the smaller events.And this leads me to my second confession. In December of 2003,I nearly missed my own SDN Event presentation. To be more precise,I missed part of it, the first part, to be exact (which must be obvious ifyou give it any thought). And here’s the weird part. It was a successfulpresentation. But you’ll have to read on if you want to know why.

As I begin this confession, I imagine that your reaction might rangefrom “Oh, who cares? It’s not the end of the world.” to “How dare you!We, who committed our time and energy to travel to these events,deserve better.” Regardless of whether you are among the “yawn”group or the “hang him up” contingent, I must admit that this mix-upwas nothing short of a worse nightmare come true.I’ve been delivering corporate training, training tours, user groupmeetings, workshops, and the like, for more than two decades. Withas much travel as I have done, and as many courses and seminars I’vepresented across North America and Europe, it’s a miracle that Ihaven’t encountered some situation where, due to events beyond mycontrol, I have failed to arrive on time for the event.In most cases, I would fly into a city where I was presenting one ortwo days in advance. And though the odds are against it, I was neverlate due to weather or equipment malfunction. Although I lived withthe constant dread that I would miss an event, and anticipated whatactions I would take if the circumstances arose, it just didn’t happen.(I should really end that last sentence with the word “yet.” It’s like theold adage about motorcycle riding. If you ride a motorcycle, you’veeither fallen, or you will fall. As long as you keep riding a motorcycle,a fall is certain.)

So, with this in mind, you might imagine that I put a fair amount ofplanning into my travel in order to minimize the possibility thatsomething may happen to keep me from making my presentation.And the days leading up to December 10th, 2003, were no different.

Cary Jensen

As you read this magazine, it should be

impossible to ignore the fact that this is

the 100th issue. This is, on so many

levels, a remarkable achievement, and

one that is worthy of celebration. I have

written columns for a number of diffe-

rent magazines, and few of them have

survived long enough to reach this

impressive milestone (though I admit no

hand in their demise). So let me begin

by expressing my heartfelt congratulati-

ons to everyone involved in this maga-

zine, past, present, and future.

I will celebrate this 100th issue bykeeping this secret no longer

If you ride a motorcycle, you’veeither fallen, or you will fall; as long asyou keep riding a motorcycle, a fallis certain

Train of Thought:

Confessions of aConference Speaker

magazine voor software development 19

SDN

MAGAZINE

EDITIE

SDNMAGAZINE

EDITIE

100

Page 20: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

This particular SDN Event was held at de Reehorst Hotel andConference Center in Ede. This, it turns out, was a contributing factor.A second factor was that I was scheduled to give my first presentationduring the day’s first time slot, immediately following registration.For those of you who’ve been to de Reehorst, you can understandwhy my wife, Loy Anderson (whom many of you are familiar with, andwho always attends SDN events with me), and I decided to stay inAmsterdam the night prior to the conference. To put it bluntly, de Ree-horst is in the middle of nowhere. Actually, it’s in the middle of acharming neighborhood, but compared to Amsterdam’s nightlife, thatconstitutes the middle of nowhere.

Mind you, Loy and I are not big nightlife people. We do, however, liketo shop and stroll around the walking streets of central Amsterdam,and Ede simply does not offer the same opportunities for this. Noproblem. We’ll stay in Amsterdam the night before and take the trainin the morning.As I mentioned earlier, when travel is involved, I tend to planextensively, and this time was no different. I choose to take the 7:46train, which would get me to the Ede-Wageningen train station at 8:45.The Hotel is a short three blocks from there, so I would be at DeReehorst at least 35 minutes or so before my talk, which wasschedules to start at 9:30.In addition, and here’s the clever part, if for some reason I missed thattrain, there was another scheduled to depart at 8:16, which would stillget me to the conference center with a few minutes to spare. With thisbit of insurance, what could possibly go wrong?We left our hotel, which was very close to Amsterdam’s CentralStation, at 7:20 the morning of the conference. It was a bitterly coldmorning, and the sidewalks were icy. No problem, however, as we hadgiven ourselves plenty of extra time. And we arrived at the trainplatform 10 minutes early.

This story is a little better if you understand that Loy and I areseasoned travelers, even in Europe. For us, taking a train is no problem(which is why the SDN organizers trusted us to make the journeyalone, rather than arranging for someone to drive us in the morning).But the Dutch language, of which we can understand only a little,aggravated our downfall. At 7:45, a mere minute before our train wasexpected, there was an announcement. My limited Dutch allowed meto comprehend that it had something to do with the arriving train. Butthat was all.My first clue that something was wrong was that the train arrived, righton time, from the wrong direction. The train arrived from the east, thedirection of Utrecht, and I knew that we had to travel through Utrechton our way to Ede. But what do I know about this train. Maybe onceit picks up its passengers it will head back towards the east. (Pleasenote that the monitors on the platform still showed a train to Utrechtat 7:46, and their was no indication of the train’s destination on thetrain itself. Believe me, I checked.)

So, here we were, on the correct platform (5b) at the correct time (7:46)with a train arriving. It must be our train, right? But then there was thatannouncement. What was actually said? There was little time to think,and certainly not enough time to ask someone whether this train washeading towards Utrecht or not. We had to act. The train doors were

about to close. Loy gave me one of those urgent “what do we do?”looks, and I said “Let’s go!”. We boarded the train just as the doorsclosed.

As soon as the train began moving, I knew I had made a mistake. Thetrain continued on its course to the west, and I had no idea where itwas going.I panicked. Obviously, this was the wrong train, and we would miss thetrain that was scheduled for 7:46 (and apparently, in hindsight,delayed). My best hope was that this train was a stoptrein, one thatmade frequent stops. We could then get off, and take the very nexttrain back to Amsterdam Central, in time for the 8:16, which wouldget us to the de Reehorst in time for my talk.

As most of you know, there are several different kinds of trains. Asmentioned, there are the “stoptreins”, which stop often, and then thereare the “sneltreins”, the fast trains, which stop infrequently. It turns outthat we were on an InterCity sneltrein. Next stop, Haarlem.The trip to Haarlem took almost 15 minutes. This alone was cause forconcern. If we could not get back to Amsterdam Central for the 8:16,there was no way I would arrive in time for my talk.We got off the train upon arrival in Haarlem. Loy tried to find out whichplatform we needed to go to in order to catch the train back toAmsterdam Central Station while I used a pay phone to call the cellphone of our conference contact, Johan Parent, with whom we hadspent a lovely afternoon the day before in central Amsterdam.

Johan didn’t answer his cell phone, and to this day I am not even surethat I dialed the correct phone number, but I left a message anyway.As I hung up the phone, Loy approached me without having disco-vered where we needed to be. At this moment, I noticed that the trainwe had just disembarked was preparing to leave the station, and thatthe monitors indicated that this train was bound for Amsterdam. Withalmost no time to spare, we once again boarded this train as the doorclosed. Fortunately, this time the train left the station in the opposite di-rection in which it had entered (why didn’t this happen in Amsterdam?).As the train departed the station, we did a little math in our heads, andrealized that, not only was this train returning to Amsterdam, but it wasscheduled to arrive at 8:16. In fact, this train was the next train, our8:16 backup train. What a relief. I should make my talk.Shortly after the train departed the Amsterdam Central station forUtrecht, where we needed to change trains, I realized that I shouldcontact Johan in order to let him know that I would arrive onlyminutes before my presentation. I noticed another passenger, a youngman, talking on a cell phone (I didn’t have a cell phone that worked inEurope at the time). After he hung up his call, I explained my situationto him, and asked if he would be so kind as to let me pay him to makea short call.This time I got through to Johan, and explained that I was not goingto arrive until just before my talk, just as long as we made ourconnecting train in Utrecht. Johan thanked me for warning him of mylate arrival, and said he looked forward to seeing us again. At this point,we felt like we could relax and look out the train windows at the cold,frosty fields as the train made its way. It was still quite early, and thepale blue of morning was only beginning to spread across the sky.

We arrived in Utrecht with 5 minutes to spare before our next train wasscheduled to depart for, among other stations, Ede-Wageningen. Butwhile we waited on the platform, there was another announcement.Again, my Dutch language skills failed me, but we both knew thatsomething was up. Everyone else waiting on that platform gatheredtheir belongings and left.Having learned a hard lesson from the morning’s earlier failure,

20 MAGAZINE

To put it bluntly, de Reehorst is in themiddle of nowhere. Actually, it’s in themiddle of a charming neighborhood,but compared to Amsterdam’s nightlife,that constitutes the middle of nowhere

In fact, this train was the next train

SDN

MAGAZINE

EDITIE

SDNMAGAZINE

EDITIE

100

Page 21: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

I immediately sought out a conductor. The gentleman I foundexplained to me that the tracks were icy, and that our scheduled trainhad been canceled. The next train that could take us to Ede-Wageningen was leaving from another platform in twenty minutes.That did it. It was now impossible for me to make my talk. Before wecaught the next train I had to contact Johan with the bad news.Maybe, I rationalized, another speaker could give a talk scheduled forlater in the day in my time slot.On our way to the new platform we found another pay phone, andcalled Johan again. I explained to him that, at best, I would be 20minutes or so late for my talk. I suggested a couple of possibleactions to minimize the damage of my absence.

Now, you are going to need a little more information before you willunderstand the difficult position we were in. To begin with, myscheduled talk was unusual for an SDN conference. Heck, if it hadbeen on a Delphi, Visual Objects, VB, or other similar topic, therewould probably have been a dozen or so people who could havestepped in to provide at least an introduction prior to my arrival.No, this was a talk on the Advantage Database Server, a productabout which Loy and I had just recently published a book. And I couldthink of only one person who would likely be able to help. His namewas Simon Groothuizen. Simon was the BeNeLux representative forExtended Systems, the company that owned the Advantage Data-base Server at the time (it is now owned by Sybase).So, I suggested two options to Johan. First, swap my first talk withthat of another speaker (and this was the option that I hoped wouldwork, but you never know. Scheduling talks can be difficult, and itsimply may not be possible to swap two talks so close to the begin-ning of the event). Second, ask Simon to take the opportunity to givethe audience an introduction to Advantage. I would then come in andcover the technical side of things.As I got off the phone with Johan, I promised I’d get to the hotel assoon as possible. In the back of my mind, however, I had doubts.Things had not gone well so far, why should they get any better now?It was still very cold, and the tracks as well as roadways were slippery.Nothing was certain at this point.Fortunately, things did start to go right. The next train arrived on time,

and we soon found ourselves at the Ede-Wageningen station. Beforearrival, however, I had started up my laptop, loaded my PowerPointpresentation, Delphi, and the Advantage Data Architect (a graphicalapplication for configuring Advantage objects and data dictionaries).I then placed my laptop in sleep mode, so I could quickly resume ifnecessary.Foot travel was difficult as Loy and I made our way to de Reehorst. Thesidewalks were icy, and running was not an option, that is unless wewanted to practice falling down. Therefore, we choose the slow andsteady method. I don’t recall either of us falling, not even once.We arrived at the conference center, and walked directly to the room

where my talk was scheduled. On the way there we saw nobody whocould confirm, one way or the other, if my talk was actually in progress.I opened the door to the conference room and walked toward thestage. On stage were two people I knew well. Speaking was JeroenPluimers, a long-time friend and fellow conference speaker. Next tohim, apparently for moral support, was another friend and SDNmember, John Blaauw. I knew that both Jeroen and John where

Advantage users.Simon, on the other hand, was nowhere to be found. (It turns out thathe suffered from stage fright, and was unable to give an introductionto an audience the size of which turned out for this talk.) Fortunately,Jeroen and John were available, and pitched in at the last moment. Forthis, I am forever grateful.

As it turns out, just as I entered the room, Jeroen had covered justabout all of Advantage that he was ready for given the spur of themoment. But what he had shared provided the perfect introduction tothe material that I had prepared.Upon seeing me, Jeroen smiled widely, and announced my presenceto the audience. This resulted in a rather embarrassing and certainlyundeserved round of applause for me. Several people mentioned tome later that it was the perfect rock star entrance.As I walked down the aisle towards the stage, I removed my coat andtook my laptop out of sleep mode. It no time my slideshow appearedon the overhead projection system. And in the transition betweenJeroen and I, we scarcely skipped a beat. And, as I mentioned earlier,the overall talk was a success on nearly every level.

You sometimes hear the phrase “Someday we’ll be able to laugh aboutthis.” At the time, I was sure that this would not be the case. Howe-ver, I hope that you have had a laugh or two, even if it was at my ex-pense. Indeed, it was fun sharing with you this little secret. I ask onlyone thing. Please don’t tell anybody. •

magazine voor software development 21

Nothing was certain at this point

… that is unless we wanted to practicefalling down

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, includingAdvantage Database Server: A De-velopers Guide (2007, Sybase),Building Kylix Applications (2001,

Osborne/McGraw-Hill), JBuilder Essentials (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.

SDN TIP:RSSOp de nieuwe SDN-site is de RSS-feed verplaatst; je zult dusje RSS-reader opnieuw moeten instellen. De nieuwe feed voorverenigingsnieuws is te vinden via: http://tinyurl.com/bca42t ende feed voor nieuwe artikelen is te vinden op http://tinyurl.com/bmpn6d.

SDN

MAGAZINE

EDITIE

SDNMAGAZINE

EDITIE

100

Page 22: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

Advertentie Sogeti

Page 23: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

.NETASP

Zijn we echt verder dan ASP “Classic”?Voor de meeste mensen die zoals ik nog ASP “Classic” en WindowsDNA geprogrammeerd hebben, was ASP.NET fantastisch. Eindelijk afvan dat lelijke gescript tussen de HTML, echt object georiënteerd pro-grammeren en veel robuuster door onder andere garbage collection.Helaas zijn er ook mensen die het model van ASP.NET vervloeken,want het vereist een hele andere denkwijze dan ASP “Classic” envooral als je hele specifieke zaken wil met de weergave, kan hetobjectmodel van ASP.NET nog wel eens in de weg zitten. Dat de ASP“Classic” manier goed werkt en blijft werken is te zien aan het succesvan PHP, dat qua methodiek veel gemeen heeft met ASP “Classic”.Als Microsoft meer moeite had genomen om ASP te verbeteren en uitte breiden met allerlei modules die het leven van de ontwikkelaarvereenvoudigen (zoals met PHP gedaan is), waren we dan niet beteraf geweest? Als je kijkt naar ASP.NET MVC (Model View Controller), ishet antwoord daarop eigenlijk een schoorvoetend “ja”. ASP.NET MVClaat het model met pagina’s en controls varen voor een model waarinwe (weer) een HTML sjabloon hebben waar we waardes “in prikken”.Het is veel geavanceerder dan ASP 7 jaar geleden was, maar het isniet ondenkbaar dat we nu veel verder waren geweest als Microsofthet model hetzelfde had gelaten en ons alleen de geneugten van deCLR had gegeven.

Is ASP.NET MVC de toekomst?Er zijn nu al mensen die me vragen of ASP.NET MVC het huidige modelzal vervangen. Mijn antwoord hierop is dat ik dit niet op korte termijnzie gebeuren, aangezien ASP.NET MVC splinternieuw is en de meestemensen het nog niet eens gezien hebben. Verder zit er een enormeinvestering in applicaties die volgens het bestaande model gebouwdzijn. Er zijn ongelooflijk veel controls op de markt die alleen geschikt zijnvoor het huidige model en voordat al die functionaliteit ook in ASP.NETMVC gerealiseerd is, zijn we wel weer even verder. Het is echterontegenzeggelijk een interessante technologie en het lijkt erop datMicrosoft meer heil ziet in ASP.NET MVC dan het steeds maarcomplexer worden van allerhande controls. Ook gaat Microsoft metASP.NET MVC de concurrentie aan met technologieën om snelapplicaties te bouwen, zoals Ruby on Rails en geeft het veel meervrijheid om AJAX (Asynchronous JavaScript And XML) te gebruiken ineen applicatie. Want hoe handig het UpdatePanel voor ontwikkelaarsook is, het is in feite niet meer dan een verkapte postback, en dat isnou net wat AJAX eigenlijk helemaal moet voorkomen.

Moeten we allemaal AJA(X)cied worden?Nu we het toch over AJAX hebben, is dat eigenlijk wel de weg die weop moeten? AJAX leunt zwaar op de HTML DOM en de mogelijkheden

van JavaScript. Dat er al jaren door Adobe, Google en Mozilla enerzijdsen Microsoft en Yahoo anderzijds onenigheid is over hoe JavaScriptzich verder moet ontwikkelen laat in zekere zin het failliet zien van dehuidige standaarden voor het web, zeker als je daar ook nog eens destrijd tussen Adobe AIR, Google Gears en Microsoft’s Silverlight bij be-trekt. Vooral AIR en Silverlight laten pijnlijk duidelijk zien dat AJAX nietmeer is dan een lapmiddel op de tekortkomingen van HTML.Ironisch genoeg had HTML eigenlijk al helemaal niet meer moetenbestaan in z’n huidige vorm. Een van de bestaansredenen van XML ishet vervangen van HTML, om op die manier tot een web te komendat bestaat uit data met betekenis: het semantische web. Hoe je deXML wilt weergeven hangt af van wat je ermee wilt doen. Is het slechtscontent? Dan is CSS als opmaak sausje eroverheen genoeg (eventu-eel met wat HTML eromheen). Is het voor een applicatie? Dan weet dieapplicatie aan de hand van onder andere het XML Schema wel watermee gedaan moet worden. Helaas is die realiteit nog steeds heelver weg, maar er gloort hoop. Met SOAP en de WS-* specificaties zijner voldoende standaarden om een serieuze applicatie te maken opbasis van web services. Het maken van een RSS-feed is kinderlijkeenvoudig en ook de ondersteuning voor custom protocollen op basisvan POX (Plain Old XML) en REST (Representation State Transfer)wordt met de dag beter. Nu moeten we alleen nog ophouden allewebsites aan te bieden als HTML … maar dat is nu net waarom XMLnog steeds HTML niet vervangen heeft: het is wel erg makkelijk zo.

Join the (r)evolution!Het web is toe aan een radicale vernieuwing, een die net zo groot isals de ontwikkeling van het web zelf begin jaren negentig. Dit ontwik-keling is echter maar voor een heel klein deel een technische ontwik-keling. Het moet vooral van ons komen. Wij moeten stoppen metkijken naar het web als een verzameling HTML-pagina’s en zien dat heteen verzameling van data, informatie en operaties moet worden. Alswe dat kunnen, is de technologie die de weergave verzorgt vanondergeschikt belang. Het is immers slechts een “view” op de data. •

magazine voor software development 23

ASP.NET onder de Motorkap:

Heeft ASP.NET nog Toekomst?ASP.NET bestaat inmiddels al weer 7 jaar en dat is een mooi moment om eens terug te kijkenen vooruit te blikken. Waren het 7 vette jaren of waren het juist 7 magere jaren en gaan we nupas echt genieten van ASP.NET?

ASP.NET MVC laat het model met pagina’sen controls varen voor een model waarin we(weer) een HTML sjabloon hebben waar wewaardes “in prikken”

Michiel van Otegem

Michiel van Otegem is een van depioniers op het gebied vanASP.NET. Hij schrijft, spreekt engeeft hierover training. Hij is mede-eigenaar van de community websiteASPNL.com en schrijver van“ASP.NET 3.5 - de basis”, “XML - debasis” en “Sams Teach YourselfXSLT in 21 Days”. Voor zijn continueinzet voor de .NET community heeft

Michiel al 6 jaar op rij de MVP Award van Microsoft ontvangen.Michiel is werkzaam bij Batavia Labs als Chief Software Architect.

Page 24: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

UXINFORMATION

WORKER

Sandra de Ridder

Tips voor Mobile Webdesign

Soorten gebruikersMobiel internet biedt toegang tot informatie op ‘vreemde’ plaatsen enin nieuwe situaties. Dit zorgt voor een hele nieuwe manier van inter-netgebruik en een nieuw soort gebruiker. Grote rol bij het maken vankeuzes voor mobile webdesign speelt de status van de gemiddeldegebruiker:• Wat zijn ze aan het doen?• Waarom bezoeken ze de website?• Waarin zijn ze geïnteresseerd?• Waarnaar zijn ze op zoek?• Waarom bezoeken ze de website juist nu?Houd er rekening mee dat de gebruikers van het mobiele internet vaakmet een ander doel naar de website komen dan gebruikers dieachter hun bureau zitten.

Google heeft veel tijd en energie gestoken in het achterhalen van deverschillende gebruikersgroepen van mobiel internet. De web develo-pers van Google hebben zich uiteindelijk gericht op drie soortengebruikers en hun webapplicaties afgestemd op de wensen en eisenvan deze drie groepen. Laten we deze groepen eens beter bekijken …

De “gewone” gebruikerDeze gebruikers verschillen niet veel van de gemiddelde bezoeker vaneen reguliere website. Ze zijn niet speciaal op zoek naar specifiekeinformatie, maar hebben even tijd over om op het internet te surfen.Om ervoor te zorgen dat deze gebruikers vaker terugkomen op je sitemoeten ze geprikkeld worden door de informatie die ze tegenkomen.Laat met het oog op de beperkte schermruimte en beperkte tijd diedeze gebruiker heeft, geen grote stukken informatie zien. Deel het opin hapklare brokken die bij de bezoeker genoeg interesse opwekkenom nog eens terug te komen naar de site.

De terugkerende gebruikerDeze gebruikers komen regelmatig terug naar je website voor speci-fieke informatie of data. Als je een site hebt met bijvoorbeeld file-in-formatie, weerberichten of sportuitslagen, dan heb je waarschijnlijkveel van dit soort gebruikers. Analyseer welke informatie veel opge-vraagd wordt en maak deze makkelijk bereikbaar: toon het als eersteop de pagina. Ook voor het mobiele web geldt, dat informatie verstoptachter drie of vier klikken niet wordt bekeken.Aanbieden van gepersonaliseerde content via een mobiele website isniet eenvoudig, maar ook niet onmogelijk. Op een reguliere websitekun je via een inlog bij voor jou relevante informatie komen. Op eenmobiele website is inloggen niet echt eenvoudig. Een alternatief hier-voor kan zijn om terugkerende gebruikers via het reguliere web hunstartpagina te laten personaliseren. De gebruiker kan via een desktoppc een persoonlijke versie van de mobiele site samenstellen. Er wordt

een speciale URL gegenereerd die alle voorkeuren van de gebruikerbevat. Als de gebruiker op zijn PDA of mobiele telefoon via deze URLde site bezoekt, krijgt hij de door hem zelf samengestelde content tezien.

De bezoeker die dringend informatie nodig heeftAfhankelijk van het soort website kan de betekenis van ‘dringend’nogal variëren. Voor een klant van een webwinkel kan dringend zijn:“Mijn bestelling is nog niet binnen, waar is die nu?” Een dringenderevraag zou kunnen zijn: “Mijn trein heeft 10 minuten vertraging, haal ikmijn aansluiting nog?”Voor sommige bezoekers is alles dringend. Als je de belangrijkste in-formatiebehoefte van je doelgroep kent en je ervoor zorgt dat deze in-formatie binnen 1 of 2 klikken beschikbaar is, verhoog je de usabilityvan je website enorm (dit geldt uiteraard ook voor reguliere websites).

Fig. 1:Routeplannen via mobile.9292ov.nl

Minder opties = effectievere interfaceGebrek aan schermruimte en internetverbindingen die vaak langza-mer zijn dan die op een pc dwingen je tot het maken van keuzes in deaangeboden opties en informatie. Minder opties zorgen voor een sim-pelere en effectievere interface, zolang de aangeboden functionaliteitde gebruiker maar laat doen wat hij wil. Aan de webdesigner deschone taak vast te stellen wat essentieel is en wat weggelaten kanworden. Dit lijkt misschien simpel, maar een website die vol staat met

24 MAGAZINE

Waar bedrijven veel tijd en geld investeren in een reguliere website, wordt er over het algemeen nauwe-lijks aandacht besteed aan een mobiele variant hierop. In de afgelopen jaren is het aantal gebruikers dateen PDA of mobiele telefoon gebruikt voor internet explosief gestegen. Het kleine scherm en gebrek aanondersteuning van JavaScript zorgen ervoor dat de meeste websites niet goed werken op een mobieletelefoon of PDA. Men doet er goed aan een aparte website te ontwikkelen voor mobiel internet om deuser experience ook voor deze doelgroep te optimaliseren. In dit artikel wordt een aantal tips behandelddie je kunnen helpen bij het ontwerpen van een mobiele website.

Page 25: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

afbeeldingen, video’s en inhoud terugbrengen tot het hoogstnoodza-kelijke kan een uitdaging zijn.Dat het moeilijk is om afbeeldingen helemaal weg te laten blijkt wel uitverschillende nieuwssites. De banners worden wel weggelaten, maarafbeeldingen mogen kennelijk niet ontbreken in de mobiele variant.

Wikipedia heeft een goede mobiele website. Het invoervak centraal,geen toeters en bellen. De resultaten worden ook heel basic weerge-geven. Jammer is alleen dat je er niet automatisch op terecht komt alsje via je mobiel de url van de reguliere site invoert.

Fig. 2 :Wikipedia back to the basic

Fig. 3 : De reguliere website van de NOS …

Fig. 4: … en de mobiele variant hierop

magazine voor software development 25

Strenge selectie van contentVanwege de eenvoud van de pagina’s en het terugbrengen van hetaantal opties is de content die weergegeven wordt zorgvuldig gese-lecteerd. Wat hierbij opvalt is dat de inhoud zorgvuldig geselecteerd isvoor de gebruiker, de optimale user experience! In de ideale webwe-reld zouden alle websites op die manier ontworpen en ingericht zijn,maar omdat de meeste websites commercieel zijn, ontkom je vaakniet aan elementen die niet belangrijk zijn voor de gebruiker, zoals ban-ners. Terwijl adverteren op reguliere websites algemeen geaccepteerdis, zijn de meeste mobiele websites vrij van advertenties.

WitruimteAls je websites gaat bekijken die voor het mobiele web ontworpen zijn,zul je zien dat deze websites veel witruimte bevatten. Zeker degene diemakkelijk zijn in gebruik. Witruimte is belangrijk in ieder ontwerp en ismeestal een uitdaging in webdesign omdat er veel informatie in be-perkte ruimte aangeboden moet worden. Witruimte is nog belangrijkerin mobile webdesign omdat het scherm nog kleiner is. Een volgeproptewebsite zou erg gebruiksonvriendelijk en moeilijk te gebruiken zijn viahet mobiele web.

Gebruik van afbeeldingenDoordat de afgelopen jaren internetverbindingen steeds sneller zijngeworden, hebben de designers meer vrijheid gekregen in het gebruikvan afbeeldingen en video’s. De gemiddelde bezoeker van eenwebsite via een desktop of laptop wil graag een rijk geïllustreerde,visueel aantrekkelijke website zien. Voor ontwerp van een mobielewebsite geldt dat afbeeldingen vaak meer fout dan goed doen.Er is een grote variatie in verbindingssnelheid en kosten van mobieleinternet. Bezoekers maken zich drukker om hun verbindingssnelheidbij internet via hun mobiel. Daarnaast maakt de schermgrootte hetmoeilijk om afbeeldingen goed te zien en tekst moeilijker te lezen. Mettoename van het aantal internetters met smartphones, die grotereschermen en hogere verbindingssnelheid hebben, is er meer mogelijkvoor gebruik van afbeeldingen. Er is echter een grote groep gebruikersdie nog geen smartphone heeft. Voor mobiele versies van websites ishet daarom gebruikelijk weinig afbeeldingen te gebruiken.

Verschillende schermformatenWaar je bij het ontwerpen van een website al rekening moet houdenmet de verschillende resoluties van beeldschermen, is het bij mobieletelefoons en PDA’s een nog grotere uitdaging. Doordat de techniekzich blijft ontwikkelen, veranderen de schermafmetingen ook. Moderne

smartphones en PDA’shebben grotere scher-men en hogere resolu-ties dan die van eenpaar jaar geleden, maarde oudere zijn ook nogsteeds in gebruik. Nietalleen moet je rekeninghouden met verschil-lende resoluties, maarook met verschillendevormen. In figuur 5 iseen aantal van deze for-maten te zien.

Subdomein versus.mobi of ander apartdomeinTerwijl sommige websi-tes .mobi voor hun mo-biele versie gebruiken,is het gebruikelijker om

Fig. 5 : Veelvoorkomende schermformaten

UXINFORMATION

WORKER

Page 26: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

een subdomein te gebruiken of een aparte folder op het primairedomein. Een van de grootste voordelen hiervan is dat alles in ééndomein blijft staan.

TestenVoor het reguliere web zijn genoeg betrouwbare manieren om jewebsite te testen. Voor het mobiele web ligt dit iets anders. De kansis aanzienlijk dat de bezoekers van je website in een situatie zijn die jeniet hebt kunnen testen. Een andere uitdaging in webdesign voor hetmobiele web zijn de vele verschillende typen telefoons en PDA’s diegebruikt worden. Met een goed ontwerp en goed geplande tests ishet mogelijk om er vrij zeker van te zijn dat de website goed weerge-geven wordt en, nog belangrijker, bruikbaar is op de meeste PDA’s enmobiele telefoons. De eenvoud van je website maakt het testen al eenstuk eenvoudiger, simpelweg omdat er minder is dat mis kan gaan.Er is een aantal online en offline emulators beschikbaar waarmee jede meeste problemen al uit je website zult kunnen halen. De GoogleWireless transcoder -zie http://www.google.com/gwt/n- geeft eengoed beeld van hoe je website eruit zal komen te zien, al is deze nietzo streng en geeft-ie je website al snel redelijk weer. Ook Microsoft -zie http://www.microsoft.com/downloads/details.aspx?FamilyId=1A7A6B52-F89E-4354-84CE-5D19C204498A&displaylang=en -heeft een emulator die als Visual Studio plugin of stand alone tegebruiken is.De beste optie is waarschijnlijk een groep mensen metverschillende soorten mobile telefoons bij elkaar te zoeken voor eengoede usability test.

StandaardenEr is een aantal organisaties dat zich bezig houdt met het ontwikke-len van standaarden om websites geschikt te maken voor het mobielinternet. Het W3C heeft sinds 2005 een “Mobile Section Workgroup”.Deze werkgroep heeft in december 2008 een concept versie van best

Sandra de Ridder

Sandra de Ridder is UX en Share-Point consultant bij Sparked(www.Sparked.nl). Voor vragen enopmerkingen is Sandra te bereikenvia [email protected] is sinds kort ook actief alsmedewerker van de UX track vanhet SDN.

Make your site mobilefriendly

Mobile web trendsfor 2009

Designing and Developingmobile websites in thereal world

7 Usability Guidelines forWebsites on MobileDevices

Google WirelessTranscoder

W3C Mobile Web Initiative

Mobile Awesomeness

http://thinkvitamin.com/features/css/make-your-site-mobile-friendly/

http://www.smashingmagazine.com/2009/01/13/mobile-web-design-trends-2009/

http://dev.opera.com/articles/view/designing-and-developing-mobile-web-site/

http://www.webcredible.co.uk/user-friendly-resources/web-usability/mobile-guidelines.shtml

http://www.google.com/gwt/n

http://www.w3.org/Mobile/About

http://www.mobileawesomeness.com/

user experience van mobiel internet moeten verbeteren. Zij ontvangengraag feedback op deze best practices (zie http://www.w3.org/2005/MWI/ BPWG/).

Resources en artikelenAls je na deze het lezen van dit artikel nieuwsgierig bent gewordennaar de mogelijkheden voor webdesign voor het mobiele internet kunje op onderstaande URL’s meer informatie over mobile webdesign envoorbeelden van mobiele websites vinden. •

UXINFORMATION

WORKER

Advertentie Barnsten/ Embarcadero

Page 27: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

magazine voor software development 27

Het artikel is gebaseerd op de praktijksituatie van de salarisverwerkerSDB Groep in de zorgsector. Voor deze dienstverlener is een reken-service gerealiseerd waarmee alle salariscomponenten opnieuwworden uitgerekend zodra het werkrooster van een zorgverlener wordtgewijzigd. De overheid streeft naar zoveel mogelijk handen aan hetbed tegen zo laag mogelijke kosten, dus inzicht in de loonkosten helpteen zorginstelling om de zorgverlening optimaal te plannen. Aan heteind van elke salarisperiode worden de rekenresultaten als invoergebruikt voor de salarisverwerking.

Figuur 1 geeft de oplossing schematisch weer. Een gebruiker bewerkteen werkrooster via de webapplicatie. Dat resulteert in een databasetransactie om het gewijzigde rooster weg te schrijven. Als gevolg daar-van moeten er salariscomponenten opnieuw berekend worden. Datwordt gedaan door asynchroon een rekenservice aan te roepen die isgeïmplementeerd als een C# stored procedure in een andere data-base op een andere server om de on-line database zo min mogelijk tebelasten. In de tweede helft van dit artikel zal de oplossing stap voorstap worden toegelicht, maar nu volgt eerst enige uitleg van ServiceBroker.

Fig. 1: Schematische weergave van de oplossing

Wat is Service Broker?Service Broker is een wat minder bekend onderdeel van SQLServerdat sinds versie 2005 aan het product is toegevoegd. Menig lezer zalooit een tabel met een statusveld hebben geïntroduceerd om dit viaeen SQLServer Agent job te laten pollen om daarmee een storedprocedure te starten zodra gedetecteerd wordt dat er records zijn dieaan bepaalde condities voldoen. Dat is een scenario dat nu beter metService Broker kan worden opgelost.

Frans van der Geer enAndre van Leeuwen

Betrouwbare Services Bouwen met

SQL ServerDit artikel beschrijft hoe een service gemaakt kan worden met SQLServer ServiceBroker. WCF is tegenwoordig de standaard keuze op het Microsoft platform voorhet maken van services, maar dit artikel toont aan dat Service Broker eenserieus alternatief kan zijn voor niet publieke services. Dit artikel beschrijft degebruikte techniek: SQL Service Broker, XML data manipulatie in T-SQL en C#stored procedures in combinatie met LINQ ter implementatie van de service. Hetartikel is van toepassing op SQLServer 2005 en 2008.

Service Broker biedt de mogelijkheid om asynchroon services te latenuitvoeren via message queueing. Een service wordt geïmplementeerdmet een stored procedure die gekoppeld is aan een queue. Een queueis in feite een speciaal soort tabel met een vooraf gedefinieerd schema,waarbij de belangrijkste velden het berichttype en het bericht zelf zijn.Een service kan geïnitieerd worden door een bericht naar een service(lees: queue) te sturen vanuit een database transactie. Het verwerkenvan het bericht uit de queue wordt vervolgens in een nieuwe transac-tie gedaan door een via Service Broker geïnitieerde stored procedure.Met andere woorden: Service Broker biedt de mogelijkheid tot hetasynchroon laten uitvoeren van database transacties.

Het SELECT statement kan worden gebruikt om in een queue tekijken, maar T-SQL heeft ook uitbreidingen ondergaan. Je hebt b.v.de statements CREATE QUEUE, SEND en RECEIVE om respectieve-lijk een queue aan te maken en berichten op een queue te plaatsendan wel er vanaf te halen. Enkele voorbeelden volgen in de tweedehelft van dit artikel.

Er is locking van toepassing op berichten in de queue, zodat eenbericht pas zichtbaar wordt nadat de versturende transactiegecommit is. Service Broker kan ervoor zorgen dat een stored proce-dure automatisch gestart wordt zodra een bericht op de queue wordtvrijgegeven. Dat doet Service Broker heel efficiënt. Er wordt niet voorelk nieuw bericht een nieuwe stored procedure instantie gestart.Er wordt pas een extra instantie gestart als blijkt dat de reeds actieveinstanties het tempo waarmee berichten arriveren niet kunnen bijhou-den. De database administrator kan het maximum aantalinstanties per queue configureren, zodat er niet ongewenst veelresources gebruikt worden.

De verzendende en ontvangende service kunnen in dezelfde databasegeïmplementeerd zijn, maar ook in verschillende databases en zelfsop een andere SQLServer, zoals in figuur 1 te zien is. Een service kanbovendien worden geïmplementeerd op verschillende SQL Serverstegelijk. Een bericht zal dan round-robin worden verzonden naar eenvan de servers om daar afgehandeld te worden. Een service kan hoog

Service Broker biedt de mogelijkheidom asynchroon services te latenuitvoeren via message queueing

DATABASES.NET

Page 28: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

beschikbaar worden gemaakt door simpelweg de database hoogbeschikbaar te maken met behulp van server clustering of databasemirroring.

Waarom Service Broker?De business casus vereist dat de rekenservice asynchroon maargegarandeerd wordt uitgevoerd. Asynchroon omdat het werk van deplanner niet gehinderd mag worden door het feit dat gekozen is om bijhet opslaan van een rooster alles opnieuw te laten berekenen, engegarandeerde verwerking omdat het om echt geld en om echteverlofdagen gaat.

Eén van de eigenschappen van Service Broker is dat het lezen van dequeue of het schrijven naar de queue in dezelfde database transactiekan plaatsvinden als het manipuleren van de data in de tabellen van dedatabase. Vergelijk dat eens met een WCF service die via het MSMQtransport ook gegarandeerde message verwerking kan bieden, maaralleen in combinatie met de Distributed Transaction Coordinator. Datgeeft een veel minder goede performance dan Service Broker.Vanwege de extra benodigde componenten buiten SQLServer is dezeoplossing ook moeilijker te configureren en te beheren.

Het doorslaggevende argument om voor Service Broker te kiezenboven WCF met MSMQ is dat de berekeningen gestuurd worden doorverschillende database tabellen. Als er iets wijzigt in een van dietabellen moeten berekeningen opnieuw worden gedaan. Met ServiceBroker is dat eenvoudig te realiseren door een bericht naar een servicete sturen vanuit een database trigger.

Maar Service Broker heeft nog meer voordelen ten opzichte van WCFmet MSMQ. Wat Service Broker extra heeft ten opzichte van anderemessaging systemen is het concept van een dialoog. Als twee ser-vices met elkaar moeten gaan communiceren moet vooraf eerst eencontract worden gedefinieerd. Dat beschrijft welke berichttypen ertussen twee services uitgewisseld kunnen worden en met welkeberichttypen een dialoog kan beginnen. Service Broker dwingt af dateen dialoog tussen twee services altijd voldoet aan het contract. Deontvangende service kan er dus op rekenen dat ze altijd berichttypenontvangt die ze kan verwerken. Service Broker garandeert bovendiendat er maar één service instantie tegelijk actief kan zijn met verwer-king van berichten van dezelfde dialoog. Daarmee worden problemenmet volgordelijkheid van verwerking voorkomen. Een dialoog zoubijvoorbeeld kunnen bestaan uit het eerst versturen van een orderheader, gevolgd door het versturen van één of meer orderregels.Zonder de garantie die Service Broker biedt zou het kunnen zijn dat deeerste orderregel al wordt verwerkt door een tweede service instantieterwijl de eerste service instantie nog bezig is met de verwerking vande header. Berichten van verschillende dialogen kunnen wel paralleldoor verschillende service instanties worden verwerkt.

In sommige situaties is de garantie van volgordelijke verwerking binneneen dialoog nog niet voldoende. Kijk b.v. eens naar de praktijk van desalarisverwerker, waar een planner twee keer achter elkaar eenberekening voor dezelfde zorgverlener in dezelfde salarisperiode kanstarten door twee wijzigingen achter elkaar uit te voeren op hetzelfdewerkrooster. Elke berekening start een nieuwe dialoog met derekenservice. De salarisverwerker moet er zeker van kunnen zijn dat al-leen het rekenresultaat van de laatste situatie wordt bewaard. Dat ismogelijk met het Service Broker concept Conversation Group.Berichten van verschillende dialogen die onderdeel worden gemaaktvan dezelfde Conversation Group, zullen gegarandeerd door éénservice instantie tegelijk worden afgehandeld. Dat werkt op basis van

een Conversation Group lock, die een Service Broker serviceautomatisch vraagt zodra ze het eerste nieuwe bericht van eenConversation Group leest. Er is maar één service instantie die dezeexclusieve lock kan krijgen. Andere berichten binnen dezelfdeConversation Group blijven verborgen voor andere service instantiestotdat de ene service instantie geen berichten voor die ConversationGroup meer in de queue vindt en de lock loslaat. Er kunnen daarnanog meer berichten arriveren binnen de dezelfde conversation Group.De eerste de beste service instantie die daarvan het eerste nieuwebericht te pakken krijgt, plaatst opnieuw een lock en gaat er mee aande slag. Een Conversation Group bestaat uit niets anders dan eenunique identifier. De oplossing voor de salarisverwerker is dus om eenConversation Group Id per combinatie van medewerker en salaris-periode in de database te administreren en te zorgen dat elke dialoogmet de juiste Conversation Group Id wordt geïnitieerd.

Is SQL Server wel geschikt om complexe berekeningen tedoen?SQLServer is erg goed in setsgewijze datamanipulaties met behulpvan T-SQL, maar berekeningen die meer vergen dan een paaraggregatie functies kunnen beter in een procedurele taal wordengeschreven. De SQLCLR komt daarbij goed van pas. Stored proce-dures kunnen in C# worden geschreven en de .Net assembly kan inde database worden ondergebracht. De SQLCLR kan de code uit-voeren alsof het een T-SQL procedure is. Procedurele code is duskrachtig. Maar aan de andere kant: berekeningen op basis van eenverzameling ingeplande diensten zijn toch ook weer setsgewijs. Hetzou mooi zijn als LINQ in de database gebruikt zou kunnen wordenzodat setsgewijze expressies gecombineerd kunnen worden metingewikkelde rekenkundige expressies.

SQLServer 2005 weet niets van het bestaan van LINQ, maar LINQ isniets anders dan een compiler truc die gewone CLR 2.0 compatiblecode oplevert met referenties naar een assembly uit het .Net 3.5Framework. En de SQLServer CLR is compatible met de CLR 2.0.Dus het enige wat moet gebeuren om LINQ te ondersteunen vanuit deSQLServer CLR is het registreren van de betreffende .Net 3.5 Frame-work assembly in SQLServer. Listing 1 laat zien dat dit eenvoudig is.

use master

go

-- CLR ondersteuning aanzetten

EXEC sp_configure 'clr enabled', 1

RECONFIGURE

go

IF @@VERSION NOT LIKE 'Microsoft SQL Server 2008%'

BEGIN

-- Trustworthy setting is nodig om UNSAFE assemblies

-- te mogen gebruiken.

-- Een assembly is UNSAFE als hij afhankelijk is

-- van een assembly die niet op de trusted list staat.

ALTER DATABASE [$(TargetDB)] SET TRUSTWORTHY ON

END

go

USE [$(TargetDB)]

go

IF @@VERSION NOT LIKE 'Microsoft SQL Server 2008%'

BEGIN

28 MAGAZINE

Service Broker heeft extra het conceptvan een dialoog Door CLR is SQL Server geschikt voor

berekeningen

DATABASES.NET

Page 29: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

-- Om LINQ in de database te kunnen gebruiken is

-- onderstaande .NET 3.5 assembly nodig.

-- Omdat deze assembly nog niet op de trusted assembly

-- list staat van SQL Server 2005,

-- is de enige optie om hem in UNSAFE mode te gebruiken.

-- N.B. de $ parameter vereist dat SSMS in SQLCMD

-- mode staat (zie de button

-- met het rode uitroepteken op de toolbar)

IF NOT EXISTS(

SELECT 1

FROM sys.assemblies

WHERE name = 'System.Core')

BEGIN

CREATE ASSEMBLY [System.Core]

FROM '$(ProgramFiles)\Reference\Assemblies\

Microsoft\Framework\v3.5\System.Core.dll'

WITH PERMISSION_SET = UNSAFE

END

END

go

Listing1: Registreren van de assembly met LINQ Extension methodsin SQLServer 2005

Ten eerste moet de SQLCLR worden aangezet. Vervolgens kan deassembly worden geregistreerd. De registratie van de .Net 3.5assembly is niet nodig voor SQL Server 2008, omdat deze de beno-digde assembly standaard op zijn vertrouwde lijst met assemblies heeftstaan. Dit is niet het geval voor SQL Server 2005 en daarom moet deassembly als UNSAFE worden gemarkeerd. Een database admini-strator die daar huiverig voor is, moet zich realiseren dat deze settingsalleen nodig zijn op de SQL Server instantie die de rekenservice host.En dat is natuurlijk een andere dan waarin alle productiedata zit. Dieinstantie draait zelfs op een andere server om de primaire databaseserver niet te belasten met complexe berekeningen. Dus nog een extraSQL Server licentie erbij? Nee hoor, een gratis SQL Server ExpressEdition is voldoende mits de limiet van 1 CPU geen probleem is. SQLService Broker werkt ook volledig op een SQL Server Express Edition,mits tenminste een Standard Edition in een dialoog betrokken is. En deSQL Server met de productiedata is dat.

Vervolgens is de rekenservice in een aantal stappen gemaakt.1) Startpunt is een XML Schema met de definitie van een drietal be-

richten. Ten eerste het vraagbericht met daarin alle data die nodigis voor een berekening. Ten tweede het antwoordbericht voor derekenresultaten en ten derde een foutbericht mocht de berekeningom een of andere reden niet lukken.

2) Op basis van het XML Schema is met behulp van het utility XsdOb-jectGen [ref1] een C# objectmodel gegenereerd. Alle berekeningenzullen geschreven worden op dit objectmodel.

3) De data wordt aangeleverd als een XML stream. Om de XML omte zetten in een instantie van een objectmodel en vice versa zijnXML (de)serializers nodig. Het .Net framework kan dynamisch XML(de)serializers genereren, maar de SQLCLR ondersteunt geen dy-namisch gegenereerde code, dus in plaats daarvan zijn de seriali-zers van te voren gegenereerd met behulp van de utility XgenPlus[ref2].

4) Tenslotte is met behulp van Visual Studio 2008 een C# databaseproject gemaakt. Dit project type bevat o.a. een template voor hetmaken van een CLR stored procedure. Daarbij moet bij de eigen-schappen van het project gekozen worden voor .Net 3.5 als doel-platform; LINQ behoort dan tot de mogelijkheden.

Listing 2 toont de C# stored procedure met de code om de XML-stream naar het object model te converteren en vice versa. Daarbijwordt gebruik gemaakt van de gegenereerde XML serializer classes in

magazine voor software development 29

de namespace SDB.Mplus.Rekenserver.ObjectModel.Serializers.Het T-SQL type xml mapt op het .Net type Sys-tem.Data.SqlTypes.SqlXml. Nadat deze “plumbing” code is geschre-ven kan de daadwerkelijke implementatie van de rekenlogicagetypeerd worden uitgeschreven tegen het objectmodel dat op basisvan het XML schema gemaakt is.

using System;

using System.Data.SqlTypes;

using System.Xml;

using System.IO;

using System.LINQ;

using SDB.MPlus.RekenServer.ObjectModel;

using Helper =

SDB.MPlus.RekenServer.ObjectModel.Serializers;

public partial class StoredProcedures

{

[Microsoft.SQL Server .Server.SqlProcedure]

public static void BerekenLoonfactoren(SqlXml vraag,

out SqlXml antwoord)

{

// Creer het objectmodel uit de xml van de vraag

XmlReader reader = vraag.CreateReader();

Helper.LoonfactorBerekeningVraag.

LoonfactorBerekeningVraagSerializer vraagSerializer=

new Helper.LoonfactorBerekeningVraag.

LoonfactorBerekeningVraagSerializer();

LoonfactorBerekeningVraag vraagObject =

vraagSerializer.Deserialize(reader)

as LoonfactorBerekeningVraag;

// Bereken het antwoord

LoonfactorBerekeningAntwoord antwoordObject =

BerekenLoonfactorenImplementatie(vraagObject);

// Converteer het antwoord naar xml

Helper.LoonfactorBerekeningAntwoord.

LoonfactorBerekeningAntwoordSerializer

antwoordSerializer = new Helper.

LoonfactorBerekeningAntwoord.

LoonfactorBerekeningAntwoordSerializer();

MemoryStream antwoordStream = new MemoryStream();

antwoordSerializer.Serialize(antwoordStream,

antwoordObject);

antwoordStream.Flush();

antwoordStream.Position = 0;

antwoord = new SqlXml(antwoordStream);

}

/// <summary>

/// Type-safe implementatie van de LoonfactorBerekening

/// </summary>

private static LoonfactorBerekeningAntwoord

BerekenLoonfactorenImplementatie

(LoonfactorBerekeningVraag vraag)

{

// Implementatie code weggelaten

return new LoonfactorBerekeningAntwoord();

}

}

Listing2: C# stored procedure met XML serializatie

Om een idee te krijgen hoe vervolgens LINQ op het objectmodel leidt

DATABASES.NET

Page 30: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

tot leesbare en dus onderhoudbare code is in listing 3 een codefragment weergegeven. Deze expressie had nog prima in T-SQL uit-geschreven kunnen worden, maar het gaat om het idee.

int aantalDagenGewerkt =

(from d in vraag.DienstCollection.Cast<Dienst>()

from tb in d.TijdblokCollection.Cast<Tijdblok>()

where (tb.DienstType.TeltMeeInGewerkteUren

&& !tb.IsZiek)

select d.Datum.Date).Distinct().Count();

Listing 3: Een berekening op setsgewijze data met behulp van LINQ

Nadat de C# stored procedure is voltooid en tot een library assemblyis gecompileerd, moet hij in SQL Server worden gedeployed. Listing4 toont hoe dat moet. Eerst moet de assembly worden geregistreerden vervolgens kan een T-SQL stored procedure wrapper om de C#static methode worden gemaakt. Omdat deze assembly afhankelijk isvan de .Net 3.5 System.Core assembly en deze door SQL Server2008 wel standaard wordt vertrouwd, wordt bij het registreren van deassembly onderscheid gemaakt tussen het benodigde permissionlevel in SQL Server 2005 en 2008.

IF @@VERSION LIKE 'Microsoft SQL Server 2008%'

BEGIN

CREATE ASSEMBLY

[SDB.MPlus.RekenServer.LoonfactorBerekening]

FROM '$(RekenserverAssemblyDir)\

SDB.MPlus.RekenServer.LoonfactorBerekening.dll'

WITH PERMISSION_SET = SAFE

END

ELSE IF @@VERSION LIKE 'Microsoft SQL Server 2005%'

BEGIN

CREATE ASSEMBLY

[SDB.MPlus.RekenServer.LoonfactorBerekening]

FROM '$(RekenserverAssemblyDir)\

SDB.MPlus.RekenServer.LoonfactorBerekening.dll'

WITH PERMISSION_SET = UNSAFE

END

go

CREATE PROCEDURE dbo.BerekenLoonfactoren

(

@Vraag xml

, @Antwoord xml OUTPUT

)

-- [assembly name].[fully qualified type name].

-- [method name]

AS EXTERNAL NAME

[SDB.MPlus.RekenServer.LoonfactorBerekening].

[StoredProcedures].[BerekenLoonfactoren]

go

Listing 4: Registratie van de assembly en de C# stored procedurein SQL Server

Om deze stored procedure asynchroon via Service Broker te kunnenaansturen moet een aantal Service Broker artifacts worden gemaakt,zoals in de inleiding van dit artikel is beschreven. Listing 5 toont eengedeelte van de code aan de server zijde; het aanmaken van een aan-tal berichttypen, een contract, een queue en een service. Er is geenruimte om alles te laten zien. Wat bijvoorbeeld ontbreekt, is het makenvan een Service Broker endpoint waarmee SQL Server berichten zalontvangen, alsmede de routes waarmee een bericht naar de juisteservice wordt geleid. Dit is wel beschreven in de SQL Server BooksOnline [ref3]

IF NOT EXISTS(

SELECT 1 FROM sys.service_message_types

WHERE name = '/Rekenserver/LoonfactorBerekening/Vraag')

CREATE MESSAGE TYPE

[/Rekenserver/LoonfactorBerekening/Vraag]

VALIDATION = WELL_FORMED_XML

IF NOT EXISTS(

SELECT 1 FROM sys.service_message_types

WHERE name = '/Rekenserver/LoonfactorBerekening/Ant

woord')

CREATE MESSAGE

TYPE [/Rekenserver/LoonfactorBerekening/Antwoord]

VALIDATION = WELL_FORMED_XML

IF NOT EXISTS(SELECT 1 FROM sys.service_message_types

WHERE name = '/Rekenserver/Fout')

CREATE MESSAGE TYPE [/Rekenserver/Fout]

VALIDATION = WELL_FORMED_XML

IF NOT EXISTS(

SELECT 1 FROM sys.service_contracts

WHERE name =

'/Rekenserver/LoonfactorBerekening/DataContract')

CREATE CONTRACT

[/Rekenserver/LoonfactorBerekening/DataContract]

(

[/Rekenserver/LoonfactorBerekening/Vraag]

SENT BY INITIATOR

, [/Rekenserver/LoonfactorBerekening/Antwoord]

SENT BY TARGET

, [/Rekenserver/Fout]

SENT BY TARGET

)

IF NOT EXISTS(

SELECT 1 FROM sys.service_queues

WHERE name = 'LoonfactorBerekeningRekenQueue')

CREATE QUEUE dbo.LoonfactorBerekeningRekenQueue

-- Rekenserver moet berichten kunnen ontvangen

GRANT RECEIVE ON dbo.LoonfactorBerekeningRekenQueue

TO RekenserverUser

-- lokaal service endpoint aanmaken

IF NOT EXISTS(

SELECT 1 FROM sys.services

WHERE name =

'/Rekenserver/LoonfactorBerekening/RekenService')

BEGIN

CREATE SERVICE

[/Rekenserver/LoonfactorBerekening/RekenService]

AUTHORIZATION RekenserverUser

ON QUEUE dbo.LoonfactorBerekeningRekenQueue

(

[/Rekenserver/LoonfactorBerekening/DataContract]

)

END

-- MPlus moet messages kunnen versturen naar

-- de reken service

GRANT SEND ON

SERVICE::[/Rekenserver/LoonfactorBerekening/RekenService]

TO MPlusUser

Listing 5: Registratie van Service Broker artifacts

30 MAGAZINE

DATABASES.NET

Page 31: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

Vervolgens moet er een stored procedure worden geschreven die ge-activeerd wordt als er een bericht in de queue verschijnt. Listing 6toont deze stored procedure. De stored procedure is zo geschrevendat hij niet voor elk afzonderlijk bericht hoeft te worden geactiveerd. Alshij eenmaal is opgestart, blijft hij berichten uit de queue lezen zolangdie er nog zijn (WHILE @@ERROR = 0). Het lezen van een bericht ge-beurt via het RECEIVE statement. Met het nieuwe WAITFOR state-ment kan de maximale wachttijd worden geregeld. In het voorbeeldwordt de stored procedure beëindigd zodra er gedurende één se-conde geen nieuwe berichten meer in de queue verschijnen. Elk be-richt wordt apart transactioneel afgehandeld. Het daadwerkelijkafhandelen van het bericht wordt overgelaten aan de C# stored pro-cedure waarvoor in listing 4 een T-SQL wrapper gemaakt is.

-- xml type methoden vereisen deze setting:

SET QUOTED_IDENTIFIER ON

go

-- Deze stored procedure is bedoeld als

-- "activating" stored procedure

-- voor de queue dbo.LoonfactorBerekeningQueue.

-- Op deze queue komen alle verzoeken binnen voor

-- een loonfactorberekening.

CREATE PROCEDURE dbo.LoonfactorBerekeningRekenQueueReader

AS

BEGIN

IF @@TRANCOUNT > 0

BEGIN

RAISERROR('dbo.LoonfactorBerekeningRekenQueueReader

mag niet vanuit een transactie gestart worden', 16, 1)

ROLLBACK TRANSACTION

RETURN 1

END

WHILE (@@ERROR = 0)

BEGIN

DECLARE @DialogHandle UNIQUEIDENTIFIER

DECLARE @RequestMessage xml

DECLARE @ResponseMessage xml

DECLARE @MessageType sysname

BEGIN TRANSACTION

BEGIN TRY

WAITFOR

(

RECEIVE TOP(1)

@DialogHandle = conversation_handle,

@RequestMessage = message_body,

@MessageType = message_type_name

FROM dbo.LoonfactorBerekeningRekenQueue

), TIMEOUT 1000

IF @@ROWCOUNT = 0

BEGIN

-- Geen berichten meer in de queue

ROLLBACK TRANSACTION

BREAK;

END

-- Voor testdoeleinden:

-- SELECT @MessageType as RequestMessageType,

-- @RequestMessage as RequestMessage

IF @MessageType =

N'/SDB/MPlus/Rekenserver/

LoonfactorBerekening/Vraag'

BEGIN

EXEC BerekenLoonfactoren

@RequestMessage,

@ResponseMessage OUTPUT;

SEND ON CONVERSATION @DialogHandle

MESSAGE TYPE

[/SDB/MPlus/Rekenserver/

LoonfactorBerekening/Antwoord]

(@ResponseMessage);

END

ELSE IF @MessageType =

N'http://schemas.microsoft.com/SQL/

ServiceBroker/EndDialog'

BEGIN

-- Service initiator heeft de dialoog beeindigd.

-- Dan doen wij dat hier ook.

END CONVERSATION @DialogHandle;

END

COMMIT TRANSACTION

END TRY

BEGIN CATCH

IF XACT_STATE() = -1

BEGIN

-- huidige transactie is niet committable

-- Dit zou nooit mogen gebeuren. Gebeurt het

-- wel, dan wordt de foutmelding in de SQL Server

-- log geschreven.

PRINT ERROR_PROCEDURE()

PRINT ERROR_LINE()

PRINT ERROR_MESSAGE()

ROLLBACK TRANSACTION

END

BEGIN TRANSACTION

-- Verwerk de fout, desnoods buiten

-- de oorspronkelijke transactie om

DECLARE @FoutBericht xml;

WITH XMLNAMESPACES (DEFAULT

'http://www.sdbnieuws.nl/MPlus/Rekenserver/2008')

SELECT @FoutBericht =

(

SELECT

ERROR_NUMBER() 'ErrorNumber'

, ERROR_SEVERITY() 'ErrorSeverity'

, ERROR_STATE() 'ErrorState'

, ERROR_PROCEDURE() 'ErrorProcedure'

, ERROR_LINE() 'ErrorLine'

, ERROR_MESSAGE() 'ErrorMessage'

FOR XML PATH ('RekenserverFout')

);

SEND ON CONVERSATION @DialogHandle

MESSAGE TYPE [/SDB/MPlus/Rekenserver/Fout]

(@FoutBericht);

END CONVERSATION @DialogHandle;

COMMIT TRANSACTION

IF XACT_STATE() = 1

BEGIN

magazine voor software development 31

DATABASES.NET

Page 32: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

-- huidige transactie is wel committable

COMMIT TRANSACTION

END

END CATCH

END; -- WHILE

END

GO

GRANT EXECUTE

ON dbo.LoonfactorBerekeningRekenQueueReader

TO RekenServerUser

go

Listing 6: Stored procedure om berichten van de queue teverwerken

Tenslotte moet de stored procedure aan de queue worden gekoppelden dan is de rekenservice is klaar voor gebruik. Listing 7 laat zien hoedat moet.

ALTER QUEUE dbo.LoonfactorBerekeningRekenQueue

WITH ACTIVATION

(

STATUS = ON,

PROCEDURE_NAME = [LoonfactorBerekeningRekenQueueReader],

MAX_QUEUE_READERS = 4,

EXECUTE AS 'RekenserverUser'

)

Listing7: Stored procedure aan de queue koppelen

Daarbij kan worden gekozen om de stored procedure automatisch telaten starten zodra er een bericht op de queue verschijnt (ACTIVATION= ON). Als één instantie van de stored procedure het tempo waarmeeberichten op de queue verschijnen niet kan bijhouden, zal ServiceBroker een extra instantie starten tot het aangegeven maximum(MAX_QUEUE_READERS). Omdat de stored procedure asynchroonworden uitgevoerd, is er geen client connectie en moet er explicietvoor een security context worden gekozen m.b.v. EXECUTE AS.

De rekenserver implementeert de service, maar aan de initiërende kantis ook nog een aantal zaken vermeldenswaardig, zoals het initiërenvan een nieuwe dialoog als onderdeel van een Conversation Group(zie listing 8). De dialoog wordt gestart WITH RELATED_CONVERSA-TION_GROUP. Zoals hiervoor al is beschreven is dit om te garanderendat twee achtereenvolgende berekeningen van hetzelfde rooster indezelfde volgorde worden afgehandeld, zodat altijd het resultaat vande meest recente berekening zal worden bewaard.

DECLARE @RekenserverDialogId uniqueidentifier;

DECLARE @ConversationGroupId uniqueidentifier;

DECLARE @DienstverbandIDint;

-- niet getoond wordt hoe deze variabele een waarde krijgt

DECLARE @PeriodeID int; -- idem

DECLARE @Vraag xml;

-- Maak een conversation group voor deze combinatie

-- van periode en dienstverband. Dit voorkomt dat

-- twee Rekenserver opdrachten voor dezelfde

-- combinatie elkaar gaan 'inhalen'

EXEC Rekenserver.LoonfactorBerekening_ConversationGroupMaken

@PeriodeID = @PeriodeID

, @DienstverbandID = @DienstverbandID

, @ConversationGroupID = @ConversationGroupId OUTPUT

-- Maak een dialog voor het versturen van de vraag

BEGIN DIALOG CONVERSATION @RekenserverDialogId

FROM SERVICE [/Rekenserver/LoonfactorBerekening/DataService]

TO SERVICE '/Rekenserver/LoonfactorBerekening/RekenService'

ON CONTRACT [/Rekenserver/LoonfactorBerekening/DataContract]

WITH RELATED_CONVERSATION_GROUP = @ConversationGroupId;

-- Stel de vraag samen

EXEC Rekenserver.LoonfactorBerekening_VraagMaken

@DienstverbandID = @DienstverbandID

, @PeriodeID = @PeriodeID

, @MessageID = @RekenserverDialogId

, @Vraag = @Vraag OUTPUT

IF @Vraag IS NOT NULL

BEGIN

-- Verstuur de vraag

SEND ON CONVERSATION @RekenserverDialogId

MESSAGE TYPE [/Rekenserver/LoonfactorBerekening/Vraag]

(@Vraag);

END

ELSE

BEGIN

-- Er valt niks te versturen

END CONVERSATION @RekenserverDialogId

END

Listing 8: Start van een nieuwe dialoog als onderdeel van eenconversation group

Bij een Service Broker applicatie moet nadrukkelijk aandacht besteedworden aan foutafhandeling. Als het verwerken van een bericht vande queue vijf keer achter elkaar tot een rollback van de transactie leidt,zal Service Broker automatisch de queue disablen en dan stopt deverwerking volledig. Om dit te voorkomen moet de code zo geschre-ven worden dat het bericht linksom dan wel rechtsom kan wordenverwerkt. En simpelweg committen van de transactie is niet altijd eenoptie; SQL Server staat niet toe dat de consistentie van de databasein het gedrang komt. Listing 9 toont het foutafhandelingsgedeelte vaneen queue reader stored procedure. Met de functie XACT_STATE()wordt bepaald wat de mogelijkheden zijn.

CREATE PROCEDURE

Rekenserver.LoonfactorBerekening_DataQueueReader

AS

BEGIN

IF @@TRANCOUNT > 0

BEGIN

RAISERROR(

'Rekenserver.LoonfactorBerekening_DataQueueReader

mag niet vanuit een transactie gestart worden', 16, 1)

ROLLBACK TRANSACTION

RETURN 1

END

WHILE (@@ERROR = 0)

BEGIN

DECLARE @DialogHandle uniqueidentifier

DECLARE @ConversationGroupId uniqueidentifier

DECLARE @Message xml

DECLARE @MessageType sysname

32 MAGAZINE

Er is nadrukkelijk aandacht nodig voorfoutafhandeling bij een Service Brokerapplicatie

DATABASES.NET

Page 33: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

DECLARE @Foutmelding varchar(255)

BEGIN TRANSACTION

BEGIN TRY

WAITFOR

(

RECEIVE TOP(1)

@ConversationGroupId = conversation_group_id,

@DialogHandle = conversation_handle,

@Message = message_body,

@MessageType = message_type_name

FROM Rekenserver.LoonfactorBerekeningDataQueue

), TIMEOUT 5000

-- code met verwerking van het bericht is weggelaten

COMMIT TRANSACTION

END TRY

BEGIN CATCH

IF ERROR_NUMBER() IN (1205)

BEGIN

-- Er is een herstelbare fout opgetreden;

-- Probeer hetzelfde bericht nogmaals te verwerken

-- N.B. Error 1205 = deadlock

ROLLBACK TRANSACTION

CONTINUE

END

IF XACT_STATE() = -1

BEGIN

-- Huidige transactie is niet committable

-- Dit zou nooit mogen gebeuren. Gebeurt het wel,

-- dan wordt foutmelding in SQL Server log geschreven

SET @Foutmelding = 'Fout ' +

CONVERT(varchar(10), ERROR_NUMBER())

+ ' op regel ' + CONVERT(varchar(10),

ERROR_LINE()) + ' van procedure '

+ ERROR_PROCEDURE()

PRINT @Foutmelding

PRINT ERROR_MESSAGE()

ROLLBACK TRANSACTION

BREAK

END

ELSE

BEGIN

-- Huidige transactie is wel committable;

-- leg de foutmelding vast

UPDATE Rekenserver.LoonfactorBerekeningLog

SET Foutmelding = ERROR_MESSAGE()

WHERE SsbDialogHandle = @DialogHandle

-- breek de dialoog af

END CONVERSATION @DialogHandle;

COMMIT TRANSACTION

END

END CATCH

END; -- WHILE

END

Listing 9: Queue reader stored procedure

Tenslotte zal getoond worden hoe makkelijk het is sinds SQL Server2005 om met XML-data te werken.

Om XML-data te genereren is het SELECT statement met FOR XML

PATH clause de meest flexibele variant. Een dataveld kan als ofweleen XML-attribuut dan wel als een XML-element worden opgenomen.Het wordt een attribuut als de alias met een @ begint. Het maken vangeneste XML-elementen is met deze variant ook heel eenvoudig.Begin gewoon een geneste subselect op de plaats waar het subele-ment moet komen. De TYPE subclause in de SELECT zorgt ervoordat de data als XML-data wordt gezien en niet als tekst. Als een XML-element dieper genest moet worden dan de (sub)select die het data-veld selecteert, kan met een relatieve XPath-expressie de nestingexpliciet gestuurd worden; vandaar de naam FOR XML PATH. Listing10 toont beide technieken. Let vooral op het dieper geneste Salariselement. De XML-namespace wordt bepaald via de WITH XMLNA-MESPACES clausule.

DECLARE @Vraag xml, @MessageID uniqueidentifier;

SET @MessageID = NewId();

WITH XMLNAMESPACES

(DEFAULT 'http://www.sdbgroep.nl/MPlus/Rekenserver/2008'),

SELECT @Vraag = (

SELECT @MessageID '@Id', CURRENT_TIMESTAMP '@Timestamp',

(

SELECT DienstverbandID '@Id',

(

SELECT CaoCodeID '@Id'

, CaoCodeCode 'Code'

, CaoCodeIs4Weken 'IsVierWeken'

, CaoCodeNaam 'Naam'

, CONVERT(int, CaoCodeWerkweekUren) 'WerkweekUren'

FROM dbo.tblCaoCode

WHERE CaoCodeID = dv.fkCaoCodeID

FOR XML PATH ('Cao'), TYPE

)

, dv.DienstverbandDagenPerWeek 'DagenPerWeek'

, CONVERT(char(10), dv.DienstverbandDatumInDienst, 120)

'DatumInDienst'

, CONVERT(char(10), dv.DienstverbandDatumUitDienst, 120)

'DatumUitDienst'

, ISNULL(NULLIF(dv.DienstverbandParttimeUren,0),

cao.CAOcodeWerkweekUren) 'ParttimeUren'

, dv.DienstverbandGarantieToeslag

'Salaris/@GarantieToeslag'

, gb.CAOInpassingCodeBedrag

'Salaris/@GarantieTredeBedrag'

, dv.DienstverbandLoonToeslag

'Salaris/@LoonToeslag'

, dv.DienstverbandSalaris

'Salaris/NominaalSalaris'

FROM …

WHERE …

FOR XML PATH ('Dienstverband'), TYPE

),

Listing 10: XML genereren met SELECT FOR XML PATH

Listing 11 toont een bijpassend XML-fragment.

<LoonfactorBerekeningVraag

xmlns="http://www.sdbgroep.nl/MPlus/Rekenserver/2008"

Id="300B830A-EA57-DD11-82FF-000C294CDAD3"

Timestamp="2008-07-22T14:31:05.487">

<Dienstverband

xmlns="http://www.sdbgroep.nl/MPlus/Rekenserver/2008"

Id="3062">

<Cao

magazine voor software development 33

DATABASES.NET

Page 34: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

xmlns="http://www.sdbgroep.nl/MPlus/Rekenserver/2008"

Id="100">

<Code>4</Code>

<IsVierWeken>0</IsVierWeken>

<Naam>CAO Ziekenhuizen</Naam>

<WerkweekUren>36</WerkweekUren>

</Cao>

<DagenPerWeek>4.00</DagenPerWeek>

<ParttimeUren>23.00</ParttimeUren>

<Salaris GarantieToeslag="121.00" LoonToeslag="0.00">

<NominaalSalaris>1234.5600</NominaalSalaris>

</Salaris>

<Soort>PT</Soort>

</Dienstverband>

</LoonfactorBerekeningVraag>

Listing 11: XML naar aanleiding van de SELECT uit listing 10

De gegenereerde XML wordt vervolgens naar de rekenservicegestuurd en die komt uiteindelijk met een XML-antwoord. Dat XML-antwoord kan vrij eenvoudig weer tot een resultset worden omge-vormd met behulp van de ingebouwde functies op het XML-datatype(zie listing 12). Met de nodes() functie wordt een XML-nodelist ge-maakt. Vervolgens worden de waarden uit elke node geselecteerd metde value() functie. De resultset kan tenslotte gewoon worden gejoinedaan andere tabellen.

DECLARE @Antwoord xml;SET @Antwoord = '<LoonfactorBerekeningAntwoordxmlns="http://www.sdbgroep.nl/MPlus/Rekenserver/2008"Id="300B830A-EA57-DD11-82FF-000C294CDAD3"Timestamp="2008-07-22T14:31:05.487"><VariabeleMutatie>

<DienstverbandId>5031</DienstverbandId><KaartSoort>5</KaartSoort><LoonfactorCode>093</LoonfactorCode><PeriodeId>463</PeriodeId><Waarde>4</Waarde>

</VariabeleMutatie><VariabeleMutatie>

<DienstverbandId>5031</DienstverbandId><KaartSoort>5</KaartSoort><LoonfactorCode>094</LoonfactorCode><PeriodeId>463</PeriodeId><Waarde>1</Waarde>

</VariabeleMutatie></LoonfactorBerekeningAntwoord>';

WITH XMLNAMESPACES('http://www.sdbgroep.nl/MPlus/Rekenserver/2008' as rs)

SELECTvm.KaartSoort, vm.Waarde, vm.DienstverbandId, lf.LoonfactorID, vm.KostenPlaatsId, vm.KostenSoortId, vm.PeriodeId

FROM(

SELECTvm.value('(rs:DienstverbandId)[1]', 'int')

as DienstverbandId, vm.value('(rs:KaartSoort)[1]', 'int')

as KaartSoort, vm.value('(rs:KostenSoortId)[1]', 'int')

as KostenSoortId, vm.value('(rs:KostenPlaatsId)[1]', 'int')

as KostenPlaatsId, vm.value('(rs:LoonfactorCode)[1]', 'varchar(3)')

as LoonfactorCode, vm.value('(rs:PeriodeId)[1]', 'int')

as PeriodeID, vm.value('(rs:Waarde)[1]', 'numeric(7,2)')

as [email protected]('/rs:LoonfactorBerekeningAntwoord/rs:VariabeleMutatie')

VariabeleMutaties(vm)) as vmINNER JOIN dbo.Loonfactor lfON lf.LoonfactorCode = vm.LoonfactorCode

Listing 12: Het omzetten van een XML-fragment tot een relationeleresultset

ConclusieIn dit artikel hebben we laten zien dat SQL Server 2005 of 2008 eenuitstekend platform is om services te bouwen die dicht tegen dedatabase aanliggen. Service Broker heeft geen op webservicestandaard gebaseerde interfaces zoals WCF, dus is niet geschikt alspublieke service. Maar de transactionele, betrouwbare en zeer snelleservices die gemaakt kunnen worden met Service Broker zijn uitste-kend geschikt als service achter de schermen. De SQLCLR maakt hetmogelijk om die services gewoon met het vertrouwde en krachtige.Net framework te realiseren. De nieuwste T-SQL mogelijkhedensluiten daar naadloos op aan.

Referenties• [ref1] XsdObjectGen: hulpmiddel om op basis van een XML

Schema een C# object model te genereren. Te downloaden via:http://www.microsoft.com/downloads/details.aspx?FamilyID=89E6B1E5-F66C-4A4D-933B-46222BB01EB0&displaylang=en

• [ref2] XgenPlus: hulpmiddel om XML Serializers te genereren opbasis van een .Net object model. Te downloaden via:http://www.codeplex.com/xgenplus

• [ref3] How To: Activate Service Broker networking:http://msdn.microsoft.com/en-us/library/ms166113.aspx •

34 MAGAZINE

Frans van der Geer

Frans van der Geer is werkzaam alssoftware architect bij VX Companyin Baarn en kan worden bereikt viae-mail op [email protected] is specialist in op SQLServeren Biztalk Server gebaseerdeoplossingen.

Andre van Leeuwen

André van Leeuwen is werkzaam alssoftware engineer bij SDB Groep teLeidschendam en kan wordenbereikt via e-mail op [email protected]. André is specialist insalarisverwerking op het Microsoftplatform.

DATABASES.NET

Page 35: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

Advertentie Bergler Nederland b.v.

Page 36: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

SDNM

Ad vd Lisdonk 1997 – 2005 (nrs. 43 t/m 84)

… Toen ik als lid bij het SDN – destijds nog CDGN geheten - kwam, kon je voor heel

veel geld een extreem dure computer aanschaffen met wel 1 Mb geheugen. Alleen

jammer dat standaard geen enkel programma met zoveel geheugen overweg kon.

Nachtenlang zat ik dan ook te ploeteren op linkers als ExoSpace en Blinker die

geheugen konden aanspreken boven de 640Kb.

… Toen ik bij de redactie begon, bestonden CDen DVD nog niet en programma’s

leverde je uit op 720Kb diskettes (als je er een gaatje in boort dan kan je er 1,44 Mb

opzetten!). Netwerken begonnen op te komen in een zakelijke omgeving. Ik ben dan

ook twee keer naar hetzelfde CDGN-seminar geweest over het programmeren voor

een netwerkomgeving. Pas na de tweede keer dacht ik aardig het verschil te begrij-

pen tussen optimistic en pessimistic locking.

… Toen ik in het bestuur zat, begon Windows te winnen, kwam Delphi onze club ver-

sterken en bleek VO toch wel erg complex voor de meeste Clipperaars. We kregen

kortom meer talen en technieken die een eigen network verdienden. Ik kan mij de in-

troductie van het Microsoft Office Network bijvoorbeeld nog herinneren. Een Micro-

soft hotshot kwam zijn verhaal doen en had wat last van gemoruit de zaal over de

stabiliteit van Windows. Hij zei toen: “Zolang je geen programma opstart, crasht

Windows niet. Windows is dus stabiel. Het probleem zit ‘m in de programma’s die

jullie schrijven”. Het is minder dan twintig jaar geleden dat ik besloot om IT te gaan

doen. D’r zal wel gewoon veel gebeurd zijn in die korte tijd!

Ernst Peter Tamminga1989 – 1995 (nrs. 1 t/m 29)Vanaf het eerste moment van de PC heb ik mij ertoe aangetrokken

gevoeld. Iedereen zijn eigen werkstation, maximaliseer productiviteit.

Waren er oorspronkelijke allerlei vragen over compatibiliteit van klonen

(van de IBM PC) - die je met Flight Simulator kon testen (waar een

Microsoft spel al niet goed voor is) -, verscheen er vervolgens de

discussie tussen Token Ring and Ethernet netwerken, de strijd tussen

Windows en OS/2 en de strijd tussen de programmeertalen Turbo

Pascal, C++, Visual Basic en Clipper.Was de CDGN destijds nog de basis voor het Clipper-succes in

Nederland, toch kunnen we nu wel zeggen dat die strijd zeker door

Clipper is verloren. De grote wereld is nu .NET en Java, met een aan-

tal kleinere spelers in de marge. Maar hypes blijven … client/server,

3-tier, multi-tier, object oriented, client based, web based, web 2.0,

code reuse, code generation, service oriented, cloud computing, enz.

De SDN is, als professionele organisatie, met de tijd meegegaan. Des

te bijzonderder om te zien dat een aantal mensen van het eerste uur

(Joop, Rob) nog steeds actief zijn in de SDN. Ik heb ze ouder zien wor-

den, heb meer mensen zien komen en gaan, maar een vaste kern is

blijven bestaan. Waren de bestuursvergaderingen in den beginne nog

vaak bij iemand thuis, toch hebben we moeten besluiten om buiten

de deur te vergaderen, omdat de discussies nogal eens hoog oplie-

pen. Zoals die keer in hotel Oud-Leusden, toen we door de manager

van het restaurant naar een afgesloten kamer werden gedirigeerd,

omdat de andere gasten zich stoorden aan ons ‘gespreks’-volume.

Ik ben benieuwd of het nog steeds zo hoog kan oplopen …

Page 37: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

SDN

MAGAZINE

EDITIE

MAGAZINE

EDITIE

100

Ton Hofstede 1995 – 1997 (nrs. 30 t/m 42)1 Gb = 1.000.000 KbWaar we nu met een gemiddelde 2.4 Gb verbinding gegevens over het internetsturen ging dat in de oude dagen met 2400 Kb via een inbelverbinding per modem(à 0.15 NLG per minuut na 19:00 uur) naar het HEKOM-BBS. Als je geluk had tenminste ...Was het erg druk, en dat was het meestal in de laag-tarief avonduren, dan viel je terug op 1200Kb of soms zelfs 300 Kb. Wilde je een update downloaden, dan belde je ’s nachts in en ging jelekker naar bed. Als je geluk had en de verbinding was gedurende de nacht niet spontaan ver-broken door een stroomdipje, dan had je de volgende ochtend je bestandje binnengekregen.Datsoort tijdseenheden waren er ook bij het compileren. Vanuit je Rmake-scriptfile duurde het zo’nanderhalf uur, waarin je mooi even naar de Albert Cuyp markt kon lopen om een broodje haringte halen. Een voordeel was wel dat je leerde programmeren. Even via trial-and-error testen ofeen enkele programmaregel correct was, liet je wel uit je hoofd. De hele ochtend stug door-werken en zonodig in de (papieren) handleiding bladeren om pas na de middagpauze (yep, van1.5 uur compileren) te kunnen zien waar je geblunderd had. Als je tenminste een Debugger hadmeegelinkt en extra testfuncties handmatig had toegevoegd.Je middagfouten kon je dan de volgende ochtend weer bestuderen …

Mark Blomsma 2005 – 2005 (nrs. 85 t/m 86)

2005 was het jaar van .NET 2.0, Visual Studio 2005 en Delphi 2005. WCF, WPF en WF bestonden nog

niet. Team System, WebServices, ClickOnce Deployment, ASP.NET 2.0 (zonder AJAX), Mobile Apps en

Unit Testen waren hot topics. DotNetNuke begon aardig populair te worden en in 2005 is www.sdn.nl in

een nieuw jasje gestoken en opgezet op basis van DNN 2.0. C# en VB.NET waren in een talenoorlog

verwikkeld en ik kan me herinneren dat we op de SDC een sessie hadden met als title ‘Battle of the

Languages’. Generics en anonymous methods waren nieuwe features die .NET developers volop bezig

hielden en ASP.NET developers waren zeer in hun nopjes met personalization, en met name masterpages

waren een coole, nieuwe feature van ASP.NET 2.0. Zaken die inmiddels alweer lang en breed ‘gewoon’

zijn … Al met al een mooi jaar!Remi Caron 2005 – heden (nrs. 87 t/m 100)

Hoewel ik (pas) sinds 2006 voorzitter ben van deze software-community ben ik al wel heel lang betrok-

ken bij de organisatie. Toen mij werd gevraagd om voor dit nummer een anekdote te leveren was het

moeilijk er een te kiezen, maar dan deze maar ...

Het betreft de SDC 2002 (als ik het mij goed herinner); twee van onze sprekers - wie anders dan Steve

Forte & Richard Campbell – zouden een Geek Night sessie verzorgen. De heren hadden in de dagen

ervoor met regelmaat geklaagd over het eten in Nederland en met name het gebrek aan hamburgers

ergens gedurende de dag! Jan van der Graaff, jaren lang onze hoofdredacteur, werd op een missie

gestuurd. “Ga naar Mc Donalds en haal 2 stuks van iedere hamburger die op het menu staat”. Ongeveer

15 minuten na aanvang van de sessie komt Jan met de hamburgers binnen en overhandigt ze aan Steve

& Richard. De heren tonen zich sportief, verslinden de hamburgers om beurten … terwijl de sessie

gewoon blijft doorgaan en als vanouds door het publiek hoog gewaardeerd wordt.

Page 38: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

MAGAZINE

.NETC#

BasispaginaOm webparts mogelijk te maken in een webpagina is het van belangeen aantal extra besturingselementen op te nemen in een standaardpagina. In de onderstaande afbeelding een voorbeeld van een paginamet een aantal besturingselementen in ontwerpmodus.

Fig. 1

Opvallend is dat de pagina een aantal zones heeft waarin eenwebparts geplaatst zijn. Deze zones bieden de ontwikkelaar demogelijkheid om de gebruiker van de toepassing een standaardindeling te geven. Door verschillende templates aan te bieden kun jegebruikers op eenvoudige wijze behulpzaam zijn bij het werken metzones. Standaard zijn een webpart-zone en een webpart-manager deminimum vereiste voor een pagina. De webpart-manager zorgt alseen soort hub voor al het gedrag van de webpart-zones en dewebpart-besturingselementen. Op een pagina met webparts moet éénwebpart-manager voorkomen.De webpart-zone is een container die gedrag toevoegt aan dewebparts die binnen deze zone voorkomen. Zo kun je een zone maken

Bert Dingemans

Fun met WebParts in ASP.NetDeel 1: Basis WebpartsInleidingWebparts zijn een nieuw soort besturingselementen in webapplicaties, geïntroduceerd door Microsoft inASP.Net sinds versie 2.0. Webparts zijn vooral bekend vanwege de toepassing binnen Sharepoint enMOSS. In deze twee platformen zijn webparts één van de mogelijkheden om eenvoudig toegang tekrijgen tot legacy systemen.Echter ook in maatwerk ASP.Net applicaties zijn webparts “fun”. In een moderne webtoepassing is hetmeer en meer gebruikelijk dat gebruikers een eigen indeling kunnen maken van hun “eigen pagina”.Kijk naar sites als hyves.nl en de verschillende elementen lijken verdacht veel op webparts.In dit artikel gaan we in op een aantal basisaspecten van webparts en behandelen we naast de opzetervan een manier om webparts te genereren op basis van een domeinmodel. De webparts zijn ontwik-keld in C#. Dat is voor mij niet mijn dagelijkse programmeertaal (dat zijn Vulcan.Net en VB.Net). Redenom hiervoor te kiezen is het feit dat binnen Sharepoint installatie van webparts die niet geschreven zijnin C#, lastig is. De webparts zijn op deze wijze in een handomdraai geschikt te maken voor Sharepoint.

waarop men een aantal ‘samenvatting’-webparts kan plaatsen. Inonderstaande code een voorbeeld van een webpart-manager en eenwebpart-zone:

<asp:WebPartManager id="WebPartManagerDRG"

runat="server">

</asp:WebPartManager>

<asp:WebPartZone id="WebPartZoneLinks"

runat="server"

EmptyZonetext="Voeg hier een webpart toe"

Height="100px"

Font-Names="Verdana"

Padding="1"

ShowTitleIcons="true"

AllowLayoutChange="true"

EditVerb-Visible="true"

EditVerb-Enabled="true"

WebPartVerbRenderMode="TitleBar"

LayoutOrientation="Vertical" >

<EditVerb text="Bewerken"

Description="Pas de instellingen aan" />

<DeleteVerb text="Verwijder"

Description="Verwijder het element" />

<MinimizeVerb text="Minimaliseren"

Description="Verklein element"/>

<ConnectVerb text="Verbinden"

Description="Verbind element" />

<RestoreVerb text="Maximaal"

Description="Maximaliseer element" />

</asp:WebPartZone>

Op basis van de eigenschappen is een zone-part op maat te makenmet eigen opmaak en meldingen van de diverse opdrachten engebeurtenissen. Aardig is dat ook de woorden en toelichtingen bij deverschillende opdrachten aangepast kunnen worden, zodat dezespecifiek gemaakt kunnen worden voor de eigen toepassing.In de voorbeeldtoepassing is de pagina default2.aspx te vinden metdaarin een compleet uitgewerkte pagina met drie zones.

38

Page 39: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

Naast de zones is het wenselijk dat een gebruiker van de toepassingde pagina kan gebruiken (bekijken) maar ook kan ontwerpen enbeheren. Met de optie ontwerpen kun je webparts van de ene zonenaar de andere verplaatsen om zo een logische indeling te krijgen. Bijbewerken komt er in het menu van een webpart de optie ‘bewerken’te voorschijn. Hiermee kan een aantal instellingen van het webpartveranderd worden. In figuur 2 zie je een voorbeeld van de pagina.

Fig. 2

Als laatste is er de catalogus-modus. Hiermee is het mogelijk omwebparts vanuit een lijst van beschikbare webparts toe te voegen aanéén van de zones.Voor al deze verschillende pagina-functionaliteiten zijn zonesaanwezig. In onderstaande code is één voorbeeld uitgewerkt; deandere zones zijn opgenomen in de voorbeeldapplicatie.

<asp:CatalogZone

runat="server" id="CatalogZoneDRG"

Height ="200px" Width="400px"

BackColor="#F7F6F3"

BorderColor="#CCCCCC" BorderWidth="1px"

Font-Names="Verdana" Padding="6">

<ZoneTemplate>

<asp:DeclarativeCatalogPart

runat="server" id="catalogDrg">

<WebPartsTemplate>

<DRGwebpart:DRGMedewerker

id="DRGMdw" runat="server" title="Mdw" />

<DRGwebpart:DRGProject

id="DRGProj" runat="server" title="Project"/>

<DRGwebpart:DRGOrganisatie

id="DRGOrg" runat="server" title="Org." />

<DRGwebpart:DRGPrs

id="DRGPrs" runat="server" title="Prs" />

</WebPartsTemplate>

</asp:DeclarativeCatalogPart>

</ZoneTemplate>

</asp:CatalogZone>

In het voorbeeld is te zien hoe van de catalogus verschillende eigen-schappen in te stellen zijn voor de eigen toepassing. Daarnaast is indeze zone de lijst van beschikbare webparts opgenomen.

Instellen van de verschillende scherm-modi is mogelijk door dewebpart-manager aan te passen. In de voorbeeldtoepassing wordtdit eenvoudig opgelost door het scherm te openen met een bepaaldequerystring.

magazine voor software development 39

public partial class Default2 : System.Web.UI.Page{protected void Page_Load(object sender, EventArgs e){if (!IsPostBack){switch (Request.QueryString["instellen"]){case "DesignDisplayMode":{WebPartManagerDRG.DisplayMode =WebPartManager.DesignDisplayMode;

break;};case "BrowseDisplayMode":{WebPartManagerDRG.DisplayMode =WebPartManager.BrowseDisplayMode;

break;};case "EditDisplayMode":{WebPartManagerDRG.DisplayMode =WebPartManager.EditDisplayMode;

break;};case "CatalogDisplayMode":{WebPartManagerDRG.DisplayMode =WebPartManager.CatalogDisplayMode;

break;};case "ConnectDisplayMode":{WebPartManagerDRG.DisplayMode =WebPartManager.ConnectDisplayMode;

break;};

};};

}}

Basis-webpartDe voorbeeldtoepassing is zodanig opgezet dat de specifiekewebparts zo weinig mogelijk gedrag bevatten, nl. door het instellenvan een aantal eigenschappen en het definiëren van de besturings-elementen die in het webpart getoond moeten worden. In het eerstecodevoorbeeld is de definitie van de class en het instellen van eenaantal eigenschappen opgenomen:

using System;

using System.Data;

using System.Configuration;

using System.Web;

using System.Web.Security;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

using System.Web.UI.HtmlControls;

using System.Collections.Specialized;

using System.Collections;

namespace DRG.Webparts.Controls

{

public class DRGOrganisatie : DRGAbstractWebpart

{

public DRGOrganisatie()

{

this.insertcommand = "INSERT INTO [Organisatie]

( [bezoekadres],[bezoekplaats],

[bezoekpostcode],[email],

.NETC#

Page 40: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

[organisatie_naam],[organisatie_soort],

[postadres],[postplaats],[postpostcode],

[telefoon],[website] )

VALUES (

'#bezoekadres#','#bezoekplaats#',

'#bezoekpostcode#','#email#',

'#organisatie_naam#','#organisatie_soort#',

'#postadres#','#postplaats#','#postpostcode#',

'#telefoon#','#website#' )";

this.updatecommand = "UPDATE [Organisatie] SET

[bezoekadres] = '#bezoekadres#',

[bezoekplaats] = '#bezoekplaats#',

[bezoekpostcode] = '#bezoekpostcode#',

[email] = '#email#',

[organisatie_naam] = '#organisatie_naam#',

[organisatie_soort] = '#organisatie_soort#',

[postadres] = '#postadres#',

[postplaats] = '#postplaats#',

[postpostcode] = '#postpostcode#',

[telefoon] = '#telefoon#',

[website] = '#website#'

WHERE [organisatie_id] = #organisatie_id# ";

this.deletecommand = "DELETE FROM [Organisatie]

WHERE [organisatie_id] = #organisatie_id# ";

this.selectcommand = "SELECT

[bezoekadres], [bezoekplaats],

[bezoekpostcode], [email],

[organisatie_naam], [organisatie_soort],

[postadres], [postplaats], [postpostcode],

[telefoon], [website]

FROM [Organisatie]

WHERE [organisatie_id] = #organisatie_id# ";

}

}

Het voorbeeld laat zien dat het webpart overerft van DRGAbstract-Webpart. In deze abstracte klasse is de generieke functionaliteitopgenomen, waarover in de volgende paragraaf meer. In deconstructor wordt gedefinieerd wat de verschillende SQL-statementszijn die bij dit specifieke webpart horen. In een volgende versie van hetwebpart schreeuwt dit vanzelf om een XML file dat deze instellingenopslaat en inleest in het webpart.

In de CreateChildControls-methode van het webpart worden deverschillende besturingselementen gedefinieerd voor dit webpart. Inonderstaande sourcecode een voorbeeld (in de applicatie zijn eenviertal webparts in detail uitgewerkt):

protected override void CreateChildControls()

{

NameValueCollection para = new NameValueCollection();

DRGHelper objHelper;

objHelper = new DRGHelper();

this.creerStandaardControls();

DropDownList organisatie_id =

ControlFactoryHelper.CreateDropDownList(

this.Controls, "organisatie_id", "", 400);

objHelper.Sql2ListControl(

"SELECT ORGANISATIE.organisatie_id as valuecolumn

, ORGANISATIE.organisatie_naam as displaycolumn

FROM ORGANISATIE UNION

SELECT 0, '--Maak uw keuze--'

FROM WebDefault ORDER BY 2",

organisatie_id,

"valuecolumn", "displaycolumn", para);

ControlFactoryHelper.CreateTextBox

(this.Controls, "bezoekplaats", "",500);

ControlFactoryHelper.CreateTextBox

(this.Controls, "postadres", "",500);

ControlFactoryHelper.CreateTextBox

(this.Controls, "postpostcode", "",100);

this.toevoegenControlProperty(new

DRGControlProperty("organisatie_id",

"Organisatie", false, false, "Supply"));

this.toevoegenControlProperty(new

DRGControlProperty("organisatie_naam",

"Organisatie naam", false, false, "Modify"));

this.toevoegenControlProperty(new

DRGControlProperty("bezoekadres",

"Bezoekadres", true, false, "Modify"));

ChildControlsCreated = true;

}

Eerst worden de verschillende besturingselementen aangemaakt;hiervoor is een helper klasse beschikbaar, waarover later meer. Daarnaworden voor deze controls elementen van het type DRGControlPro-perty toegevoegd aan een arraylist binnen de abstracte klasse. Dezehelper klasse wordt in de generieke klassen gebruikt om gedrag teactiveren wanneer gewenst.

Generieke en helper-classesDe eerste helper-klasse is een factory voor besturingselementen welkeervoor zorgt dat een besturingselement op de juiste wijze wordtgecreëerd. Als voorbeeld is de methode opgenomen die een multline-edit aanmaakt:

static public TextBox CreateMultiLineTextBox(

System.Web.UI.ControlCollection controls,

String ID, String tooltip, Int16 width)

{

TextBox control = new TextBox();

control.ID = ID;

control.ToolTip = tooltip;

control.Width = width;

control.Height = (width / 3);

control.TextMode = TextBoxMode.MultiLine;

controls.Add(control);

return control;

}

De code is rechttoe rechtaan: er wordt een besturingselement vanhet juiste type aangemaakt en vervolgens wordt een aantal eigen-schappen ingesteld en wordt deze toegevoegd aan de controls-col-lection van het webpart. Als returnwaarde wordt de aangemaaktecontrol gebruikt. Dit maakt het mogelijk om specifiek gedrag aan eenbepaalde control toe te voegen. In het voorbeeld van het basisbesturingselement zie je hoe dit wordt gedaan bij een keuzelijst. Hier-bij maakt de ControlFactory een keuzelijst aan en vervolgens zorgt despecifieke code ervoor dat het juiste SELECT-statement wordtgekoppeld aan de juiste keuzelijst.

Een andere routine die in de ControlFactory-klasse is opgenomen,handelt af dat een dataset wordt omgezet naar de waardes in één ofmeer besturingselementen. In het codevoorbeeld hieronder is een deelvan de routine opgenomen; in de voorbeeldtoepassing is de completecode te vinden.

40 MAGAZINE

.NETC#

Page 41: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

static public void Dataset2Controls(DataSet ds,System.Web.UI.ControlCollection controls)

{String varType;if (ds.Tables.Count == 1){

DataTable objTable = ds.Tables[0];if (ds.Tables[0].Rows.Count > 0){

DataRow objRow = objTable.Rows[0];foreach (Control webcontrol in controls){

varType =webcontrol.GetType().ToString().ToUpper();

switch (varType){

case "SYSTEM.WEB.UI.WEBCONTROLS.TEXTBOX":{

TextBox objTB = (TextBox)webcontrol;if (ColumnNameExists(

objTable.Columns, objTB.ID)){

objTB.Text = objRow[objTB.ID].ToString();};break;

};case "SYSTEM.WEB.UI.WEBCONTROLS.DROPDOWNLIST":{

DropDownList objTB =(DropDownList)webcontrol;

if (ColumnNameExists(objTable.Columns, objTB.ID))

{objTB.Text = objRow[objTB.ID].ToString();

};break;

};…

};};

};};

}

Via de switch-case wordt de waarde van een rij in een datatable ge-koppeld aan een waarde van een besturingselement. De foreach loopzorgt ervoor dat alle besturingselementen gecontroleerd worden. Hetkan natuurlijk zijn, dan een besturingselement niet is gekoppeld aaneen waarde uit de database. In dat geval zal de waarde niet gekoppeldworden, omdat de ColumnNameExists functie niet afgaat.

In de onderstaande code is een voorbeeld van een methode te zien diein een andere helper-klasse geïmplementeerd wordt.

public void Sql2ListControl(string sql,

ListControl control, string valueField,

string displayField, NameValueCollection colPara)

{

DataSet objDS;

sql = this.verwerkParameters(sql, colPara);

objDS = this.Statement2DataSet(sql);

if (objDS.Tables.Count > 0)

{

control.DataSource = objDS;

control.DataValueField = valueField;

control.DataTextField = displayField;

control.DataBind();

};

}

De code laat zien dat een SQL-statement wordt omgezet naar eendataset en dat de datatable afkomstig vanuit de aangemaaktedataset gebruikt wordt als vulling van een keuzelijst besturingselement.Reden om dit soort functionaliteit te plaatsen in een abstracte klasseis dat de toestand van een eigenschap kan veranderen via de eigen-schap errorMelding.

Naast het gebruik van een helper-klasse is het werken met overervingin het geval van webparts erg handig. Onder een helper-klasse verstaik trouwens een klasse met alleen maar static methods zodat die nietgeïnstantieerd kan worden tot een object. Eigenlijk kan een helper-klasse gezien worden als een half object. Een object bestaat normaaluit status en gedrag; een statische klasse bestaat enkel uit gedrag(dat de status van andere objecten kan aanpassen).Is wel de combinatie van status en gedrag gewenst, dan is hetgebruik van overerving vaak een middel om hergebruik teintroduceren. In figuur 3 hieronder is te zien hoe overerving enstatische klassen gecombineerd gebruikt kunnen worden.

Fig. 3

In de abstracte klasse kan generieke code geplaatst worden welke destatus van het webpart of de status van de besturingselementenbinnen het webpart aanpassen. Ook kun je in een abstracte klasseevents plaatsen die op generieke wijze reageren op acties van degebruikers. Als voorbeeld de code hieronder:

protected void verwerk_supply(

Object sender, EventArgs e)

{

NameValueCollection para = new NameValueCollection();

String sql = "";

DRGHelper objHelper = new DRGHelper();

DataSet ds;

para = ControlFactoryHelper.Controls2Collection(

this.Controls);

if (this.soortMutatie.Text == "Muteren")

{

sql = this.selectcommand;

sql = objHelper.ProcessStatement(sql, para);

ds = objHelper.Statement2DataSet(sql);

ControlFactoryHelper.Dataset2Controls(

ds, this.Controls);

};

}

In onze webparts komt een aantal standaard besturingselementenvoor (bijvoorbeeld soortMutatie) waarmee je instelt welke bewerking opde gegevens uitgevoerd wordt. In het voorbeeld is te zien hoe op basisvan de helper-klasse de controls worden omgezet naar een naam-waarde collection. Deze wordt gebruikt om een SQL-statement te

magazine voor software development 41

.NETC#

Page 42: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

parametriseren met waarden zoals ingevuld in de besturingselemen-ten. Vervolgens wordt het SQL(SELECT)-statement omgezet naar eendataset. De waarden uit deze dataset worden gekoppeld aan deeigenschappen van de controls. Hiermee is een round trip van controlsnaar database en weer terug naar de controls gerealiseerd.In de onderstaande afbeelding is een en ander te zien. Na het klikkenop de knop kiezen gaat bovenstaande source code af. Omdat alleende waarde van de eerste keuzelijst relevant is voor het SELECT-state-ment wordt op correcte wijze het juiste besturingselement gebruiktvoor het instantieren van het SELECT-statement. Omdat de namenvan de besturingselementen overeenkomen met de kolomnamen inde resultset van het SELECT-statement, worden vervolgens de juistebesturingselementen gevuld met waarden uit de resultset.

Fig. 4

Genereren van webpartsUit dit artikel blijkt dat een webpart bestaat uit een groot generiek deelen een klein specifiek deel. Het specifieke deel wordt gebruikt omcollecties van eigenschappen te instantiëren met specifieke waarden.We kunnen echter nog een stap verder gaan. Het specifieke deel kanvanuit een CASE tool gegenereerd worden, hierdoor kun je op basisvan datamodellen zeer snel één of meerdere webparts genereren.Omdat de webparts in gedrag generiek zijn werken alle specifiekewebparts op een zelfde wijze.De CASE tool DLA-Work in Process bevat de mogelijkheid om eendomein- of datamodel om te zetten naar source code in een webpart.In figuur 5 is te zien hoe in een repository wordt opgegeven waarinspecifieke eigenschappen aangepast worden.

Fig. 5

De CASE tool maakt het voor een gebruiker mogelijk om snel eneenvoudig door het domeinmodel te navigeren, maar nog belangrij-ker is het dat de tool structuur biedt en validaties uitvoert zodat een

inconsistent objectmodel vrijwel niet mogelijk is. Is het domeinmodelgereed, dan kan er eerst een database-structuur aangemaakt wordenvoor SQL-Server of MS-Access. Daarna kan het webpart wordengegenereerd. Dit wordt gedaan op basis van een template zodat eigengedrag later toegevoegd kan worden aan het webpart. In deafbeelding hieronder is te zien hoe een genereerscherm van eenwebpart er uitziet.

Fig. 6

SamenvattingIn dit artikel is ingegaan op de basismogelijkheden van webparts.Webparts zijn niet alleen interessant binnen Sharepoint maar zekerook binnen ASP.Net webtoepassingen. Bij het gebruik van webpartsis het gebruik van helper-klasses en overerving een belangrijkhulpmiddel voor het implementeren van hergebruik en het zorgen datspecifieke sourcecode minimaal is en alleen gebruikt wordt voor hetaanroepen van generieke functies binnen de generieke modulen. Doorhet gebruik van een CASE tool is het verder mogelijk om het specifiekedeel van de code uit een repository te genereren. Hierdoor wordt hetmaken van webparts bijzonder eenvoudig. Een freeware versie van deCASE tool DLA Work in Process is te vinden op de website www.dla-os.nl. Bij het artikel hoort een voorbeeldtoepassing die gebruikt kanworden in Visual Studio 2008. In volgende artikelen over webparts zalik ingaan op het koppelen van webparts aan elkaar en het gebruikvan datagrids en andere besturingselementen voor Master-Detailwebparts. •

42 MAGAZINE

Bert Dingemans

Bert is als software architect werk-zaam binnen de maatschap FreeIT,een maatschap van ICT professio-nals. Bert heeft een voorliefde voorModel Driven Development en hetgenereren van software. Zo heeft hijCASE tools ontwikkeld in Visual Ob-jects als DLArchitect en DLA Work

in Process. Er zijn freeware versies van deze tools beschikbaarop de dla-os website. Bert heeft een weblog op www.dla-os.nl.

UX TIP:Leren omgaan met Expression Blend?Iedereen die met WPF of Silverlight begint zal vroeger of latermet Expression Blend aan de slag gaan. Er zijn diverse manie-ren om het te leren maar één manier is een online cursus vanbijna 4 uur van Lynda.com. Op de website is een complete gra-tis cursus Getting Started with Expression Blend te vinden. Ziehttp://movielibrary.lynda.com/html/modPage.asp?ID=384.

.NETC#

Page 43: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

GENERAL

Newton’s first lawNow, let’s add some physics. Back in 1687 Isaac Newton stated histhree laws of motion. The first law nicely describes the current state ofmost titanic projects. It states: “A body continues to maintain itsuniform motion unless acted upon by an external unbalanced force."Here, if you replace body by project, titanic projects will never stopunless something really drastic occurs. “We have already invested 25million Euro’s in this project, we cannot afford to stop now!” prowls theeager program manager.Well, that was then, and this is now. We now do have an externalunbalanced force. It’s called the financial crisis. For the majority, thesetitanic projects will be put on hold - or will shift to slow motion.Personally I consider putting such projects asleep to be one of thegreatest benefits of the current worldwide economic situation.

Newton’s third lawSo now what? This is where Newton’s third law of motion comes inhandy. Without going into much technical detail it can be simplified as:“To every action there is an equal and opposite reaction." Doesn’t that

sound good? Instead of runninghighly expensive, never ending,never delivering projects, therewill an equal and oppositereaction. We all know what thatreaction will look like: shorter,smaller, delivering projects. Agileprojects. In 2009 and 2010 (latefollowers) nearly every respecta-ble bank, insurance companyand government agency will turnto look how agile practices cansave their pet projects.

Being a longtime agile evangelistyou might say: “Sander, what areyour complaining about? This iswhat you always dreamed of.”Well, yes and no. Of course I’mglad that agile practices finallybecome accepted. But there’s a

dark side too. The sudden churn towards agile will trigger a hugedemand for agile expertise in the marketplace, not only onshore asyou might expect, but even offshore.

A new breedAs agile becomes hot, a whole new breed of agile practitioners willarise from the ashes of the titanic projects: the people that previouslyran those projects. They all will be officially converted to agile, althoughdeep down inside they very much believe that agile is not different from

the way they’ve been conducting (failing) projects for the last twentyyears. And who will treat projects in exact the same way as they didfor the last twenty years, only with a small speak.Thus we will see six month “iterations” - or longer, feature teams ofover sixty members, projects where the first ten iterations are used toestablish the requirements, the next ten iterations for doing design,and the remaining iterations to build the software, and finally if there’sstill time left, will use the last iteration to test the software. Projects thatare agile in name only. Please be aware of this new breed.

Let me illustrate agile misuse with a small example I recently encoun-tered. In the week before Christmas I received an interesting newslet-ter by a company that claims to be agile. Unfortunately, their newsletterwriters are still left in the dark. A quote from this newsletter. “Govern-ment chooses agility in IT projects,” heads one of its articles. “As of2010 all big IT projects run by government agencies are to beevaluated per stage on suitability for the next stage.”In my humble opinion there’s not much agile about this statement. Infact, it sounds like waterfall with even tighter milestones to me. Butthe newsletter concludes: “The Dutch government clearly chooses foran approach based on agility.” Eh? As I said before: we’re in the yeareverything turns agile. I even got new year’s greeting cards wishingme lots of agility in the new year.

Agile popularity paradoxService oriented architecture is out. It’s just too complicated. And agileis in. In 2009 and 2010 the term agile will be used for anything thatpeople want you to apply to your projects. Think of highly proprietarycode generators that were sold five years ago as service oriented codegenerators, agile frameworks that previously were mash-upframeworks, agile project managers with only waterfall experience,agile requirements tools that require the creation of multiple Worddocuments per requirement, and projects who claim to be agile justbecause their weekly progress meeting is now done standing up.The risks involved form a true paradox. Yes, we know agile works.Hook up to its core principles, including collaborative teams,re-prioritization, short iterations, small units of work, and testing anddelivering early and frequently. And then implement techniques tomatch these principles, such as daily (!) stand up meetings, agiledashboards, burn down charts, pair programming or retrospectives.Your projects will benefit.But due to the exploding popularity of anything agile we are going tohave to wade through the mud. Newton was right. A body continuesto maintain its uniform motion unless acted upon by an externalunbalanced force. The thicker the mud, the slower the motion.

Sander Hoogendoornblog.sanderhoogendoorn.org •www.accelerateddeliveryplatform.com

magazine voor software development 43

Interesting Things:Why Newton was Agileand the Titanic was NotLet’s be perfectly clear about one thing: 2009 will not only be known as the year the financial crisis hit in hard, it willalso be known as the year everything turned agile. Please allow me to explain. The times when banks, insurancecompanies, car industries and the likes could start up multi-million software development projects of titanic ambi-tion, with dozens of stakeholders, never ending requirements sessions and five year deployment plans are passed.I mostly refer to such projects as titanic projects. They take forever to build, but sink at the first bump in the road.

Page 44: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

DELPHI

Unfortunately, not all of the capabilities of Delphi’s IDE are well known.Consider this. Did you know that Delphi can record (Ctrl+Shift+R) andplayback (Ctrl+Shift+P) a series of keystrokes? It’s my impression thatat least half of Delphi developers do not know this. But it is a featurethat has been available in Delphi since version 1.Part of the problem is that the various keystrokes supported byDelphi’s IDE have been notoriously hard to find in Delphi’s help. Someof them have never been documented. For example, one of my favo-rite keystroke combinations is Ctrl+<spacebar>, which invokes theArgument Value List drop down. Whenever you are entering the valueof an expression, for example, the left side of an assignmentstatement or a parameter of a function, pressing Ctrl+<spacebar>displays a list of the possible symbols that would satisfy theexpression. This feature, which was added in Delphi 3, appeared inthe Delphi 4 help files only. It wasn’t in Delphi 3’s help, and has beenmissing in action since Delphi 5.

Another interesting item to note is that, although Delphi’s IDE hasundergone major revisions in the past few years with the introductionof the Galileo IDE, the keystrokes available in the IDE, and the editorspecifically, have not changed much at all. In particular, nearly everykeystroke combination that was available in Delphi 1 still works inDelphi 2009.

But there is still the problem of documentation. When I inspected themost recent help that ships with RAD Studio 2007, I found that justover half of the editor’s keystroke combinations appeared in the help.The others were nowhere to be found.And this brings us to the essence of this article. I have attempted tocollect here, in Table 1, many of the editor keystroke combinations thatI am aware of (the complete list will be on the website-version of thisarticle, because it would be too long in a magazine). These keystrokecombinations are for the default key mapping, which is used by mostDelphi developers. If you are using one of the other key mappings,some of these combinations will not work, but many will.

I also want to admit that most of this table’s contents was derived fromDelphi’s help files. In other words, while I compiled this table, I did notwrite most of the entries myself. Some entries appear exactly as theydid in the help files, and I wrote some as well.Furthermore, I edited many of the help file entries, either to makecorrections or to simplify the description. I also removed entries thatwere in the help files that either didn’t work correctly, or appeared tonot work at all. Finally, I didn’t include many keystrokes that are notcode editor specific. For instance, I did not include debugging relatedkeystrokes.

So here, for your consideration and enjoyment, is a comprehensivelist of the keystrokes supported by Delphi’s editor. This list ispresented in alphabetical order, by key. When two key or key combi-nations perform the same task, they both appear in the left column.The full list can be downloaded from www.sdn.nl •

Cary Jensen

Keystroke Combinations in

Delphi’s Code EditorThere are many advantages to being a

Delphi developer. Not only has the

language kept pace with improvements

added to other languages, such as C#,

but it has maintained a remarkable

consistency over its many years, first as

Turbo Pascal, and later as Delphi. For

example, routines originally written for

Turbo Pascal in the 1980s often compile

in the latest version of Delphi with little

or no changes. There are not many

languages you can say that about.

Delphi developers have also benefited

from Delphi’s strong IDE (integrated

development environment). From Delphi

1 through RAD Studio 2009, Delphi’s

IDE has provided developers with

state-of-the-art features that support

and improve the overall development

experience.

Did you know that Delphi can record(Ctrl+Shift+R) and playback(Ctrl+Shift+P) a series of keystrokes?

44 MAGAZINE

Page 45: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

magazine voor software development 45

Key/Key Combination Action

Alt+Up Arrow - Ctrl+Left Click Starts code browsingClick+Alt+Mouse Drag Selects column-oriented blocksCtlr+/ Comments or uncomments the current line or selected blockCtrl+Alt+F12 Displays list of open filesCtrl+Alt+Shift+End Selects the column from the cursor position to the end of the current fileCtrl+Alt+Shift+Home Selects the column from the cursor position to the start of the current fileCtrl+Alt+Shift+Left Arrow Selects the column to the left of the cursorCtrl+Alt+Shift+Page Down Selects the column from the cursor position to the top of the screenCtrl+Alt+Shift+Page Up Selects the column from the cursor position to the bottom of the screenCtrl+Alt+Shift+Right Arrow Selects the column to the right of the cursorCtrl+Backspace Deletes the word to the right of the cursorCtrl+E Starts Incremental SearchCtrl+O+A Triggers Open file at cursor or go to declarationCtrl+O+B Browses symbol at cursorCtrl+O+C Turns on column blockingCtrl+O+G Go to line numberCtrl+O+K Turns off column blocking or line blockingCtrl+O+L Turns on line block modeCtrl+O+O Inserts compiler options and directivesCtrl+O+U Toggles case of blockCtrl+P Causes next character to be interpreted as an ASCII sequenceCtrl+Q+[Alt-[ Finds the matching delimiter (forward)Ctrl+Q+]Alt-] Finds the matching delimiter (backward)Ctrl+Q+A Displays Replace dialogCtrl+Q+B Moves to the beginning of a blockCtrl+Q+F Displays Find dialogCtrl+Q+K Moves to the end of a blockCtrl+Q+P Moves to previous positionCtrl+Q+R Moves to the beginning of a fileCtrl+Q+SHome Moves to the beginning of a lineCtrl+Q+T Shifts editor so the current line is at the top of the windowCtrl+Q+U Shifts editor so the current line is at the top of the window, if possibleCtrl+Q+X Moves the cursor to the bottom of the windowCtrl+Q+Y Deletes to the end of a lineCtrl+Shift+<space bar> Displays Code Parameters pop-up windowCtrl+Shift+A Displays Find unit dialogCtrl+Shift+D Displays the Declare Field dialogCtrl+Shift+Down Arrow Jump between declaration and implementationCtrl+Shift+E Displays Rename refactoring dialogCtrl+Shift+End Selects from the cursor position to the end of the current fileCtrl+Shift+K+A Expands all collapsed regionsCtrl+Shift+K+E Collapses current regionCtrl+Shift+K+G Collapses interface, implementation, initialization, and finalization sectionsCtrl+Shift+K+M Collapses all methodsCtrl+Shift+K+N Collapses unitCtrl+Shift+K+O Enables/disables code foldingCtrl+Shift+K+P Collapses nested proceduresCtrl+Shift+K+R Collapse all custom regionsCtrl+Shift+K+T Expands/collapses current regionCtrl+Shift+P Playback a key macroCtrl+Shift+R Starts/stops recording a key macroCtrl+Shift+Right Arrow Selects the word to the right of the cursorCtrl+Shift+Tab Moves to the previous code page (or file)Ctrl+Shift-K+C Collapses all classesShift+Alt+ArrowAlt+Mouse Drag Selects column-oriented blocksShift+Alt+ArrowClick+Alt+Mouse Drag Selects column-oriented blocks

Table 1. Delphi Editor Keystrokes for the Default Key Mapping

DELPHI

Page 46: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

Softwareontwikkeling, verandering is de enige constante …Soms lijkt het wel of er geen eind komt aan de veranderingen in soft-ware land. We zien talen en technieken komen en gaan. Neem Clip-per: 20 jaar geleden een populaire ontwikkelomgeving maartegenwoordig hoor en zie je er niet veel van. Niet dat Clipper niet meerbestaat! Er is nog steeds een groep ontwikkelaars die hun brood ver-dient met het schrijven van Clipper code. Maar groot is deze groepzeker niet meer en er zullen weinig nieuwe mensen bijkomen.Maar zijn al die veranderingen nu eigenlijk echt of verpakken we oudeproblemen gewoon in een nieuwe TLA (three-letter acronym) enmaken we onszelf wijs dat alles steeds verandert? Als ik het artikel uit1990 doorlees krijg ik toch een beetje het idee dat we misschien nogmet een aantal van dezelfde problemen bezig zijn. Zo gaat het artikelover Smartmem, een bibliotheek om binnen Clipper-applicaties hetgeheugengebruik te controleren en geheugen boven de 640Kb aante spreken.

Fig. 1: Zo keken we toen naar geheugengebruik

De getallen zijn misschien heel anders geworden maar het probleemvan “Wat doet mijn programma met zijn geheugen en hoe kan ik meergeheugen krijgen?” is nog steeds actueel. Toen het oorspronkelijkeartikel geschreven werd, gebruikten de meesten van ons MS-DOS. Bijhet ontwikkelen van MS-DOS is ooit bedacht dat 1 megabyte meer

geheugen was dan ooit nodig zou zijn, 640Kb voor de programma’sen de rest voor MS-DOS zelf. Volgens de overleveringen zou Bill Gatesdeze beslissing zelf genomen hebben. Of Bill Gates dit echt gezegdheeft weet ik niet, maar één ding was zeker: in 1990 was 640Kb vooreen programma al lang niet meer genoeg.

Fig. 2: Zo ziet het er tegenwoordig uit

Tegenwoordig denken we nauwelijks meer in kilo- of mega-bytes enis het allemaal giga. Maar het probleem bestaat nog steeds, vandaarde beweging van de 32 bit processor naar de 64 bit processor. Kochtik een paar jaar geleden nog een nieuwe laptop met 1Gb interngeheugen, tegenwoordig denk ik er niet eens meer aan om er één metminder dan 4Gb te kopen en eigenlijk heb ik liever 8 Gb in mijn ma-chine. En ook het probleem wat mijn programma met het geheugendoet, is niet minder geworden; alleen de technieken om hetgeheugengebruik te meten zijn een stuk beter geworden. Zo hebbenwe tegenwoordig memory profilers die we op onze .NET applicaties loskunnen laten. Een stuk makkelijker dan dit van tevoren in hetprogramma te moeten inbouwen.Ook het vrijgeven van gebruikt geheugen blijft ons bezighouden. Als ikop GC.Collect() zoek, waarmee je binnen .NET geheugen vrij kangeven - iets wat eigenlijk binnen een virtuele omgeving helemaal au-tomatisch zou moeten gaan -, kom ik toch nog ruim 66.000 hits tegen.Blijkbaar houdt geheugenbeheer ons nog flink bezig in 2008.

Uiteraard zijn er genoeg dingen wel echt veranderd sinds 1990. Zowerken we al lang niet meer met MS-DOS maar is het nu WindowsVista en kijken we uit naar Windows 7. De procedurele talen als

Maurice de Beijer

Smartmem,Zo Smart Alsde Naam Zegt?

Dat was de titel van een artikel van Ernst Peter Tamminga in het eerste nummer van het SDNblad. Al moet ik eigenlijk CDGN zeggen want toen heette de gebruikersgroep nog de ClipperDevelopers Group Netherlands. En dat eerste nummer van het toenmalige CDGN blad kwamuit op 1 mei 1990. Er is veel veranderd sinds die tijd; zo zie je Clipper tegenwoordig nog wel eenbeetje terug als Visual Objects, maar wie het huidige SDN magazine doorleest zal veel meer overDelphi, .NET, Information Worker en Core Systems lezen.

46 MAGAZINE

SDN

MAGAZINE

EDITIE

SDNMAGAZINE

EDITIE

100

Page 47: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

Clipper zijn nu voor een groot deel verdrongen door object georiën-teerde talen. En waar we met Clipper voornamelijk monolithischeapplicaties maakten, zijn het nu n-tier-, service georiënteerde- engedistribueerde applicaties die het daglicht zien.

ConclusieEr is veel veranderd sinds de CDGN opgericht is, dat is zeker. Maarsoms lijkt het ook wel een beetje of we onszelf voor de gek houden enalleen de nummertjes veranderen. Eén ding is zeker, we werken in eenindustrie die volop verandert. Ik ben dan ook heel erg benieuwd naarwat er in nummer 200 van het SDN magazine, of hoe het dan ook zalheten, gaat staan als terugblik op dit nummer. •

Maurice de Beijer

Maurice de Beijer is een zelfstandigsoftware ontwikkelaar, Most Valua-ble Professional en bèta-tester voorMicrosoft. Hij specialiseert zich in.NET, object oriëntatie en het oplos-sen van technisch moeilijke proble-men. Hiernaast is Maurice ook devoorzitter van de UX track van hetSoftware Development Netwerk,www.sdn.nl. Maurice is te

bereiken via [email protected] of www.theproblems-olver.nl

AGENDA2009

VO DevFest, London (UK) . . .12-15 maart

SDN Event . . . . . . . . . . . . . . . . .30 maart

TechEd USA, Los Angeles . . . . .11-15 mei

SDN Magazine Nr. 101 . . . . . . . . . .15 mei

Microsoft DevDays 2009, Den Haagwww.DevDays.nl . . . . . . . . . . . .28-29 mei

SDN Event . . . . . . . . . . . . . . . . . . .26 juni

SDN Magazine Nr. 102 . . . . . .28 augustus

SDN: Software Developer Conference 2009

Papendal, Arnhem . . . . . .19 - 20 oktober

Genoemde data onder voorbehoud

SDN

MAGAZINE

EDITIE

SDNMAGAZINE

EDITIE

100

Advertentie Aladdin

Page 48: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

MAGAZINE

.NETASPARCHITECTURE

OntwerpprincipesDit framework is, naast het MVC design pattern, opgebouwd volgenseen aantal principes:• Convention over configuration: Het meest voorkomende patroonwordt gebruikt. Wil je iets anders bereiken, dan is dat te configure-ren.

• DRY (Don’t Repeat Yourself): Filosofie die tracht duplicatie tereduceren.

• Extensible: Het framework zal eenvoudig uitbreidbaar zijn.Kerncontracten zijn interface-gebaseerd.

• Seperation of concerns: Het scheiden van belangen zorgt ervoordat elk component zijn eigen verantwoordelijkheid heeft en nietafhankelijk is van een of meerdere andere componenten.

• Facilitate Test Driven Development: Het framework moet het een-voudig maken om applicaties die ermee ontwikkeld worden, unit-testbaar te maken.

Model View ControllerMVC (Model View Controller) is een design pattern bedoeld ombusiness-logica te scheiden van userinterface-logica. Het resultaat vaneen juiste toepassing van het MVC-pattern zal robuuste, onderhoud-bare en (unit)testbare applicaties opleveren.

• Model: Representeert de data en business-rules, verantwoordelijkvoor handhaven van ‘State’.

• View: Definieert hoe de data aan de gebruiker gepresenteerd wordt(UI).

• Controller: Definieert hoe de UI reageert op ontvangen comman-do’s en requests. Deze componenten zijn verantwoordelijk voor deafhandeling van interactie met de eindgebruiker, het manipulerenvan het Model en de uiteindelijke keuze van welke View aan degebruiker wordt gepresenteerd.

Fig. 1: Schematische weergave Model View Controller

VoordelenHet MVC-Framework biedt de volgende voordelen:• Alle kerncontracten binnen MVC zijn interface-gebaseerd endaardoor uitwisselbaar (of mockable). Door het scheiden van be-langen wordt een goede unit-testbaarheid verkregen.

• Het framework is uitbreidbaar. Het is bijvoorbeeld mogelijk IOCcontainers zoals Windsor, Spring.Net, NHibernate, etc., in te zettenmet het Framework, maar ook view engines en unit test frameworkszijn uitwisselbaar.

• Door het introduceren van UrlRouting heb je veel controle over deURL’s van je applicatie. Je hoeft geen url rewriting meer in te zettenom URL’s te krijgen die afwijken van de WebForms manier.

Page-request flowFiguur 2 toont een schematische weergave van het verloop van eenpage-request bij het MVC Framework:

Fig. 2: Verloop Page-request

1. Request komt vanaf de client naar de controller.2. De controller roept het model aan om business-operaties uit te

voeren (data ophalen, business-rules uitvoeren).3. Het model retourneert het resultaat van de operatie aan de con-

troller.4. De controller beslist welke view getoond moet worden en stuurt

deze view de benodigde data.5. View toont de output en stuurt response naar de client.

Unit-testenDe consensus binnen de moderne developer community is dat hetgebruik van unit-tests belangrijk is. Een unit-test moet autonoom, nietafhankelijk van externe resources of componenten, snel uit te voerenen herhaalbaar zijn. Dit is onder andere te bereiken door objecten diegeen direct onderdeel uitmaken van de te testen unit te mocken endoor het gebruik van “Inversion of Control”, ook wel het “DependencyInjection” design pattern genoemd. Het woord mocken betekent hierdat het gedrag en de eigenschappen van een ander objectgesimuleerd worden.

Het idee achter inversion of control is om externe afhankelijkhedennaar objecten te faciliteren d.m.v. externe mechanismen in plaats van

Henry Cordes

ASP.NETWebapplicaties Eindelijk Unit-TestbaarOnder de bezielende leiding van Scott Guthrie heeftMicrosoft ‘s ASP.NET team in december 2007 de eerstepreview van het ASP.NET MVC-Framework uitgebracht.Met het ASP.NET MVC-Framework is het mogelijk eenwebapplicatie in ASP.NET te ontwikkelen, gebaseerd ophet Model View Controller design pattern.

DRY: Don’t Repeat Yourself

Een unit-test moet autonoom, snel uitte voeren en herhaalbaar zijn

48

Page 49: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

de objecten zelf de afhankelijkheden op te laten zetten, of zelfs deprocessen die de objecten gebruiken de benodigde afhankelijkhedenop te laten zetten. Het einddoel is 'loose coupling', en het kan vrij een-voudig bereikt worden door het parametriseren van de constructormet het object waarvoor je de aanroepende class verantwoordelijk laatzijn (zie listings 3, 4 en 5). Omdat het met deze hulpmiddelen een-voudig is om een unit (methode) te isoleren, is de mogelijkheid omalleen het gedrag van de unit te testen binnen handbereik. Het MVC-design pattern laat de controller de requests afhandelen en beslissenwelk model er aan de view doorgegeven wordt om aan de gebruikerte tonen. Door deze scheiding van belangen is het unit-testen van eenwebapplicatie veel eenvoudiger. Het is mogelijk unit-tests te runnenzonder dat de webserver actief is, doordat de namespaceSystem.Web.Abstractions, nadat het in het MVC framework zijnwaarde bewezen heeft, is toegevoegd aan het .NET Framework. Dezenamespace bevat HttpContextBase, waarmee je HttpContext kuntabstraheren en nabootsen, of mocken. Natuurlijk is het nog steedsvan belang om principes als “een class heeft een verantwoordelijk-heid” of “single responsibility principle” te volgen om een unit-testbareapplicatie te krijgen.

MVC-Framework en unit-testenHet ASP.NET MVC Web Application projecttype kan in Visual Studiotoegevoegd worden door de installer te runnen; deze is te downloa-den vanaf www.asp.net/mvc. Om duidelijk te maken hoe het MVC-Framework omgaat met unit-tests maken we een nieuw project aan.

Fig.: 3: Nieuw ASP.NET MVC Web Application project

We geven de gewenste naam en locatie op en klikken op ‘OK’. Danverschijnt het scherm in figuur 4.

Fig.4: Maak Unit Test Project aan

De eerste dialoog na het aanmaken van een ASP.NET MVC WebApplication geeft de mogelijkheid tot het creëren van een unit-testproject. Bij ‘Test Framework’ kan ieder unit-testframework gekozenworden dat integreert met het MVC-Framework. Wij maken gebruikvan het Microsoft testframework dat standaard in Visual Studio 2008aanwezig is.

Een veelgebruikt alternatief testframework is MbUnit, dit is een opensource initiatief. Bij installatie van MbUnit versie 3.x zet MbUnit zichzelfin de lijst van beschikbare testframeworks. Tevens worden erMVC/MbUnit Test Project Templates voor C# en VB.NET geinstalleerd.Mocht het testframework van jouw keuze dit (nog) niet doen, dan kunje op de Visual Web DeveloperTeam Blog [3] lezen hoe dit werkt.

ProjectstructuurDe wizard heeft twee projecten in de solution aangemaakt: de we-bapplicatie en een testproject. Zelf heb ik een class-library toegevoegd.In de webapplicatie zijn de models, views en controllers gescheidendoor aparte mappen.

In de View-map wordt voor iedere controller een bijbehorende subfol-der verwacht. Doordat het convention over configuration principe ge-bruikt wordt, zal de controller direct werken wanneer men zich aan deconventie houdt. Hierdoor kun je snel aan de slag. Wil je andergedrag, dan kun je dit configureren. In de sub folder worden de MVC-ASPX-views geplaatst. In de View-map staat ook een Shared-sub-map waarin de MasterPages en errorpagina’s geplaatst worden. DeContent-map is voor de stylesheets en javascript–bestanden. Dewizard plaatst een CSS-bestand en een MVC-variant van de ASP.NETAJAX Client library. De wizard maakt een Home- en een Account-con-troller aan met bijbehorende views. Home is voor de start pagina vanhet project en account voor de aanmeld pagina. Voor de controllers

magazine voor software development 49

Alternatief testframework is MbUnit,een open source initiatief

Fig. 5: Projectstructuur

.NETASPARCHITECTURE

Page 50: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

geldt het convention over configuration principe dat iedere publiekemethode als action-methode gezien wordt. De controller baseclasszal de betreffende action-methode uitvoeren volgens de URL routingregels die in de GLOBAL.ASAX van de applicatie zijn geconfigureerd.

In het testproject is een Controllers-map met een HomeControllerTestaangemaakt. In deze class zijn twee voorbeeldtests geplaatst, waar-mee getest wordt of de controllers de juiste titel in de view plaatsen.

Afhankelijkheden verwijderenWe willen een unit, een zo klein mogelijk stuk functionaliteit, testen.In dit geval nemen we de Index-methode op de HomeController alsvoorbeeld . De Index-methode (zie lisiting 3) haalt data op uit een da-tabase via de HomeModel-class en geeft deze door aan de view.Zodra we met een database werken, wil je bij het unit-testen nietafhankelijk zijn van het bestaan van de database. Door met interfaceste werken wordt het eenvoudiger om de datalaag te abstraheren en dedatabase na te bootsen.

public interface IProductsDataSource

{

List<Product> GetProducts();

}

Listing 1: Interface IProductsDatasource

In listing 1 is een simpel interface zichtbaar. Dit interface dicteert hetimplementeren van een methode die een List van het type Productteruggeeft. Door een interface te gebruiken maken we het mogelijk demethodes in deze interface uit te wisselen, waardoor we in onze unit-test kunnen controleren wat deze retourneert.We maken een eigen class genaamd MockDataStore. Deze classimplementeert het IProductsDataSource-interface en geeft altijd de-zelfde List<Product> terug (zie listing 2). Deze class zal alleen voorunit-testdoeleinden ingezet worden.

public class MockDatastore : IProductsDataSource

{

public List<Product> GetProducts()

{

List<Product> products = new List<Product>();

for (int i = 0; i < 3; i++)

{

Product product = new Product();

product.Name = "Productname " + i.ToString();

product.Category = "Testproduct";

product.Description = "This is product no: "

+ i.ToString();

product.Price = (Decimal)i * 10;

products.Add(product);

}

return products;

}

}

Listing 2: Mock Data class

Test faaltTest Driven Development (TDD) schrijft voor om te starten met hetschrijven van een test, deze uit te voeren en te zien falen. De volgendestap is de methode zo simpel mogelijk in te vullen, zodat de test slaagt.Vervolgens refactor je de code en voer je de test weer uit; dit herhaal

je totdat de test slaagt. Hierna start het proces weer van voren af aan.We starten met de test in listing 3.

[TestMethod]

public void HomeController_Get_All_Products_Index()

{

MockDatastore store = new MockDatastore();

HomeController controller = new HomeController(store);

controller.Index();

Assert.IsTrue(

((List<Product>)controller.ViewData.Model).Count == 3,

"ViewData.Model did not hold 3 Products");

}

Listing 3: Test HomeController

Deze test instantieert de HomeController, geeft in de constructor eeninstantie van onze zojuist gemaakte MockDatastore-class mee envoert vervolgens de Index-methode uit. De test controleert dat er drieProducten in het model zitten.Na het uitvoeren van de test krijgen we het resultaat ‘Failed’, zoalsgetoond in figuur 6.

Fig. 6: Test failed

RefactorHet Model krijgt een private read-only IProductsDatasource-property,die geïnstantieerd wordt met een nieuwe instantie van de datalaag-class genaamd Datastore. Dit is een object dat via de GetProducts-methode de producten uit de database haalt en retourneert. Doorinversion of control te gebruiken kunnen we tijdens een test een anderobject dat de IProductsDataSource interface implementeert, gebruikenom de data aan te leveren (zie listing 4).

public class HomeModel

{

private IProductsDataSource _DataSource;

private IProductsDataSource DataSource

{

get

{

if (_DataSource == null)

{

_DataSource = new Datastore();

}

return _DataSource;

}

}

public HomeModel()

{

}

/// <summary>

/// Constructs an instance of HomeModel

/// inversing control of the datasource to the caller

50 MAGAZINE

TEST / REFACTOR / TEST

.NETASPARCHITECTURE

Page 51: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

/// </summary>

/// <param name="dataSource"></param>

public HomeModel(IProductsDataSource dataSource)

{

_DataSource = dataSource;

}

public List<Product> GetProducts()

{

return DataSource.GetProducts();

}

}

Listing 4: Inversion of control op Model

In listing 5 zien we dat de controller (HomeController) een privatemember ModelData heeft van het type HomeModel. De standaardconstructor zonder parameter instantieert het HomeModel type metbehulp van zijn standaard constructor. Op de controller maken we eenextra constructor waarbij een IProductsDataSource als parameterwordt verwacht. In deze constructor wordt de waarde van deparameter aan de private member ModelData toegewezen.

[HandleError]

public class HomeController : Controller

{

HomeModel ModelData;

public HomeController()

{

ModelData = new HomeModel();

}

public HomeController(IProductsDataSource productsData)

{

ModelData = new HomeModel(productsData);

}

public ActionResult Index()

{

return View("Index", ModelData.GetProducts());

}

}

Listing 5: Controller-class

In de Index-methode, die een ActionResult retourneert, wordt demember ModelData gebruikt om GetProducts uit te voeren. Door dezewerkwijze zorgen we ervoor dat standaard, wanneer de constructorszonder parameter gebruikt worden, de data uit de database gebruiktwordt. Tijdens onze test in listing 4 kunnen we echter een eigenData-object gebruiken, MockDatastore uit listing 3, die we in de con-structor van de HomeController injecteren. Vervolgens zal dit Mock-Datastore object aan de private member DataSource toegewezenworden via de geparameteriseerde constructor van het HomeCon-troller object, waarna het in de GetProducts methode de productenkan retourneren die wij in onze test verwachten.De class declaratie in listing 5 is met het attribuut HandleErrorgedecoreerd. Dit action-filter-attribuut is sinds preview 4 aan het MVCFramework is toegevoegd

Test slaagtNa deze refactoring voeren we de test uit listing 4 nogmaals uit.Infiguur 7 is te zien dat de test succesvol is uitgevoerd. We kunnen ernu vanuit gaan dat de methode Index op de HomeController-control-ler doet wat wij verwachten.

Fig. 7: Test slaagt

ConclusieWanneer jouw volgende webapplicatie meer is dan alleen CRUD, alsje de mogelijkheid wilt om je processing- en business-logica te tes-ten, misschien zelfs TDD wilt adopteren … dan is het ASP.NET MVCFramework misschien iets voor jou.

De aard van het MVC design pattern leent zich uitstekend voor unit-testen doordat de afzonderlijke onderdelen gescheiden zijn. Voeg daarhet feit aan toe dat de kerncontracten binnen het ASP.NET MVC Fra-mework interface-gebaseerd zijn, en het wordt alleen maar beter.De onderhoudbaarheid van een MVC-applicatie zal beter zijn door de‘loosely coupled’ aard ervan. Overigens kan ook bij gebruik van hetASP.NET MVC Framework een slecht onderhoudbare applicatiegemaakt worden …Ook als je het prettig vindt veel controle te hebben over bijvoorbeeldde HTML die in de browser gerenderd wordt, is MVC ideaal. Er wordtgeen HTML gegenereerd; alleen datgene dat je zelf in de view plaatstwordt gebruikt. Voldoet de WebForms view-engine die standaard doorhet ASP.NET MVC-Framework gebruikt niet aan je wensen, gebruikdan de engine die je wel bevalt of maak er zelf een.

ReferentiesGebruikte URL’s:• ASP.NET MVC: http://www.asp.net/mvc• DRY: http://en.wikipedia.org/wiki/Don't_repeat_yourself• Visual WebDev team blog: http://blogs.msdn.com/webdevtools/ar-chive/2008/03/06/asp-net-mvc-test-framework-integration-demo.aspx

• MVC-Framework Preview 5: http://www.codeplex.com/aspnet/Re-lease/ProjectReleases.aspx?ReleaseId=16775

• Dit artikel is geschreven op basis van MVC-Framework Preview 5! •

magazine voor software development 51

Henry Cordes

Henry Cordes is consultant bij Avan-ade(www.avanade.com), een sa-menwerkingsverband van Microsoften Accenture. Voor vragen en op-merkingen is Henry te bereiken [email protected] of zijnblog www.henrycordes.nl.

SDN TIP:.NETDe SDN-site is vernieuwd. C# en VB.NET vind je nu samenonder de noemer .NET op www.sdn.nl/NET.

.NETASPARCHITECTURE

Page 52: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

52 MAGAZINE

CORESYSTEMS Ulf Büchner

IBM Rational Business Developer withEnterprise Generation Language -

Java zonder Java

Evolutie in de software-ontwikkelingIn de laatste decennia van de vorige eeuw zijn programmeertalenuitgegroeid tot volledige ontwikkelomgevingen, met codegeneratie,patterns, overerving en andere vormen van abstractie en hergebruik.Code werd steeds meer logisch van aard en geschreven door busi-ness developers in plaats van door technici op byte niveau. Vaak wasde software gerelateerd aan een bepaald platform, of een bepaaldetechnische infrastructuur (Synon, client/server). Overgang van het eneplatform naar het andere of toepassing van een andere infrastructuurwas niet of slechts door conversie of herbouw mogelijk. Voordeel wasdat er met de nieuwe tools steeds sneller ontwikkeld kon worden: hetaantal uren per functiepunt ging steeds verder omlaag.

Halverwege de jaren ’90 begon de opmars van een nieuwe, objectgeoriënteerde taal: Java. Door de platformonafhankelijkheid, eenuitgebreide set libraries en de mogelijkheden om web applicaties teontwikkelen werd de taal snel populair. Na verloop van tijd bleek ech-ter dat Java grote problemen met zich mee bracht. Complexiteit vande taal en de libraries, het voor velen nieuwe object-oriëntatie con-cept, de steeds groter wordende hoeveelheid frameworks in allerleiversies en de samenwerking ertussen maakte de overstap voor zowelIT organisaties als de individuele – procedureel geschoolde – ontwik-kelaar moeilijk. In veel gevallen zelfs onmogelijk.

De gestegen productiviteit was door de overgang naar Java en de bij-behorende object-georiënteerde manier van programmeren ineensvoor een deel verloren gegaan. Inmiddels is de productiviteit weer aanhet groeien door strikter gebruik van frameworks en betere IDE’s,samen met aangepaste ontwikkelstraten en de uitstroom van eennieuwe generatie ontwikkelaars van de hogescholen en universiteitendie de nieuwe techniek met de paplepel ingegoten hebben gekregen.

Fig. 1: Productiviteitsverloop in de loop van de tijd

De vraag is echter of dit voldoende is. Bij veel bedrijven staan legacysystemen die al twee of meer decennia naar volle tevredenheid draaienen dermate groot en belangrijk zijn dat uitfasering nog lang op zich zallaten wachten. Herbouw of conversie is vaak geen optie door deenorme omvang. Daarnaast zijn er grote groepen ontwikkelaars vandeze systemen die zich moeten richten op nieuwe uitdagingen. Voor-beelden hiervan zijn het toegankelijk maken van de legacy systemenvoor andere toepassingen, zoals het web en uitwisseling van gege-vens met derden via XML. Voor deze ontwikkelaars zal omscholingnaar Java vanwege de complexiteit geen optie zijn, maar als ze nouJava zouden kunnen ontwikkelen zonder Java te kennen…

RBD met EGL: Java zonder JavaIBM heeft hiervoor sinds drie jaar een product, Rational Business De-veloper, kortweg RBD. Zoals de naam al doet vermoeden is dit productbedoeld om bedrijfskritische applicaties te laten ontwikkelen doormensen die business problemen oplossen en niet zozeer technischeproblemen. Zoals zoveel moderne IDE’s is RBD gebaseerd op het –oorspronkelijk door IBM ontwikkelde – Eclipse framework. Hierdoorwordt integratie met andere Eclipse gebaseerde tools ondersteund.Rational Business Developer biedt de mogelijkheid om vanuit een lo-gische taal Java of COBOL code te genereren voor allerlei platforms.Denk hierbij aan webapplicaties die op een J2EE Application Serverdraaien (WebSphere, Tomcat, BEA), Windows en Linux (J2SE), dezSeries (mainframe) en de PowerSystems (voorheen i5, iSeries,AS/400).

In tijden waar IT organisaties onder steedsgrotere kostendruk komen te staan wordenstijgende productiviteit en hergebruik eenvereiste om aan de verwachtingen van degebruikersorganisatie te kunnen voldoen.Hergebruik doelt in dit opzicht echter nietalleen op het al langer toegepaste herge-bruik van individuele softwarecomponen-ten, maar ook op hele applicatiesystemenen uiteindelijk zelfs op degenen die dezeooit maakten: de legacy ontwikkelaars. Indit artikel wordt uiteengezet hoe IBM’s Ra-tional Business Developer (RBD) met deEnterprise Generation Language (EGL)hierbij kan helpen.

Maar als ze nou Java zouden kunnenontwikkelen zonder Java te kennen …

Page 53: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

Onderdeel van RBD is een generatietaal, de Enterprise GenerationLanguage (EGL). Dit is een abstracte, declaratieve en procedurele taaldie eenvoudig te leren is. Het leertraject is 1 tot 2 weken; na eenmaand is een ontwikkelaar volledig zelfstandig. Naast het feit dat EGLeenvoudig is en zoveel mogelijk de technologie verbergt, biedt het welde ondersteuning die je van een moderne ontwikkeltaal mag ver-wachten. Zo kun je er allerlei soorten applicaties mee ontwikkelen(Web 1.0, Web 2.0, batch en SOA ondersteunende applicaties). Ookis er een geïntegreerde debugger. Als laatste redmiddel: als je er metEGL niet uitkomt, kun je altijd nog zelf Java of COBOL source codeschrijven in zogenaamde external types en die zeer eenvoudig ge-bruiken vanuit EGL.

EGL in een notendopMaar genoeg inleidende marketingpraat, laten we naar de opzet vanEGL kijken. De beschrijving van de IDE laten we hier achterwegeomwille van de ruimte. Iedereen (zeker hier?) die wel eens met een opEclipse gebaseerde omgeving heeft gewerkt kent de werkwijze, metworkspaces, projecten, packages, source objecten, perspectives enviews.

Om de omvang van het artikel te beperken zullen we ons verder hiervooral richten op het maken van webapplicaties, dus het genererenvan J2EE code in combinatie met Java Server Pages (JSP’s) op eenApplication Server. Genereren van COBOL of het aanroepen van be-staande legacy applicaties is in de praktijk wel belangrijk, maar zal wel-licht op een later moment worden besproken.

EGL bestaat in de basis uit verschillende soorten source files. Dezehebben de extensie .egl en kunnen worden onderverdeeld in:• Programs – losstaande programma’s met een enkel entry point;• Libraries – groepen van programma’s in één file, dus meerdere entrypoints;

• Services – groepen van operations in één (web) service, meerdereentry points;

• JSFHandlers – event handling programma behorend bij een JavaServer Page;

• BIRTHandlers – event handling programma behorend bij een BIRTreport;

• BuildFiles – configuratiefile om instellingen vast te leggen voor hetgenereren van code (doelplatform, database, etc.).

De source files worden in een logische structuur onderverdeeld inpackages en hebben binnen een package een unieke naam. Vanuitdeze EGL source files worden Java source files gegenereerd, die ophun beurt door Eclipse worden gecompileerd tot Java class files.

EGL sources zijn op een bepaalde manier opgebouwd, afhankelijk vanhet soort source. Als voorbeeld is in listing 1 de code van een pro-gramma om een record uit de Customer tabel op te halen afgebeeld.

package programs;

import egldemo.StatusRec;

import egldemo.access.CustomerLib;

import egldemo.data.Customer;

// basic called program

//

program myProgram type BasicProgram(customerID string,

customerRecord Customer) {}

// Variable Declarations

status StatusRec;

function main()

customerRecord.CUSTOMER_ID = customerID;

CustomerLib.GetCustomer(customerRecord, status);

if(!status.succeeded)

SysLib.writeStderr("Error fetching record!");

end

end

end

Listing 1: Een eenvoudig EGL programma om een record op tehalen

Voor de Java kenners onder ons zal de structuur bekend voorkomen.Er zitten dan ook aardig wat overeenkomsten tussen Java en EGLvoor wat betreft opbouw van sources. Maar ook voor een procedureleprogrammeur is de source goed leesbaar. Voor de verduidelijking lopenwe de statements door vanaf het begin:• Package - geeft aan waar in de hiërarchische structuur van foldersdeze source staat;

• Import statements - zorgen ervoor dat in het programma gebruikteobjecten die niet in dezelfde package staan kunnen worden ge-vonden;

• Program - dit is de definitie van het programma, met het interface(een veld customerID en een record van het type Customer, beidezowel in- als output);

• Status - een variabele-definitie, waarbij status wordt gedefinieerdals zijnde van het type StatusRec (een record);

• Function main() - het entry point van het programma.

Binnen het main() entry point wordt de eigenlijke code geprogram-meerd. In dit geval wordt in het customerRecord het veld CUSTO-MER_ID gevuld met het customerID dat via de call binnenkomt.Daarna wordt een functie GetCustomer aangeroepen in een libraryCustomerLib (hierover later meer). Het customerRecord is een dualparameter, waar dus het CUSTOMER_ID gevuld is. Als er een recordvoor dit CUSTOMER_ID bestaat, zal een volledig gevuld customer-Record worden geretourneerd. Het status record zal na de aanroepvan de GetCustomer functie informatie bevatten of het aangeroepenprogramma succesvol is verlopen. Binnen het status record bevindtzich een boolean veld, succeeded. Als dit niet true is wordt eenmelding naar de console gestuurd via de ingebouwde EGL functieSysLib.writeStderr. Daarna eindigt het programma.

Aan dit voorbeeld is te zien hoe eenvoudig EGL source in elkaar zit. Dein EGL ingebouwde content assist, waarbij slechts delen van eenstatement hoeven te worden ingevuld waarna EGL zelf de statementsaanvult, helpt enorm bij het snel programmeren. Om b.v. het state-ment CustomerLib.GetCustomer(…) in te voeren geeft de program-meur eerst een aantal beginletters in, bijvoorbeeld Cust, en drukt danCTRL-spatie. Uit de lijst die dan wordt getoond kan CustomerLibworden gekozen.

Fig. 2: Content assist

Na het kiezen van de CustomerLib library geeft de programmeur eenpunt (.) in en drukt weer CTRL-spatie. Nu toont EGL alle functies diein de betreffende library beschikbaar zijn en kan hieruit een keuzeworden gemaakt. Door beginletters in te geven kan de subset wordenverkleind.Door het veelvuldig gebruik van content assist kan met groteresnelheid worden geprogrammeerd en worden fouten voorkomen.

magazine voor software development 53

CORESYSTEMS

Page 54: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

Data accessErg belangrijk in een bedrijfsapplicatie is bijna altijd het benaderen vandatabases. EGL doet dit met SQL via JDBC. In principe is iederedatabase te gebruiken die een JDBC driver heeft. Erg krachtig is demanier waarop database-definities kunnen worden geïmporteerd,waarna automatisch libraries worden gegenereerd om de data in debetreffende database te kunnen benaderen. Nieuwe databases entabellen kunnen worden gemaakt in de zogenaamde Data Perspec-tive. Er kunnen dus zowel bestaande als nieuwe databases wordengebruikt.

De database-import gebeurt met behulp van de Data Access Appli-cation Wizard. Deze wizard geeft de ontwikkelaar in achtereenvol-gende stappen de mogelijkheid om:1. De database te selecteren;2. Al dan niet een filter te leggen op een bepaald schema in die

database;3. Tabellen te selecteren;4. Eventueel wijzigingen aan te brengen in de sleuteldefinities die door

EGL zullen worden gebruikt;5. Eventueel ervoor te kiezen dat er na de import ook standaard JSP’s

worden aangemaakt om de data in de database te bewerken.

Na de import heeft EGL de volgende packages met daarin EGL sourceobjecten aangemaakt (zie figuur 3):• Package egldemo.primitivetypes.data: bevat veldtypen die wordengebruikt;

• Package egldemo.data: bevat record definities van de tabellen;• Package egldemo.access: bevat libraries die voor de database-toe-gang zorgen.

De sources in deze packages maken gebruik van elkaar. Zo zijnrecord-definities van tabellen samengesteld uit veldtypen in de primi-tivetypes package. De libraries met database-toegang uit de accesspackage maken weer gebruik van de record-definities uit de datapackage.

Fig. 3: Objecten aangemaakt door de database-import

Zoals eerder gezegd verbergt EGL technische details waar mogelijkvoor de ontwikkelaar. Een mooi voorbeeld daarvan is het commandoom een record op te halen. Eerder in dit artikel gebruikten we de Cus-tomerLib.GetCustomer functie om een record op te halen. Deze func-tie bekijken wij nu door de CustomerLib library te openen en naar defunctie te scrollen. Een makkelijker alternatief hiervoor is om op hetCustomerLib.GetCustomer statement te gaan staan en op F3 te druk-ken. EGL toont dan de functie in een nieuwe editor. Met behulp vandeze functionaliteit is het dus erg eenvoudig om objecten binnen deapplicatie te vinden. Listing 2 toont de GetCustomer functie.

Function GetCustomer(searchRecord Customer inout,

status StatusRec)

try

get searchRecord with

#sql{…

};

if (SysVar.sqlData.sqlCode == 100)

HandleDBRecordNotFound(status, "CUSTOMER");

else

HandleSuccess(status);

end

SysLib.commit();

onException (exception SQLException)

HandleException(status, exception);

end

end

Listing 2: De GetCustomer functie

We zien de functiedefinitie met parameter-interface en allerlei logicaom af te handelen wat er moet gebeuren als iets fout gaat bij het op-halen van het record. Wat we ook zien is dat er één enkel statementis dat voor het lezen van het record zorgt: get searchRecord. Dit iseen zogenaamd impliciet EGL statement, waaronder de eigenlijke SQLcode is verborgen. Doordat searchRecord van het type Customer is,weet EGL dat een Customer record moet worden opgehaald. Naast‘get’ zijn er de keywords ‘add’, ‘delete’ en ‘replace’, voor respectie-velijk het toevoegen, verwijderen en wijzigen van records.

We kunnen het SQL-statement zichtbaar maken door met rechts ophet impliciete statement te klikken en Add te kiezen. EGL voegt dan devolledige syntax in, zoals te zien is in listing 3.

Function GetCustomer(searchRecord Customer inout,

status StatusRec)

try

get searchRecord with

#sql{

select

CUSTOMER.CUSTOMER_ID, CUSTOMER.FIRST_NAME,

CUSTOMER.LAST_NAME, CUSTOMER.PASSWORD,

CUSTOMER.PHONE, CUSTOMER.EMAIL_ADDRESS,

CUSTOMER.STREET, CUSTOMER.APARTMENT,

CUSTOMER.CITY, CUSTOMER."STATE",

CUSTOMER.POSTALCODE, CUSTOMER.DIRECTIONS

from CUSTOMER

where

CUSTOMER.CUSTOMER_ID = :SEARCHRECORD.CUSTOMER_ID

};

if (SysVar.sqlData.sqlCode == 100)

HandleDBRecordNotFound(status, "CUSTOMER");

else

HandleSuccess(status);

54 MAGAZINE

CORESYSTEMS

Erg krachtig is de manier waaropdatabase-definities kunnen wordengeïmporteerd

Page 55: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

end

SysLib.commit();

onException (exception SQLException)

HandleException(status, exception);

end

end

Listing 3: Impliciet SQL statement volledig getoond

We zien het SQL-statement dat wordt gebruikt om het record op tehalen. Het expliciet maken van een SQL-statement heeft natuurlijkalleen nut als we er iets aan willen veranderen. Op die manier kan eenrecord op een andere manier worden opgehaald door een kopie vande GetCustomer functie te maken, een andere naam te geven en in diekopie het SQL statement aan te passen.Overigens kunnen aangepaste definities eenvoudig worden veiligge-steld, zodat ze bij een nieuwe import van de database niet wordenoverschreven. Hiervoor is een speciale plek gereserveerd in iederelibrary.Het importeren van database-definities maakt het mogelijk om vanuitEGL bestaande databases te benaderen. De manier van werken metdatabase libraries die de toegang verzorgen en de techniek verber-gen houdt daarbij de programmatuur erg overzichtelijk.

WebservicesEGL ondersteunt zowel het publiceren als het consumeren van(web)services. Ook dit gebeurt op een abstracte manier, waarbij detechniek zoveel mogelijk wordt verborgen. Als eerste zullen we kijkennaar het produceren van een webservice.

Zoals we eerder zagen is er een source type Service. Met behulp vaneen wizard maken we een nieuwe service, MyService.egl. We gevendaarbij aan dat dit een webservice moet worden, waardoor EGL op deachtergrond allerlei zaken voor ons regelt. In de service voegen weeen operatie toe die twee getallen bij elkaar optelt en het resultaat te-ruggeeft (zie listing 4). Merk op dat door middel van de keywords ‘in’en ‘out’ kan worden aangegeven wat in- en output-parameters zijn.Daarnaast is er een keyword ‘inout’, dat aangeeft dat een parameterzowel in- als output is. Het gebruik ervan is echter triviaal, omdatparameters in EGL standaard al zo worden gegenereerd.

package services;

service MyService

function myOperation(number1 int in, number2 int in,

result int out)

result = number1 + number2;

end

end

Listing 4: Een eenvoudige webservice

Om de webservice te kunnen publiceren moeten we nu nog eenzogenaamd WSDL-file maken. Deze bevat de locatie en het interface,waardoor derden de webservice kunnen aanroepen. Dit doen we een-voudigweg door met rechts op de service te klikken en te kiezen voorGenerate WSDL File. Via een wizard, waarin bijvoorbeeld de poort enserver locatie voor de webservice kunnen worden ingevuld, maken wehet WSDL-file aan.

Zie als resultaat de (grafische weergave van) het WSDL-file in figuur 4.In dit geval hebben we als server localhost ingevuld met poort 9080.

Fig. 4: WSDL-file

We kunnen deze webservice nu gebruiken vanuit andere software diewebservices kan consumeren. Om te laten zien hoe we dit in EGLdoen zullen we een webpagina maken die onze service gebruikt. Te-vens wordt dan duidelijk hoe we een webpagina met bijbehorendeeventhandler (JSFHandler) maken.Als eerste klikken we met rechts op het WSDL-file en kiezen CreateEGL Client Interface. Dit zorgt ervoor dat er een EGL-library wordtaangemaakt die de toegang tot de webservice verzorgt.Met behulp van een wizard (New -> Web page) maken we een nieuweJSP aan, callWS.jsp. Deze opent leeg in een nieuwe editor. Vanuit depalette, een view met componenten die we op de pagina kunnen toe-voegen, kiezen we EGL->Service en slepen dit op de pagina (zie figuur5).

Fig. 5: Aanmaken van de servicedefinities op een JSP

We kiezen uit een lijstje van beschikbare services onze MyService ser-vice. Dit zorgt ervoor dat definities voor zowel het parameter-interfacevan de webservice als de functie om de webservice aan te roepenworden aangemaakt.Door met rechts op de pagina te klikken kiezen we Edit Page Code.Hierdoor opent de JSFHandler, dus de EGL eventhandler die bij depagina hoort. We zien dat de code om de webservice aan te roepenal voor ons is ingevoegd doordat wij het service-component op deJSP hebben geplaatst. De code staat in listing 5.

package jsfhandlers;

import com.ibm.egl.jsf.*;import services.MyService;

handler callWS type JSFHandler{onConstructionFunction = onConstruction,onPrerenderFunction = onPrerender,

view = "callWS.jsp",viewRootVar = viewRoot}

viewRoot UIViewRoot;

number1 int;number2 int;result int;

// Function Declarationsfunction onConstruction()end

function onPrerender()end

function callWebService()myService MyService {@bindService};myService.myOperation(number1, number2, result);

endend

Listing 5: Aanroep van een webservice vanuit een JSFHandler

magazine voor software development 55

EGL ondersteunt zowel het publicerenals het consumeren van (web)services

CORESYSTEMS

Page 56: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

Naast de standaard code zoals die in een nieuwe JSFHandler auto-matisch staat is het volgende toegevoegd:• Drie variabele-definities type int voor de velden number1, number2en result;

• Een functie callWebService.

In die laatste functie wordt eerst een locaal object myService aange-maakt. Dit is van het type MyService, dus het client-interface die dewebservice kan aanroepen. Daarna wordt de operatie myOperationvan de webservice aangeroepen, met de parameters die eerder alsvariabelen zijn gedefinieerd.Nu willen we in de JSP zorgen dat we de variabelen kunnen vullen ende callWebService functie kunnen aanroepen. Hiervoor gaan we terugnaar de JSP en slepen uit de Page Data view (zie figuur 6 links on-derin) de betreffende velden op de JSP. Wederom wordt een wizardgestart die ons vraagt wat voor velden (input of output, in ons gevalinput) dit moeten worden, waarna automatisch JSF componenten voorde velden op de pagina worden geplaatst. Daarnaast wordt meteen(naar keuze) een button op het scherm gezet.

Fig. 6: Opmaken van een JSP

Op deze manier hebben we onze variabelen als invoervelden op hetscherm geplaatst, waarbij ook meteen de binding (de koppelingtussen de JSF-componenten en de EGL-variabelen) is geregeld.Nu willen we er nog voor zorgen dat de functie callWebService wordtaangeroepen als we op de Calculate button klikken. Dit doen we doorde callWebService() functie, die in de Page Data view links onderinonder Actions staat, op de button te slepen. Hierdoor ontstaat eenbinding tussen de button en de functie.Als we nu de JSP opstarten op onze Application Server (die onderdeelis van de ontwikkelomgeving), dan kunnen we getallen invullen en deberekening uitvoeren.

Fig. 7: Aanroep van de service vanuit een webpagina

AJAX, RichUI en Web 2.0Naast de hier genoemde functionaliteit biedt EGL nog ondersteuningvoor andere moderne technieken, zoals AJAX en Rich User Interfaces(RichUI) door middel van JavaScript-generatie en DOJO/Silverlight-widgets. Hiermee zijn o.a. mashups mogelijk om informatie uitverschillende bronnen te combineren. Hieraan wordt vaak gerefereerdmet de term Web 2.0.

ConclusieMet de Rational Business Developer en EGL heeft IBM een productdat het voor de klassieke ontwikkelaar mogelijk maakt om de nieuwewereld van Java- en web-applicaties te betreden. Kennis van Java isin beperkte mate wenselijk, namelijk voor foutopsporing of het makenvan zogenaamde external types, dus stukjes Java source code omeventuele extra ondersteuning te bieden waar EGL dit (nog) niet kan.In een team zal het vaak voldoende zijn om één iemand op te nemendie deze kennis heeft.Op een zeer eenvoudige manier kan een bestaande database-defini-tie worden ingelezen en kan de database daarna worden benaderd.Ook webservices kunnen makkelijk worden geproduceerd en gecon-sumeerd. Daarnaast worden steeds nieuwe technieken toegevoegdaan het product, zoals recentelijk Rich User Interfaces. Hierbij wordt inplaats van Java Server Pages JavaScript gegenereerd om webappli-caties te bouwen met processing in de browser.Voor ontwikkelaars die al bekend zijn met de Java-wereld kan EGLook perspectieven bieden. Het bouwen van bedrijfskritische applica-ties is veel eenvoudiger en er kan sneller resultaat worden geboekt, alzitten er aan een generatie-tool altijd beperkingen waar een Java-ont-wikkelaar zich snel aan zal storen. •

56 MAGAZINE

EGL biedt ook ondersteuning voor an-dere moderne technieken als AJAX enRich User Interfaces

Ulf Büchner

Ulf werkt bij Synobsys als EGL Con-sultant. In het verleden werkte Ulf als4GL application developer (CA Plex)op Windows/iSeries met C++/Java/RPG. Ulf werkt met EGL sinds2006.

IW TIP:Verloopdatum instellen op lijstenin SharePoint 2007?Vaak wil je een maximale datum stellen aan content. In lijsten enkolommen is deze functionaliteit standaard beschikbaar: zie deonderstaande link. Bron TechNet: http://blogs.technet.com/collaboration/archive/2008/02/22/how-to-see-items-added-to-a-sharepoint-list-library-in-the-last-x-days.aspx.

Jordy van Paassen - VX Company

CORESYSTEMS

Page 57: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

Advertentie 4DotNet b.v.

Advertentie MI Consultancy BV

Page 58: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

DOTNETNUKE

Brandon Haynes

LINQ to SQL for Rapid DevelopmentLINQ to SQL is a lightweight pseudo-ORM tool allowing for rapiddevelopment in connected, highly-focused architectures. It is aMicrosoft SQL Server-specific technology. LINQ to SQL entities areeasily updated as the underlying schema changes. Overall, itslightweight implementation offers “just enough” abstraction for suchsmaller, focused applications.

Saliently, because DotNetNuke is predominately operated usingMicrosoft SQL Server, a more robust platform such as the EntityFramework (operable against a wide variety of data stores) introducesadditional unnecessary overhead. Similarly, for most DotNetNukemodules, the database model is generally equivalent to its finalconceptual structure. Such a module does not require the additionaloverhead (present in other ORMs such as the Entity Framework) thatallows such separation.

Isn’t LINQ to SQL Deprecated?No. It is true that LINQ to SQL was recently transferred to the SQLData Programmability Team (home of the Entity Framework). There,Program Manager Tim Mallalieu has clearly communicated that LINQto SQL is alive, well, and will be supported into .NET 4.0 as it is mer-ged into the Entity Framework (Schwartz, 2008). The bottom lineremains that it is both safe and prudent to move forward with LINQ toSQL development.

Why not the DAL?It is worth discussing why LINQ to SQL might be used in favor of theDotNetNuke-recommended data-layer solution, the Data AccessLayer (DAL) and subsequently released DAL+. Both are designed totarget any backing store (through the use of an abstract providerpattern). Access is generally achieved through the retrieval of IData-Reader-implementing objects from the data tier. However, in practice,DotNetNuke is virtually always deployed using Microsoft SQL Server(Leupold, 2008). Given this reality, the DAL abstract provider pattern

adds additional complexity with little marginal utility. LINQ to SQLavoids many of these drawbacks given the context of a focused, non-enterprise module. Object exchange across tiers involves strongly-typed entity objects (instead of weakly-typed IDataReader-implementing property bags). Hydration of distinct business entitiesfrom the already strongly-typed LINQ to SQL objects thereby becomesoptional (and in many applications unnecessary). Finally, LINQ to SQLprovides a footprint that is similar to or less than (when it is allowed togenerate dynamic SQL) its DAL counterpart.

A Drawback: Cross-Tier and Entity Context LifetimeThere arguably exist some design disadvantages associated with theuse of LINQ to SQL entity objects as an unmediated data layer. Whilesuch architectural caveats are generally beyond the scope of thisarticle, it is worth mentioning that Microsoft LINQ Program ManagerDinesh Kulkarni (2007) noted that there exists no out-of-the-box multi-tier story within the LINQ to SQL framework. This, inter alia, makeschange-tracking across tiers within LINQ to SQL particularly difficult.This difficulty, however, is offset to some length by the rapid, focuseddesign constraints discussed above.In a stateless, web-oriented environment, this issue is of particular re-levance with data context lifetime. LINQ to SQL requires all operationsto be performed against a DataContext object, which is responsible fordifferential tracking. This context must, then, exist throughout a “unitof work” – which, for module development purposes is (in general)equivalent to the lifetime of any given ASP.NET request thread.One common solution to this problem involves the implementation ofthe Unit of Work (UoW) pattern (Fowler, 2002). This pattern is used inother ORM solutions such as NHibernate. A straightforwardimplementation utilizes the HttpContext.Current.Items collection tostore a context over the lifetime of a request. This approach isdemonstrated in listing 1, and is used for the DotNetNuke moduledemonstration that follows. This approach may be improved throughthe application of an Inversion of Control (IoC) pattern (to avoid theSystem.Web reference in the data tier), but such an enhancement isbeyond the scope of this article (Johnson & Foote, 1988).

static class Context{private const string key = "MyDataContext";

public static MyContext Current{get{if (!HttpContext.Current.Items.Contains(key))HttpContext.Current.Items.Add(key,

58 MAGAZINE

LINQ to SQL and DotNetNuke:A Perfect Fit for Rapid DevelopmentMicrosoft’s LINQ to SQL is a great choice for module development on the DotNetNuke platform. It allows for rapid

development, is well-suited to smaller and focused architectures, and has a lightweight footprint. For many Dot-

NetNuke modules – which often focus on performing one highly-focused task – this is a natural fit.

In this article we explore the many advantages of using LINQ to SQL as a data tier within a DotNetNuke module,

discuss the alternatives, and demonstrate a sample module using this technology.

LINQ to SQL is a great choicefor module development on theDotNetNuke platform.

LINQ to SQL is alive, well, and willbe supported into .NET 4.0

Page 59: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

new MyContext(Config.GetConnectionString()));

return (MyContext)HttpContext.Current.Items[key];}

}}

Listing 1: Unit of Work pattern for handling a LINQ to SQL datacontext

LINQ to SQL in Action: A Sample ModuleA Search and Replace DotNetNuke ModuleWe now turn to a concrete example demonstrating the use of LINQ toSQL in a DotNetNuke module. This module is designed to search andreplace text across all instances of Text/HTML modules in a given Dot-NetNuke website. The module is developed using the web applica-tion project type (WAP) generally (but not exclusively) preferred byDotNetNuke developers. Note that, for purposes of brevity, we per-form business-related functionality directly within the user control eventhandler and embed the LINQ to SQL entities and context directly wit-hin the UI assembly. While this allows for a more straightforward de-monstration, any robust solution would certainly further separate thesedistinct architectural concerns. This module was tested against anddeployed within DotNetNuke version 4.91 and 5.0. It assumes thatASP.NET 3.5 is deployed in the server environment (required for useof LINQ to SQL). Note that DotNetNuke now 5.0 supports auto-con-figuration of ASP.NET 3.5 through its UI.

Project Structure and DiscussionThe module project structure contains three elements relevant to thisdiscussion: a user control (and associated code-behind), a UoWcontext class (discussed above), and a LINQ to SQL database meta-model. The project also contains a module schema file (SearchAnd-Replace.dnn) used to install the module within a particular DotNetNukeinstallation. Figure 1 depicts the project structure as displayed in theVisual Studio solution explorer.

Fig. 1: Project structure in Visual Studio Solution Explorer

LINQ to SQL ModelFor purposes of simplicity, our model uses tables and views that existacross all DotNetNuke installations. This alleviates the need to createadditional database objects during module installation. Note, howe-ver, that these techniques may be utilized against any custom data-base schema. Consult the DotNetNuke module developmentdocumentation (Washington, 2007) for more information about thecreation and population of custom database objects during moduleinstallation.

The entity model in this project contains two entities, as illustrated infigure 2. The first, HtmlInstance, contains the raw HTML data wedesire to search (and replace). Because DotNetNuke identifies a givenwebsite by its unique portal identifier (many such portals may exist

within a given installation), we must associate this entity to somethingthat contains the needed value. In this case we use a second entity,Module, which contains the desired identifier. A custom association(keyed on ModuleId) joins the two entities and allows parent and childreferences.

Fig. 2: LINQ to SQL Entity Model

Sample Project Markup and CodeOur markup, located in SearchAndReplace.ascx, is straightforwardand requires little discussion. This markup is displayed in listing 2.

<%@ Control Language="C#"Inherits="SearchAndReplace.Presentation.View" %>

<div>Search and replace text in all Text/HTML modules

</div>

<div>Search for:<asp:TextBox ID="SearchFor" runat="server" />

</div>

<div>Replace with:<asp:TextBox ID="ReplaceWith" runat="server" />

</div>

<asp:Button Text="Submit" runat="server"OnClick="SearchAndReplace_Click" />

Listing 2: Markup within SearchAndReplace.ascx module user control

Business Logic and Code-BehindThe code-behind for our module, SearchAndReplace.ascx.cs, con-tains the code (listing 3) used to interface with the LINQ to SQL entitymodel discussed above. The first statement (lines 1–3) queries thedata model for a set of HTML data instances, and is constrained by thecurrent portal identifier (line 3). This is necessary because DotNetNukesupports multiple websites within the same installation, making itessential to ensure that the module only operates on the “current”website (as identified by this.PortalID). Next, the resultant entity enu-meration is walked, during which string replacement is performed viaa call to string.Replace (lines 5–7). Finally, the updates are committed(line 9). Note the use of the UoW-inspired Data.Context.Currentinstance throughout the method body. Additionally, despite the factthat an assignment is made to ALL entities (even those where noreplacement is actually made), LINQ to SQL tracks and updates onlythose entities that were actually modified.

1: var htmlModules = Data.Context.Current.HtmlInstances2: .Where(html =>3: html.Module.PortalID == this.PortalId);4:5: foreach (var htmlModule in htmlModules)6: htmlModule.DesktopHtml = htmlModule.DesktopHtml7: .Replace(SearchFor.Text, ReplaceWith.Text);8:9: Data.Context.Current.SubmitChanges();

Listing 3: Body of the SearchAndReplace_Click event handler inSearchAndReplace.ascx.cs

magazine voor software development 59

DOTNETNUKE

Page 60: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

Demonstrating the Sample ModuleThe compiled module files may be zipped, uploaded to an active Dot-NetNuke installation, and added to a new page within DotNetNuke.The module will render in a manner similar to that depicted in figure 3.For demonstrative purposes, we will replace all instances of the word“DotNetNuke” with the replacement “DotNetNuke with LINQ to SQL.”In a freshly-installed DotNetNuke 5.0 site, this will result in changes tothree module instances. Figures 4 and 5, respectively, display one suchsection both before and after the changes.

Important: This module is intended as a LINQ to SQL sample fordemonstrative purposes only. Because the module has the potential

to affect markup across an entireDotNetNuke website, please ensurethat only administrative users haveac-cess to its functionality! Figure 6 illus-trates the recommended permissions.

A Note about Database Ownersand Object-QualifiersDotNetNuke allows an installation tobe configured with a custom data-base owner and object qualifier (thelatter being applied as a prefix on alldatabase objects within a particularinstallation). This allows for myriadhosting configurations, includingshared servers and multiple, isolatedDotNetNuke installations within adatabase (each with a unique objectqualifier). Additionally, the use of non-default values for these attributesyields some protection against auto-mated attacks (Connolly, 2006).An installation using non-default da-tabase owner and/or object qualifierintroduces some difficulties whenusing LINQ to SQL. For those modu-les that must accommodate suchscenarios – including all modules de-veloped for commercial use – an al-ternative now exists in the form of amodel adapter (Haynes, 2008). Thisadapter analyzes a LINQ to SQLmeta-model at runtime and dynami-

cally produces an adapted model compatible with any installation(regardless of database owner and object qualifier specification). It isavailable free of charge and under a liberal BSD license at http://codeplex.com/DNNLinqToSqlAdapter.

The Bottom LineLINQ to SQL is not the panacea for the data tier of all DotNetNukemodules; no approach can be universally assigned such an accolade.Each project must carefully balance development complexity, level ofabstraction, database targeting flexibility, performance, and many otherfactors. For modules requiring rapid development, performing astraightforward and focused task, and not requiring database agnos-ticism, LINQ to SQL remains an excellent choice. Strongly consider itfor your next DotNetNuke module project.

References• Connolly, C. (2006). Securing DotNetNuke: Hardening DotNetNukeInstallations. Retrieved Dec 2008, from http://dotnetnuke.com/Link-Click.aspx?fileticket=qkVjRRDHNwU%3D

• Fowler, M. (2002). Patterns of Enterprise Application Architecture.Boston, MA: Addison-Wesley Longman Publishing Co.

• Haynes, B. (2008). DotNetNuke LINQ to SQL Model Adapter. Re-trieved Dec 2008, Web site: http://codeplex.com/DNNLinqToSqlA-dapter

• Johnson, R., & Foote, B. (1988). Designing Reusable Classes. Jour-nal of Object-Oriented Programming. 1, 22-35.

• Kulkarni, D. (2007). LINQ to SQL: What is NOT in RTM (V1).Dinesh's Cyberstation. Retrieved Dec, 2008 from http://blogs.msdn.com/dinesh.kulkarni/archive/2007/10/15/linq-to-sql-what-is-not-in-rtm-v1.aspx

• Leupold, S. (2008). Re: MySQL 5x and DotNetNuke 4.7x. RetrievedDec 2008, from http://dotnetnuke.com/Default.aspx?ThreadId=223520&Scope=Posts&TabId=795

• Schwartz, J. (2008). Microsoft Says LINQ to SQL Not Dead. Red-mond Developer News: Data Driver. Retrieved Dec 2008, fromhttp://reddevnews.com/blogs/weblog.aspx?blog=3036

• Washington, M. (2007). DotNetNuke 4.0 Module Developers Guide(Part 1). Retrieved Dec 2008, from http://dotnetnuke.com/Link-Click.aspx?fileticket=s%2bGtSX0BJTM%3d •

60 MAGAZINE

Brandon Haynes

Brandon Haynes (brandonhay-nes.org) is chief executive officer atEverysport.net Inc., which deliversenterprise resource planning, web-presence, e-commerce, and inte-gration-related functionality torecreational facilities. He is a mem-ber of the DotNetNuke SecurityTeam.

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.

Fig. 5: After Replacement

Fig. 6: Recommended Permissions – Deny on All Users

Fig. 4: Before Replacement

Fig. 3: Display of Sample LINQ to SQL Module

DOTNETNUKE

Page 61: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

Advertentie Sira Holding BV

Page 62: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

62 MAGAZINE

Gael Fraiteur

The recent popularity of multicore processors has turned the termmultithreading into a buzz word. Still, it is hardly a new concept. Anynon-trivial graphical application has to perform long operations suchas reading and saving large files from disk, accessing the network,and carrying out expensive computations. However, implementinglong operations without taking care of multithreading would utterlyjeopardize user satisfaction.Indeed, the graphical subsystem of Windows (on the top of which both.NET WinForms and WPF are built) is intrinsically single-threaded. It isbased on a message queue where individual actions (processing abutton click or rendering the dialog box) are executed one after theother. Therefore, when a button event handler executes, the progressbar cannot be rendered, even if its value has been updated. Neithercan the user interface react properly to a click of the Cancel button.Consequently, a golden rule for graphical programming is to never doanything long in the GUI thread. A few dozen milliseconds is themaximum we can afford to block the message queue, if we want usersto be satisfied. And we do want this satisfaction.

The commonly used solution is to execute long operations in aworker thread. In the .NET Framework, it is generally considered bestpractice not to create a new thread for every operation, but instead,to queue a work item into the thread pool. This operation used to bedifficult, but C# 2.0 and anonymous methods have fortunately madeit easier.The following piece of code handles clicks by using the Save button.It queues the I/O operation for asynchronous execution on a workerthread.

void OnApplyClick(object sender, RoutedEventArgs e)

{

ThreadPool.QueueUserWorkItem(

delegate { this.contact.Save(); });

}

Now, what if we want to display a message after the contact has beensaved? Since the graphical subsystem is single-thread, we cannotinvoke the MessageBox.Show method from the worker thread.Therefore, we have to dispatch it to the GUI thread. With WPF, wehave to use a dispatcher object, as demonstrated in the following codesample:

void OnApplyClick(object sender, RoutedEventArgs e){ThreadPool.QueueUserWorkItem(delegate {this.contact.Save();this.Dispatcher.BeginInvoke(

DispatcherPriority.Normal,new Action( delegate { MessageBox.Show(Window.GetWindow(this), "Saved!"); } )); } );

}

As can be seen, multithreading quickly makes the code unreadableand error-prone. Fortunately, however, there is a superior solution.What if we have the possibility to mark the affinity of methods directlyto the worker thread, or GUI thread, and eliminate the plumbing code?It seems unrealistic, doesn’t it? But with PostSharp and aspect-orien-ted programming, it is not.So let’s dream on. What we want are two custom attributes:• the OnWorkerThreadAttribute, when the method should beexecuted asynchronously on a worker thread;

• the OnGuiThreadAttribute, when the method should be executed onthe GUI thread.

The above piece of code would look like this:

[OnWorkerThread]void OnApplyClick(object sender, RoutedEventArgs e){this.contact.Save();this.ShowMessage("Contact Saved!");

}

[OnGuiThread]void ShowMessage(string message){MessageBox.Show(Window.GetWindow(this), message);

}

Implementing the OnWorkerThread and OnGuiThreadAttributesIf you are not already familiar with PostSharp, you may find it strangethat custom attributes can actually change the behavior of methods.

How Aspects MakeMultithreaded WPF EasierIt is sometimes claimed that 11 programmers out of 10 cannot implement multithreadingproperly. Although this statement is of course deliberately exaggerated, nobody wouldpretend it is not based on some truth: multithreading is difficult, especially when one hasto work directly with the primitives provided by the .NET Framework.Fortunately, aspect-oriented programming comes to the rescue. This article demon-strates that multithreaded programming can be as easy as applying custom attributes.

.NETC#

Page 63: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

Indeed, these new custom attributes will have the effect of modifyingthe methods to which they are applied. But PostSharp is not an ordi-nary library: it is a tool that inserts itself in the build process andenhances the assemblies after the compiler did its job (figure 1).

Fig. 1: PostSharp inserts itself into the build process and enhancesthe assemblies after the compiler completes its job.

So the first thing to do is to download PostSharp from http://www.postsharp.org/download and install it. Next, add Post Sharp.Public.dll andPostSharp.Laos.dll to your project references.We are now ready to develop our two aspects.Both custom attributes will be derived from the class PostSharp.Laos.OnMethodInvocationAspect. They will intercept calls to themethod to which they are applied.

Our first custom attribute, OnWorkerThreadAttribute, is trivial:

using System;

using System.Threading;

using PostSharp.Laos;

namespace ContactManager.Aspects

{

[Serializable]

public class WorkerThreadAttribute:

OnMethodInvocationAspect

{

public override void OnInvocation(

MethodInvocationEventArgs eventArgs)

{

ThreadPool.QueueUserWorkItem(

delegate { eventArgs.Proceed(); });

}

}

}

In this attribute, we implemented the method OnInvocation instead ofthe intercepted method.The statement eventArgs.Proceed() then proceeds with the invocationof the intercepted method. As can be seen, the implementation of thisaspect simply queues the execution of the intercepted method intothe thread pool.

The implementation of the OnGuiThreadAttribute is a little more com-plex, because we first need to check if we are already on the GUIthread. If we are not, we need to invoke the intercepted methodthrough Dispatcher.Invoke.

using System;

using System.Windows.Threading;

using PostSharp.Laos;

namespace ContactManager.Aspects{[Serializable]public class OnGuiThreadAttribute :OnMethodInvocationAspect

{public DispatcherPriority Priority { get; set; }

public override void OnInvocation(MethodInvocationEventArgs eventArgs)

{DispatcherObject dispatcherObject =(DispatcherObject) eventArgs.Delegate.Target;

if (dispatcherObject.CheckAccess()){// We are already in the GUI thread. Proceed.eventArgs.Proceed();

}else{// Invoke the target method synchronously.dispatcherObject.Dispatcher.Invoke(this.Priority,new Action(() => eventArgs.Proceed()));

}}

}}

Note the use of the eventArgs.Delegate property. The eventArgs pa-rameter contains everything we need to know about the interceptedmethod. Here, we are interested in the target instance of the method,because we need to cast it and retrieve its dispatcher.These two very simple custom attributes can have a significant impacton the way you think about multithreading. You can now forget aboutthe thread pool and the WPF message dispatcher. All you have to thinkabout is where the method should be executed: can it run asynchro-nously on a worked thread, or does it require a GUI thread? Usingthese two simple aspects makes your code easier to read and lesserror-prone.

Synchronizing Access to ObjectsPutting operations on threads is only one side of the equation, andarguably the easiest one. What is much more difficult, is to avoidconflicts when accessing shared resources from different threads.Because of this, we need to address the following issues:

• How do I ensure that an object is in a consistent state when a threadreads it? How can I be sure that another thread is not modifying itat that particular moment?

• How do I avoid two threads concurrently modifying the same objectand breaking its consistency?

• How do I prevent deadlocks?

In object-oriented programming, it often occurs that a significant partof the object model is a shared resource. This is typically the case withmodel objects in a Model-View-Controller. If the controller is allowed tomodify the model from different threads, proper thread synchronizationis necessary.

The Design PatternThe first and most important thing to do when coping with threadsynchronization is to identify good design patterns – there is no alter-native to good design. The design pattern I chose here is based onreader-writer locks (see the class System.Threading.ReaderWriter-LockSlim). These locks allow concurrent reader threads, but thewriter must have exclusive access. That is, a writer must wait for otherreaders, or other writers, to finish before starting, and will prevent them

magazine voor software development 63

Using these two simple aspectsmakes your code easier to read andless error-prone

.NETC#

Page 64: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

from starting until the writer finishes. Using these locks results inminimal thread contention (i.e. threads wait only minimally for eachother) and deadlocks. Alas, they also result in an extensive amount ofplumbing code. Our design pattern eventually associates a lock witheach object instance. However, if instance-level consistency is notenough, many instances can share the same lock. This is typically thecase when one object is aggregated into another one. For instance,one may want an order and its order lines to always be consistent. Inthat case, all instances forming together in the same order would sharethe same lock (see figure 2). As part of the design pattern, we decidedthat all synchronized objects should implement the IReaderWriter-Synchronized interface:

public interface IReaderWriterSynchronized

{

ReaderWriterLockSlim Lock { get; }

}

This interface will be useful when implementing the aspects.Additionally, since implementing IReaderWriterSynchronized is stillwriting plumbing code, we would prefer a custom attribute to do it forus. Let’s call it ReaderWriterSynchronizedAttribute.We further define custom attributes that, when applied to methods orproperty accessors, determine which kind of access to the object isrequired: ReaderAttribute, WriterAttribute or ObserverAttribute.

Any method that modifies the object, should be annotated with the[Writer] custom attribute. Methods that read more than one field of theobject should also be annotated with the [Reader] custom attribute (itis useless to synchronize methods or property getters performing asingle read access, because the operation is always consistent).Let’s set aside the observer lock for the moment. The next piece ofcode illustrates a synchronized class: all its public members areguaranteed to perform consistently in a multithreaded environment.

[ReaderWriterSynchronized]

public class Person

{

public string FirstName { get; [Writer] set; }

public string LastName { get; [Writer] set; }

public string FullName

{

[Reader]

get { return this.FirstName + " " + this.LastName; }

}

}

Observer LocksIn an MVC design, the view is bound to model objects. Model objectsexpose events that are raised when they are updated (typically thePropertyChanged event of the INotifyPropertyChanged interface). Theview (for instance, a data-bound WPF control) subscribes to this event.In certain cases, it is crucial that the object does not get modifiedbetween the time the event is fired and the time it is processed by theview. One example is with observable collections in WPF (INotifyCol-lectionChanged interface). Since the NotifyCollectionChangedEven-tArgs object contains item indices, it is essential that these indices stillrefer to the same items when the event is processed.So at first sight, it seems that we need to invoke events inside thewriter lock, doesn’t it? Wrong; this would cause a deadlock. Indeed,remember that the view is bound to the GUI thread. Therefore, thePropertyChanged event handler is dispatched to the GUI thread:

[GuiThread]

void person_PropertyChanged(

object sender, PropertyChangedEventArgs e)

{

this.label.Text = ((Person)e).FullName;

}

When you bind a control to a domain object using WPF Data Binding,the thread dispatching is completed transparently. When evaluatingthe FullName property, the GUI thread will require a read lock on themodel object. However, the object is already locked by the writer! TheGUI thread would therefore be required to wait for the worker threadto release the writer lock, but the worker thread has to wait until theGUI thread finishes the processing of the PropertyChanged event: weclearly would have a deadlock. Therefore, we need a locking level thatwould prevent any other writer, but would allow concurrent readers.This needed lock is called an upgradable reader lock: a reader lockthat can be upgraded to a writer lock, then downgraded back to areader lock. Upgradable readers allow concurrent readers, but forbidconcurrent writers or upgradable readers. This is exactly what weneed.

Instead of acquiring a writer lock, WriterAttribute will always acquire anupgradeable read lock and upgrade it to a write lock. As a result, itwill be possible to downgrade it into an ObserverAttribute.The following listing demonstrates how the Person class can be madeobservable, while ensuring multi-thread safety and avoiding deadlocks:

[ReaderWriterSynchronized]

public class Person : INotifyPropertyChanged

{

private string firstName;

private string lastName;

public string FirstName

{

get { return this.firstName; }

[Writer]

set

{

this.firstName = value;

this.OnPropertyChanged("FirstName");

}

64 MAGAZINE

Fig. 2: As a part of the system design, it is essential to identify whichparts of the object model should share multithreading consistency.(Note: Circles represent instances, rectangles represents groupsof instances sharing the same lock)

.NETC#

Page 65: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

}

public string LastName

{

get { return this.lastName; }

[Writer]

set

{

this.lastName = value;

this.OnPropertyChanged("LastName");

}

}

public string FullName

{

[Reader]

get { return this.firstName + " " + this.lastName; }

}

[Observer]

protected virtual void OnPropertyChanged(

string propertyName)

{

if (this.PropertyChanged != null)

this.PropertyChanged(this,

new PropertyChangedEventArgs(propertyName));

}

public event PropertyChangedEventHandler

PropertyChanged;

}

We are now complete with our design pattern. Now, let’s look at theimplementation of these custom attributes.

Implementing the ReaderWriterSynchronizedAttributeThis custom attribute must inject a new interface into the target typeand implement this interface. This can be realized easily by derivingthe CompositionAspect class.To accomplish this, two methods must be provided:

• GetPublicInterface should return the type of the interface to beinjected into the type. We simply return typeof(IReaderWriterSynchronized).

• CreateImplementationObject should return an object implementingthat interface. So we define a class ReaderWriterSynchronizedImpland return an instance of it.

The following code is a complete implementation of this procedure.

using System;

using System.Threading;using PostSharp.Laos;

namespace Starcounter.Threading{

[Serializable]public sealed class ReaderWriterSynchronizedAttribute:

CompositionAspect{

public override object CreateImplementationObject(InstanceBoundLaosEventArgs eventArgs)

{return new ReaderWriterSynchronizedImpl();

}

public override Type GetPublicInterface(Type containerType)

{return typeof(IReaderWriterSynchronized);

}

private class ReaderWriterSynchronizedImpl :IReaderWriterSynchronized

{private readonly ReaderWriterLockSlim @lock;

public ReaderWriterSynchronizedImpl(){this.@lock = new ReaderWriterLockSlim();

}

public ReaderWriterLockSlim Lock{ get { return this.@lock; } }

}}

}

Implementing ReaderAttribute, WriterAttribute and Observer-AttributeBefore implementing an aspect, it’s good to ask oneself: how wouldwe do it without aspects? What would the expanded code look like?To answer these questions, we would first have to determine if wealready hold the lock and, if not, acquire it. We would have to enclosethe whole method body in a try block and release the lock, if it wasacquired, in the finally block. So our methods would look like this:

void MyMethod(){bool acquire =!(this.myLock.IsWriteLockHeld ||this.myLock.IsReadLockHeld ||this.myLock.IsUpgradableReadLockHeld);

if ( acquire ) this.myLock.EnterReadLock();try{

// Original method body.}

finally{if ( acquire ) this.myLock.ExitReadLock();

}}

PostSharp provides an appropriate kind of aspect for this transfor-mation: OnMethodBoundaryAspect. It wraps the original method bodyinside a try…catch…finally block and gives us the opportunity toexecute code before the method, upon successful execution, uponexception, and in the finally block. This is exactly what we need.

The following is the code for the Reader attribute. Note that theWriter and Observer attributes are similar.

[Serializable]

[MulticastAttributeUsage(MulticastTargets.Method,

TargetMemberAttributes=MulticastAttributes.Instance)]

public class ReadLockAttribute : OnMethodBoundaryAspect

{

public override void OnEntry(

MethodExecutionEventArgs eventArgs)

{

ReaderWriterLockSlim @lock =

((IReaderWriterSynchronized)eventArgs.Instance).Lock;

if ([email protected] &&

[email protected] &&

[email protected])

{

magazine voor software development 65

.NETC#

Page 66: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

eventArgs.MethodExecutionTag = true;

@lock.EnterReadLock();

}

else

{

eventArgs.MethodExecutionTag = false;

}

}

public override void OnExit(

MethodExecutionEventArgs eventArgs)

{

if ((bool) eventArgs.MethodExecutionTag)

{

((IReaderWriterSynchronized) eventArgs.Instance).

Lock.ExitReadLock();

}

}

}

In the preceding code, we implemented two handlers: OnEntry andOnExit. In order to obtain access to the ReaderWriterLockSlim object,we need to cast the target instance (available on the eventArgs.Instance property) to the IReaderWriterSynchronized interface andretrieve the Lock property. The OnEntry method needs to store the in-formation somewhere, whether the lock was acquired by us or not.Indeed, this information will be required by the OnExit method. For thispurpose, we can use the eventArgs.MethodExecutionTag property.Whatever a handler stores in this property will be available to the otherhandlers. Note the presence of the MulticastAttributeUsage customattribute on the top of our class. It means that the aspect is to be usedon instance methods only, so it is not to be used on constructors oron static methods.

Gael Fraiteur

Gael Fraiteur is the founder and pro-ject leader of PostSharp, the mostpopular aspect weaver for .NET. Heis an occasional speaker at interna-tional conferences and user groups.Gael is Microsoft Certified SolutionDeveloper for Microsoft.NET, andhas an advanced knowledge of Ora-cle Server, Microsoft SQL Serverand TIBCO EAI. He has experience

in telecom and ISV industries. Gael speaks French, English,Czech and Flemish. He lives in Czech Republic.

ConclusionsMultithreaded programming can be simplified by adequately raisingthe level of abstraction. But why should every programmer care aboutsynchronization primitives? In an ideal world, it should be enough if heor she annotates methods with a custom attribute determining thethread affinity or the locking level required by the method. This is whatwe have demonstrated in this article by using six aspects: OnWorker-Thread and OnGuiThread for thread affinity, and ReaderWriterSyn-chronized, Reader, Writer and Observer for the locking level.However, multithreading is just one possible field of application ofaspect-oriented programming. Caching, transaction management,exception handling, performance monitoring, and data validation areother concerns where aspect-oriented programming can advantage-ously be applied. By providing a new way to encapsulate complexity,aspect-oriented programming results in shorter, simpler and more rea-dable code, therefore being less expensive to write and maintain. •

.NETC#

Advertentie Twice IT

Page 67: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

DELPHI

best version of Delphi ever a try!

Steps for Building DataSnap 2009 Server ApplicationCreate a new Delphi (or C++Builder) ”VCL Forms Application”, click on”Save All” from the ”Files” menu. Save the main form’s unit as ”uForm-Server” and the project as ”DelphiDataSnapEchoServer”. In the ObjectInspector change the ”Name” property of the form to ”FormServer”and ”Caption” property to ”Delphi 2009 DataSnap Echo Server”.Now we are going to transform this standard Delphi application into aDataSnap server. This is done with components from ”DataSnapServer” tab. It contains three different components and we need themall. Double-click on ”TDSServer”, ”TDSTCPServerTransport” and”TDSServerClass” components in the Tool Palette to add them to theserver form.

Fig. 1: DataSnap Server Application Main Form

The ”DSServer1” component is the logical heart of the DataSnapserver application. It contains ”Start” and ”Stop” methods for startingand stopping the server, and also a very handy ”AutoStart” property.By default it is set to ”True”, so the server starts automatically at theapplication startup. You only need one ”TDSServer” component perserver application. The ”DSTCPServerTransport1” component con-tains the ”TIdTCPServer” Indy component that implements a multi-threaded TCP server listening for incoming client connections onmultiple threads. This component does not have any events, but itcontains a ”Server” property that needs to be set to ”DSServer1”. Italso has a ”Port” property that indicates the TCP port to be used.By default it is set to port 211. The ”DSServerClass1” componentrepresents... yeah, you are right... a server class ☺. It also has the”Server” property that needs to be set to ”DSServer1”. In this way allthree components are linked together. The ”TDSServerClass”component contains ”OnGetClass” event that must be implementedby the programmer. If you fail to implement this event, the applicationwill, immediately after a start, raise a TDBXError event with the mes-sage ”OnGetClass event not set or it did not provide a class reference”.The ”OnGetClass” event has the ”PersistentClass” argument that ispassed by reference. In the event handler code the programmer needsto assign to ”PersistentClass” a class reference to a server class.

Pawel Glowacki

Getting Started with

Delphi DataSnap 2009IntroductionOne of the main new features of RADStudio 2009 is the DataSnap 2009framework for building multitier data-base applications. In fact DataSnap2009 is more than that. It is a compo-nent-based architecture for creatingarbitrary applications that communicateover the network. It has never beeneasier to quickly create server and clientapplications in Delphi and C++Builder!

The new DataSnap 2009 architecture extends the DBX4 databasedriver framework introduced in Delphi 2007 and C++Builder 2007. TheDBX4 framework abstracted away the concept of a database driverand introduced the notion of extensible command types. DataSnap2009 takes advantage of the DBX4 extensibility and adds to the port-folio of existing databases drivers the new ”DataSnap” driver that -from the perspective of a client application - looks very much like adatabase, but in reality provides connectivity to a DataSnap serverapplication. Similarly the new ”DSServerMethod” command type forinvoking methods on server objects has been added to ”TDBX Com-mandTypes” class.

The DataSnap 2009 is part of the Visual Component Library (VCL) thatis shared between Delphi and C++Builder. In this article I’m going tofocus on Delphi 2009, however almost all of the functionality describedin here is also applicable to C++Builder 2009.

DataSnap 2009 ”Hello World”In this article I’m going to walk you through the steps for building asimple ”Hello World” DataSnap 2009 system consisting of a serverand a client application. The server application will provide the ”Echo”function that accepts a string and returns a string that echoes the ori-ginal value. The client application will provide means for entering anarbitrary string, call the ”Echo” function with the string provided anddisplay the string returned from the server. Too simple? Yeah... but agood starting point for more complex things!Are you ready? Is your Delphi 2009 already installed and started? Youdo not have Delphi 2009 installed? Shame on you ;-) Grab the trialfrom http://www.codegear.com/products/delphi/win32 and give the

It has never been easier to quicklycreate server and client applicationsin Delphi and C++Builder!

magazine voor software development 67

Page 68: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

This is probably the one single most important concept to understandabout the DataSnap2009 architecture. We are assigning to ”Persis-tentClass” a class reference and not an object reference.

The DataSnap server will automatically create and destroy instancesof server classes. The instancing of a server class is controlled by the”TDSServerClass.LifeCycle” property that can have one of the threepossible values: ”Server”, ”Session” and ”Invocation”.The lifecycle set to ”Server” means that the DataSnapserver willcreate one instance of a server class that will be used by all clientsconnected to the server application. This represents a ”singleton”pattern. Be careful when using ”Server” lifecycle as your server classimplementation needs to be thread-safe; it is possible that this single-ton object will be accessed simultaneously from multiple threads.The default ”LifeCycle” value is ”Session”. This means that the Data-Snap server will create one instance of a server class for everyconnected client. This is similar to the concept of a ”stateful” sessionbean in JEE.The third possible value for ”LifeCycle” property is ”Invocation”. Aserver class instance will be created and destroyed for every methodcall arriving from a client and the state of a server class will not bepreserved between method calls.

In order to implement ”OnGetClass” event we need to add to ourDataSnap server project a server class. Select ”File | New | Other” from”File” menu and double-click ”Server Module” icon from the ”DelphiFiles” category.

Fig. 2: New DataSnap 2009 ”Server Module” Item

This will add a new server module to the project. Save the new unit as”uServerModule”. At this stage I’m going to do one optional step thataims at highlighting the fact that it is the server that manages the life-cycle of server objects. The server module is ultimately derived from adata module and the Delphi designer automatically added it to a list ofauto-created forms in our server application. This is unnecessary, soyou can go to ”Project | Options” dialog and in the ”Forms” sectionremove the ”DSServerModule1” from the list of auto-created forms.

Fig. 3: DSServerModule1 does not need to be auto-created

It is also safe to comment out the global ”DSServerModule1: TDSSer-verModule” variable from the server module unit as it is never used.

Now we are going to implement a simple ”Echo” function that willaccept a string and return a string. I’m going for an enterprise strengthecho functionality so my implementation will echo the argument notonce, but twice;-).The resulting server module implementation looks like this:

unit uServerModule;

interface

uses

SysUtils, Classes, DSServer;

type

TDSServerModule1 = class(TDSServerModule)

private

{ Private declarations }

public

function Echo(s: string): string;

end;

//var

// DSServerModule1: TDSServerModule1;

implementation

{$R *.dfm}

{ TDSServerModule1 }

function TDSServerModule1.Echo(s: string): string;

begin

Result := ‘Delphi DataSnap 2009 is echoing ‘ +

s + ‘ ... ‘ + s;

end;

end.

Listing 1: DataSnap Echo server module implementation

The last step is to implement the ”DSServerClass1.OnGetClass” event.In the server main form select the DSServerClass1 component and inthe Object Inspector double-click on the ”OnGetClass” event togenerate an empty handler. Add ”uServerModule” to the ”uses” clauseof the main form and implement the event.

The DataSnap server will automaticallycreate and destroy instances of serverclasses

68 MAGAZINE

DELPHI

Page 69: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

implementation

uses uServerModule;

{$R *.dfm}

procedure TFormServer.DSServerClass1GetClass(

DSServerClass: TDSServerClass;

var PersistentClass: TPersistentClass);

begin

PersistentClass := TDSServerModule1;

end;

end.

Listing 2: DSServerClass1.OnGetClass event code

Our DataSnap Echo server application is now complete.

Client and Server Applications need a piece of shared know-ledge to communicateIf you want to have two arbitrary applications to communicate, theremust be some form of a contract in place that describes whatfunctionality a client can access from a server.

Different distributed computing technologies have different ways ofsolving this problem. In CORBA the contract is described in the formof an Interface Definition Language (IDL) document, in DCOM there isa Type Library. In Web Services we have a Web Service DescriptionLanguage (WSDL) that is used by client applications to generateproxies. DataSnap 2009 does not have any static form of a servicedescription. In order to create a DataSnap client you need to have ac-cess to a running server application at design time. This is similar toWeb Services where the WSDL document can be typically obtainedon-the-fly from a running Web Service application.

Steps for Building DataSnap 2009 Client ApplicationThe DataSnap Server application is already opened in the Delphi IDEand it is the most convenient to add a client application to a projectgroup so we could switch between two projects inside the IDE.Right-click on the ”ProjectGroup1” in the Project Manager, select ”AddNew Project” from the context menu and go for the new Delphi ”VCLForms Application”. Save all from the ”File” menu. Save the main formunit as ”uFormClient”, the project as ”DelphiDataSnapEchoClient” andthe project group as ”DelphiDataSnapEchoGrp”. Click somewhere onthe form to make sure it is selected in the Object Inspector. Set the”Name” property to ”FormClient” and the ”Caption” property to ”Del-phi 2009 DataSnap Echo Client”.

You can have only one project active at any given point of time in RADStudio IDE. The Project Manager indicates the active project bydisplaying the project name with bold font. You can also see the nameof the active project in the title of the RAD Studio window itself.Double-click on the project name in the Project Manager to make theproject active.During the development of a DataSnap client application we need to

have access to a running instance of the server application. Double-click on the ”DelphiDataSnapEchoServer.exe” in the Project Managerto make it active and select ”Run | Run Without Debugging” from themain menu to run the server application. We need to have it runningwhile developing the client. You can safely minimize the server appli-cation window. Double-click on the ”DelphiDataSnapEchoClient.exe”in the Project Manager to switch back to client application.

As discussed earlier DataSnap 2009 extends the DBX4 databasedriver architecture by implementing a special ”DataSnap” driver thatfrom the perspective of a client looks like a connection to a database,but in fact it provides connectivity to DataSnap servers. That is thereason that we start client development from a ”TSQLConnection”component.Make sure that the client form is opened in the IDE, go to Tool Paletteand double-click on the ”TSQLConnection” component from the”dbExpress” category to add it to the form. Go to Object Inspector,drop down the ”Driver” property and select ”Datasnap” driver. Notethat the ”Driver” property can be now expanded and it contains Data-Snap specific sub-properties. Make sure that the ”HostName” is setto ”localhost” (or the DSN name or the IP address of the machinewhere the server is running) and the ”Port” number is set to 211. The”Port” property has to match the value of the ”DSTCPServerTrans-port1.Port” property in the server application.Additionally change the ”SQLConnection1.LoginPrompt” property to”False” to prevent username and password dialog to popup every timewe connect to the server.Right-click on the ”SQLConnection1” component on the form andselect ”Generate DataSnap Client Classes” from the context-menu.

Fig. 4: Generate DataSnap client classes from SQLConnection1context menu

This will add a new unit to the client project. Save it as ”uClientClas-ses”. The generated unit will contain the ”TDSServerModule1Client”class that can be used to communicate with the server as if it were alocal object. DataSnap 2009 uses RTTI (Delphi ”reflection” mecha-nism) for discovering all public and published methods on server clas-

If you want to have two arbitraryapplications to communicate, theremust be some form of a contract inplace that describes what functionalitya client can access from a server

magazine voor software development 69

DELPHI

Page 70: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

ses and generates proxy classes with matching method signatures.In order to call any method from our server it is necessary to create aninstance of ”TDSServerModule1Client” and call its ”Echo” method thattakes and returns a string.Switch to ”FormClient” and add to it ”TButton” and ”TEdit” compo-nents from the Tool Palette. Add ”uClientClasses” to the ”uses” clauseof the ”FormClient” (for example using ”File | Use Unit” menu). Doubleclick on the ”Button1” component and add the following code to thegenerated ”OnClick” event that creates an instance of a proxy class,calls its ”Echo” method passing the contents of the edit box anddisplays the result in a dialog box.

uses uClientClasses;

{$R *.dfm}

procedure TFormClient.Button1Click(Sender: TObject);

var proxy: TDSServerModule1Client;

begin

proxy := TDSServerModule1Client.Create(

SQLConnection1.DBXConnection);

try

ShowMessage(proxy.Echo(Edit1.Text));

finally

proxy.Free;

end;

end;

end.

Listing 3: DataSnap ”Echo” client implementation

Note that the ”TDSServerModule1Client” constructor requires a”TDBXConnection” argument that represents the non-visual DBX4connection object. Luckily the ”TSQLConnection” class exposes itsinternal ”DBXConnection” as a property that we can use in our code.That’s it! Just run the client, enter something into the edit box and clickthe button to call the ”Echo” method on the server and display theresult.

Fig. 5: DataSnap ”Echo” client in action

SummaryThe DataSnap 2009 architecture for building multitier databaseapplications is one of the most interesting and innovative newfeatures introduced in RAD Studio 2009. It can be used not only forbuilding database application but also for arbitrary client/server sys-tems that communicate over the network using the TCP protocol. RADStudio 2009 contains Delphi 2009, C++Builder 2009 for buildinghigh-performance, native Windows applications and the new DelphiPrism for building .NET applications. DataSnap 2009 technology isavailable in all of these environments.

The objective of this article was to provide step-by-step instructions forbuilding the simplest possible ”Hello World” client and server Data-Snap 2009 applications to get you up and running with this powerfulnew technology.But DataSnap 2009 is much more than that. In addition to returningsimple types like ”string” it is possible to pass more complex types likearray or ”TDataSet”. The new ”TSqlServerMethod” component can beused to call server methods without generating client classes, and new”TDSProviderConnection” component make it easy to builddatabase applications that can easily apply database updates fromclient back to server. With the ”ServerConnection” sub-property of theDataSnap ”TSQLConnection.Driver” it is even possible to access theserver-side database connection directly from the client. Thisfunctionality is key for building Delphi Prism managed .NET DataSnapclients that communicate with native Delphi 2009 or C++Builder 2009DataSnap servers.The electronic version of the application described in this article can bedownloaded from the SDN-site. •

Pawel Glowacki

Paweł Głowacki is Senior SoftwareConsultant, Presales Engineer,Technical Evangelist and blogger atEmbarcadero Technologies - themakers of Delphi and C++Builder.You can reach Paweł at [email protected] or byvisiting his blog at http://blogs.codegear.com/pawelglowacki

70 MAGAZINE

DELPHI

Delphi TIP:FillChar en Fill/ZeroMemoryDelphi 2009 ondersteunt Unicode en een Char is niet langereen Char maar een 2-byte WideChar. Toch werkt FillChar nogmet Bytes in plaats van met Char (vanwege backwardscompatibility). Dus als we een string met iets willen vullen, danmoeten we niet het aantal Chars maar het aantal Bytesopgeven:

varBuffer: array[0..255] of Char;

beginFillChar(Buffer, Length(Buffer) * SizeOf

(Buffer[0]), 0);

In plaats van SizeOf kunnen we ook de nieuwe functieStringElementSize gebruiken:

varBuffer: array[0..255] of Char;

beginFillChar(Buffer,Length(buffer) * StringElementSize(Buffer),0);

Overigens kunnen we in dit specifieke voorbeeld ook Si-zeOf(Buffer) gebruiken in plaats van de vermenigvuldiging vanhet aantal elementen met de size van de individuele elemen-ten. Omdat FillChar niet langer Chars maar Bytes vult, zou eenbetere naam FillByte of FillMemory zijn geweest. Toevallig is ernu ook een FillMemory, die intern FillChar aanroept. Net als eenZeroMemory, die FillChar aanroept met #0 als opvulteken.

Page 71: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

Advertentie Sybase iAnywhere / ELMO ICT Systems

Page 72: MAGAZINE - SDN · Nummer100februari2009 SDNMagazineverschijntelkkwartaaleniseenuitgavevanSoftwareDevelopmentNetwork 100  INDITNUMMERO.A.: SnelWebsitesOntwikkelenmetASP ...

Advertentie Bridge Incubation Group b.v.