E D I T O R I A L E
N. 65 - Settembre/Ottobre 2005 VBJ4
Come potete leggere in questo numero della rivista, le novità alla PDC 2005 sono tante e tutte ben corpose. Io quest’anno non ho partecipato, quindi posso al massimo ragionare sul
materiale messo a disposizione sul sito Microsoft e non potevo certo resistere alla curiosità di capire in che direzione stanno an-dando Visual Basic e C#. Così mi sono tenuto un pomeriggio da parte per dare un’occhiata agli articoli già disponibili.
Alla fine del pomeriggio mi sono ritrovato con sentimenti ambi-valenti. Da una parte c’era l’innegabile soddisfazione di vedere che
il Visual Basic continua a colmare il gap rispetto al C# – a dispetto delle mille cassandre a cui piace etichettare il VB come un linguaggio di seconda scelta.
A parte queste e altre (piccole) piacevolezze, devo però dire che in generale quello che ho letto non mi ha affatto entusiasmato. La novità principale di VB9 e C#3 è il supporto di Linq, una specie di embedded SQL che permette di immergere query SQL direttamente nel codice. In teoria, Linq dovrebbe promuovere una più stretta integrazione tra i database relazionali e i modelli ad oggetti (intrinsecamente gerarchici) costruiti nella propria appli-cazione. In pratica, però, questa integrazione non si può affatto dare per scontata. Alcuni progetti simili – primo tra tutti, ObjectSpaces – sono falliti oppure comunque non hanno mai conquistato il cuore degli sviluppatori, che continuano a produrre ottime applicazioni gestionali senza bisogno di queste infrastrutture (o sovrastrutture, se preferite). L’altro punto importante è che se Linq non offrirà prestazioni identiche a quelle offerte da SQL tradizionale, nessuno vorrai mai utilizzarlo.
Il problema, comunque, non è tanto quello di aggiungere feature che poi nessuno userà realmente, quanto il fatto che il supporto per Linq costringe ad altre “novità”, ad esempio gli anonymous types. E a loro volta, gli anonymous types richiedono di rilassare la sintassi di alcune istruzioni. Ad esempio, sarà possibile dichiarare una variabile senza la clausola As, lasciando al compilatore il compito di determinare il tipo necessario. Con tanti saluti alla leggibilità del codice!
Il discorso è complesso e non è certo adatto alla paginetta che questo editoriale mi concede. La stessa Microsoft ha dichiarato che questa pre-release serve soprattutto a raccogliere le impressioni della comunità degli sviluppatori. Ho scritto qualcosa sul mio blog e sicuramente tornerò sull’argomento man mano che altre novità diventeranno disponibili, e sarà interessante confrontare le opinioni di tutti coloro che usano questi strumenti “sul campo”.
Francesco [email protected]
www.dotnet2themax.it/blog
Il futurodei linguaggi .NET
o n l i n e . i n f o m e d i a . i tn. 65 - settembre/ottobre 2005bimestrale - anno undicesimo
Direttore Re spon sa bi leMarialetizia Mari ([email protected])
Direttore EsecutivoFran ce sco Balena ([email protected])
Managing EditorRenzo Boni ([email protected])
CollaboratoriMaurizio Codogno
Stefano Corti Emanuele DelBono Raffaele Di Natale
Fabio Fabozzi Claudio Maccari Angelo Ossola Fabio PerronePaolo Pialorsi
Francesco Quaratino Stefano Sanna
Lorenzo Vandoni
Direzione Natale Fino ([email protected])
Marketing & Advertising Segreteria: 0587/736460
AmministrazioneSara Mattei
GraficaManola Greco ([email protected])
Technical BookLisa Vanni ([email protected])
Segreteria Enrica Nassi
StampaTIPOLITOGRAFIA PETRUZZI
Citta’ di Castello (PG)
Ufficio AbbonamentiTel. 0587/736460 - Fax 0587/732232e-mail: [email protected]
www.infomedia.it
Gruppo Editoriale Infomedia srlVia Valdera P., 116 - 56038 Ponsacco (PI) Italia
Tel. 0587/736460 - Fax 0587/[email protected]
Sito Web www.infomedia.it
Manoscritti e foto originali anche se non pub bli ca ti, non si restituiscono. È vietata la ri pro du zio ne
anche parziale di te sti e immagini.
Si prega di inviare i comunicati stampa e gli inviti stampa per
la redazione all’indirizzo: [email protected]
Visual Basic Journal è una rivista diGruppo Editoriale Infomedia S.r.l. Via Valdera P, 116 Ponsacco - Pisa.
Registrazione presso il Tribunale di Pisa n. 20/1999
6
SOMMARIO
VBJ N. 65 - Settembre/Ottobre 2005
N.65S E T T EM B R E / OT TO B R E
8Reportage da PDC 2005Dall’11 al 16 settembre 2005 si è tenuta a Los Angeles la Professional Developer Conference 2005, orga-nizzata da Microsoft Corporation.
a cura di DevLeap
SPECIALE
20Controlli multimediali in Visual Basic 6Non capita spesso di realizzare software dai contenuti multimediali. Questo articolo illustra le modalità di gestione di elementi multimediali in VB6: non sarà forse molto originale, ma di sicuro se ne potrà apprezzare la valenza evocativa per coloro che già sanno ed educativa per coloro che ancora non sanno.
di Fabio Fabozzi
Controllo Remoto in Visual Basic .NET (seconda puntata)SQL Server 2005 rappresenta una grande evoluzione nella gestione di database. Vediamo come l’integrazione con il framework .NET possa migliorare la vita degli sviluppatori e dei DBA.
di Stefano Corti
Supporto XML in SQL Server 2005Sql Server 2005 introduce il tipo di dato nativo XML per trattare documenti e frammenti XML, insieme a metodi specifici per interrogare e modificarne il contenuto. XQuery è il linguaggio implementato per le interrogazione dei dati XML attraverso i nuovi metodi di interrogazione.
di Francesco Quaratino
MULTIMEDIA
APPLICAZIONI
26
DATABASE
33
7N. 65 - Settembre/Ottobre 2005 VBJ
All’indirizzo ftp.infomedia.it/pub/VBJ sono liberamente scaricabili tutti i listati relativi agli articoli pubblicati. La presenza di questa immagine indica l’ulteriore disponibilità, allo stesso indirizzo, di un progetto software relativo all’articolo in cui l’immagine è inserita. Il nome identifica la cartella sul sito ftp.
Codice allegato
Editoriale 4
.NET Tools 52
Libri 65
RUBRICHE
Sviluppare Servizi Windows con .NETIn passato scrivere Servizi Windows richiedeva la conoscenza del C o del C++ ma con l’avvento del framework .NET e dei suoi nuovi linguaggi C# e VB.NET, lo sviluppo di questo tipo di applicazioni non è mai stato così semplice. Vediamo come scriverli, installarli e testarli.
di Emanuele Delbono e Claudio Maccari
SOAP Messaging con WSEVediamo le principali caratteristiche di Microsoft Web Services Enhancements dal punto di vista del SOAP Messaging.
di Paolo Pialorsi
I design pattern più famosi implementati in VB.NET (quarta puntata)Il pattern Adapter suggerisce come modificare una classe server in modo da adattarsi all’interfaccia richiesta da altre classi client.
di Lorenzo Vandoni
.NET
38
45
SOFTWARE ENGINEERING
60
8 VBJ N. 65 - Settembre/Ottobre 2005
Dall’11 al 16 settembre 2005 si è tenuta a Los Angeles la Professional Developer Conferen-ce 2005 (PDC05). Si tratta di un evento tec-
nico organizzato da Microsoft Corporation e rivolto a programmatori che utilizzano le tecnologie di Re-dmond per lo sviluppo delle proprie applicazioni. È un evento che non ha una cadenza fissa, ma che vie-ne organizzato solo quando Microsoft ha qualcosa di particolarmente interessante da annunciare agli svi-luppatori. Quest’anno gli argomenti di maggior rilievo sono stati l’imminente rilascio del .NET Framework 2.0, accompagnato da SQL Server 2005 e BizTalk Ser-ver 2006, ma anche e soprattutto l’annuncio di nuove tecnologie e prodotti che vedranno la luce nei prossi-mi due anni. Tra questi possiamo sicuramente citare WinFX, che rappresenta il framework di base per le applicazioni business dei prossimi anni. A oggi Win-FX è rappresentato dall’insieme di Windows Presen-tation Foundation (WPF, conosciuto con il nome in co-dice “Avalon”) per la gestione dell’interfaccia utente, Windows Communication Foundation (WCF, nome in codice “Indigo”) per lo strato di comunicazione e ser-vizi SOAP e Windows Workflow Foundation (WWF, sconosciuto ai più sino a PDC05) per la gestione dei processi e flussi aziendali. Un altro argomento che ha avuto il suo peso è l’anteprima della prossima versio-ne di Microsoft Office, ormai giunto alla versione 12, e di Windows SharePoint Services 3.0.
Grande rilievo hanno avuto an-che la versione 3.0 del linguaggio C# e la tecnologia .NET Langua-ge Integrated Query (LINQ). An-che ATLAS, estensione del mo-tore di ASP.NET per supportare il tanto discusso AJAX (Asyncro-nous Javascript And XML), si è fatto spazio fra le numerose ses-sioni dell’evento. Infine per la parte sistemi sono stati presenta-ti Windows Vista e Windows Lon-ghorn Server. Di seguito parlere-mo di alcuni di questi argomenti in maggiore dettaglio.
Windows WorkflowFoundation
Da alcuni mesi ormai si parlava in modo informale di un possibile rilascio, da parte di Microsoft, di un motore di workflow integrato nel sistema operativo Windows e distribuito gratuitamente agli utenti del sistema stesso. In que-sta PDC è stato definitivamente svelato il progetto Windows Work-flow Foundation (WWF), al quale pare che stia lavorando da tempo un gruppo costituito anche da al-cuni membri del team di BizTalk Server. Il progetto dovrebbe vede-re la luce nella seconda metà del prossimo anno e pare che sarà offerto gratuitamente, un po’ come è stato per Windows Sha-repoint Services rispetto a Win-dows Server 2003. Si tratta di un
Paolo Pialorsi è un consulente e autore specializzato nello
sviluppo di Web Service e soluzioni Web con il Framework
.NET di Microsoft. Lavora nell’omonima società Pialorsi Sistemi
S.r.l. e fa parte del gruppo DevLeap. Può essere contattato via
email: [email protected]. Paolo mantiene un blog all’indirizzo:
http://blogs.devleap.com/paolo/ .
SPECIALE
Reportage da PDC 2005
a cura di DevLeap
Dall’11 al 16 settembre 2005 si è tenuta a Los Angeles la Professional Develo-
per Conference 2005, organizzata da Microsoft Corporation.
9N. 65 - Settembre/Ottobre 2005 VBJ
framework applicativo sviluppato in codice ma-
naged .NET e pensato per gestire/creare work-
flow che interagiscono con i vari servizi e pro-
dotti software Microsoft e con applicazioni di
terze parti. WWF prevede un’architettura che
si appoggia a un motore di base, in grado di ge-
stire eventi, timer, flussi e relativi stati. Questi
sono poi legati all’esecuzione e all’esito di attivi-
tà, che non sono altro che classi .NET; per i casi
di uso più ricorrente (invio email, attesa compi-
lazione form, approvazione/non approvazione di
un documento, chiamata a un Web Service, ecc.)
potremo contare su classi già presenti nel pro-
dotto, mentre per tutti gli altri si possono crea-
re classi in appositi progetti .NET, che verranno
configurati in WWF. Il motore di WWF prevede
la possibilità di realizzare flussi automatici o che
interagiscono con l’utente finale. Nel secondo
caso è possibile utilizzare vari strumenti di inte-
razione con l’utente come: Office InfoPath, form
e email con voting button di Outlook, pagine ad
hoc in Windows Sharepoint Services, Web Servi-
ce; ecc. L’hosting dei flussi è altrettanto variabi-
le e dipende dal particolare tipo di implementa-
zione che si vuole realizzare. Al minimo possia-
mo creare un’applicazione Console, comandando
da codice il flusso, oppure possiamo definire ap-
plicazioni Windows Forms o Web, eventualmen-
te utilizzando in questo secondo caso il motore
di Sharepoint 3.0, come vero host dei flussi. Lo
storage dei flussi e dei loro stati di avanzamen-
to è personalizzabile e configurabile. Possiamo
appoggiarci a semplici flussi in memoria, sen-
za alcun tipo di persistenza, oppure è possibile
serializzare i flussi in file XML su disco (o altri
storage). Per scenari più complessi, dove deve
essere garantito un elevato livello di affidabili-
tà, c’è la possibilità di utilizzare Microsoft SQL
Server come storage permanente, transaziona-
le e sicuro dei dati di WWF. Operativamente la
creazione di un flusso, per quanto si è visto in
una prima versione beta, è realizzabile utiliz-
zando una delle seguenti strade:
• Sviluppo di codice .NET su misura. Soluzio-
ne molto versatile, ma relativamente impe-
gnativa, oltre a richiedere uno sviluppatore
.NET per poterla realizzare;
• Disegno del flusso con la prossima versione
di FrontPage (quella che sarà presente in Of-
fice 12 e che non ha quasi più niente a che
vedere con FrontPage attuale) tramite l’uti-
lizzo di un wizard grafico su più passi;
• Definizione del flusso tramite Visual Studio
2005 (qualsiasi versione, anche le Express
gratuite) utilizzando un apposito designer,
integrato con l’IDE. In questo caso è pre-
vista la scrittura di piccole porzioni di co-
dice, associate ai singoli eventi del flusso.
Tutti i flussi, a prescindere da come ven-
gono disegnati, sono rappresentabili e/o
esportabili in formato XOML, una gram-
matica XML pensata per descrivere stati,
azioni e regole del flusso. In questo modo
potremmo anche definire un flusso a parti-
re da un XML “grezzo” e da una trasforma-
zione XSLT. Si possono definire flussi a fasi
singole e con stati finiti, oppure si possono
creare flussi multi-attività e a stati variabili.
Dal momento che parte del motore di WWF
è stato “importato” e adattato dal designer
di orchestration di BizTalk Server, non ven-
gono meno alcune delle funzionalità chiave
di BizTalk, come la possibilità di interagire
con Web Service esterni e di svolgere atti-
SPECIALE
10 VBJ N. 65 - Settembre/Ottobre 2005
vità transazionali e long running, con even-
tuali compensating transaction. Non a caso
si è lasciato intendere che la prossima ver-
sione di BizTalk Server, dopo l’imminente
versione 2006, possa utilizzare direttamente
WWF per la definizione dei suoi flussi e or-
chestration.
Microsoft Office 12Office 12 sarà la release con le maggiori no-
vità percepibili dall’utente rispetto alla ver-
sione precedente sin dai tempi di Office 97.
Il motivo è che l’interfaccia utente cambia ra-
dicalmente: via i menu, via le toolbar, avremo
un nuovo elemento, il Ribbon, che agisce in
modo contestuale alle azioni dell’utente. Ap-
parentemente un Ribbon è una nuova forma
di toolbar, in realtà ci sono regole ben precise
su ciò che può contenere, su cosa può presen-
tare e come deve interagire con l’utente. Tec-
nicamente un Ribbon è un contenitore di Tab,
ciascuno dei quali può avere più Chunk che
a loro volta contengono oggetti di vario tipo
(Button, Label, EditBox, CheckBox, Gallery e
anche Menu). L’impatto, vedendo una foto, è
di estrema diffidenza (perché mai hanno cam-
biato tutto?). Ma l’esperienza d’uso è incredi-
bile: fondamentalmente Office 12 ha gli stes-
si comandi di controllo del layout (in Word ed
Excel) di Office 2003 (e in gran parte anche di
Office XP, 2000 e 97!) ma semplicemente... mol-
ti non sanno nemmeno dove cercarli. Sembra
di usare un prodotto completamente nuovo, le
funzionalità sono proposte esattamente quan-
do servono e in maniera intuitiva, con poche
(spesso nessuna) dialog box.
Ci si può chiedere perché si parli di interfac-
cia utente di un prodotto come Office in una
rivista di programmazione: il punto è che Of-
fice ha sempre stabilito le linee guida di in-
terfaccia utente per le applicazioni “cool” in
Windows. Non è detto che il modello di Office
12 sia sensato per un’applicazione con 10 fun-
zioni in tutto, ma molti gestionali potrebbero
trarne enormi vantaggi in termini di semplici-
tà d’uso. Ma avere uno strumento non significa
essere in grado di usarlo proficuamente: die-
tro Office 12 devono esserci anni-uomo di stu-
dio delle migliori modalità di interazione con i
singoli comandi, per arrivare ad avere qualco-
sa che sembra semplice da usare quanto una
calcolatrice. Sembra facile, ma non lo è assolu-
tamente. Dal punto di vista funzionale, Office
12 ha diversi “pilastri”: integrazione comple-
ta con SharePoint v3, integrazione di funzioni
di WorkFlow, componenti Office lato server e
funzioni di visualizzazione dati avanzate (Bu-
siness Intelligence) in Excel.
Partiamo dai componenti Office lato server:
l’idea è più o meno quella di consentire a un
utente di “pubblicare” un foglio Excel su un
server producendo pagine HTML che conten-
gono il risultato di un foglio Excel, aggiornato
in base ai dati letti dinamicamente dal server.
In altre parole, se si crea un foglio Excel che
presenta il totale delle vendite diviso per ca-
tegoria di articolo, estraendo tali informazioni
da un database relazionale o multidimensiona-
le (Analysis Services), pubblicando il foglio sul
server si ottiene una pagina HTML con i dati
aggiornati al momento della richiesta (e non
solo della pubblicazione!); tutto questo avvie-
ne senza avere sul server un’istanza di Excel,
come potrebbe avvenire oggi (ma dal punto di
vista della scalabilità si tratta di un incubo, si
mette su un server un componente pensato
per un desktop client dedicato). Questo porta
a un mondo dove gli utenti possono definire
dei report da pubblicare sulla Intranet azien-
dale usando il loro amato foglio Excel. Questa
sola funzione vale oro. La funzione di workflow
(implementata basandosi su WWF) introduce la
possibilità di definire processi di gestione do-
cumentale, ma non solo: grazie all’estendibili-
tà del WWF è possibile introdurre propri com-
ponenti nel workflow e personalizzare alcune
parti di tutto il processo. Anche qui, per il pro-
grammatore diventa banale creare l’infrastrut-
tura di workflow (quella c’è già) e ci si può con-
centrare sugli aspetti prettamente funzionali
delle attività da svolgere. Chi ha sudato anni
di lavoro su questi temi sa quanto possa esse-
re decisiva una funzionalità del genere in am-
bito aziendale: con Office 12 e Windows Vista
sarà addirittura pervasiva. SharePoint v3 è il
collante tra WWF, Office 12 e componenti Offi-
SPECIALE
11N. 65 - Settembre/Ottobre 2005 VBJ
ce lato server e vi dedichiamo un’intera sezio-
ne dell’articolo, poco più avanti. Excel 12 è il
nuovo client di riferimento per accedere ai dati
aziendali. Supporta dati relazionali e multidi-
mensionali, offre finalmente tutte le funziona-
lità di Analysis Services 2005 e Analysis Servi-
ces 2000 (Excel 2003 non consente di sfruttare
appieno le capacità di Analysis Services 2000).
Ma non basta, Excel 12 integra anche funziona-
lità avanzate di visualizzazione dei dati (oltre
a tabelle pivot e grafici, per capirci) che deri-
vano dall’esperienza di Microsoft Data Analy-
zer (il team di sviluppo di quel prodotto è sta-
to inglobato in quello di Excel già dal lontano
2001). Purtroppo su questa parte c’è ancora un
po’ di riservatezza e queste funzioni non sono
ancora state mostrate al pubblico, ma non do-
vrebbe mancare molto per qualche anteprima.
Note per chi sviluppa soluzioni con/per Office:
Office 12 sarà anche l’occasione per una nuo-
va versione, la 3.0, di Visual Studio Tools for
Office; inoltre vedremo l’erede di VBA (Visual
Basic for Applications) che si chiamerà VSTA
(Visual Studio Tools for Applications), che con-
sentirà di scrivere le macro di Office in codice
.NET. Office 12 al momento è ancora sotto stret-
tissimi NDA (Non Disclosure Agreement) e la
beta non è ancora aperta al pubblico. La Beta
1 sarà disponibile entro fine anno (si ipotizza
per i primi di dicembre) e il prodotto dovreb-
be essere rilasciato nel secondo semestre 2006.
Il commento pressoché unanime che abbiamo
raccolto in chi ha visto Office 12 all’operà si può
riassumere più o meno così: si venderà da solo.
Vedremo se si tratta di analisi accurate o è solo
il frutto dell’entusiasmo per la novità.
Windows Sharepoint Services 3.0Windows Sharepoint Services 3.0 ha destato
notevole interesse. Volendo riassumere in uno
slogan le novità di WSS 3.0 si potrebbe dire:
avrà tutto quello che oggi manca a WSS 2.0!
Volendo entrare nel dettaglio, le document li-
brary, cioè le cartelle destinate a contenere i
documenti, saranno molto più configurabili di
quanto lo siano nella versione 2.0. Per esempio
avremo la possibilità di definire permessi sui
singoli file e non solo sulle cartelle, come ac-
cade oggi. Avremo il “cestino” per recuperare i
documenti eventualmente cancellati per errore.
Potremo definire gestori di eventi multipli sul-
le liste, anziché doverci adattare ad averne al
massimo uno solo. I gestori di eventi saranno
configurabili anche sulle liste non documenta-
li. Per esempio potremo configurare un nostro
handler personalizzato che ci invii una email
ogni qual volta venga creato un contatto nella
rubrica condivisa aziendale. Proprio nell’ottica
della gestione dei dati aziendali e della creazio-
ne di un portale aziendale basato su Sharepoint,
sarà possibile collegare gli item di una lista, per
esempio la lista di contatti, con i dati presen-
ti in database esterni, come potrebbe essere il
database del sistema ERP aziendale.
Immaginate la comodità di vedere dal por-
tale l’elenco dei clienti, con i loro recapiti, ma
anche con le loro posizioni aperte (saldo dare/
avere) direttamente lette dall’ERP e aggiorna-
te in tempo reale, potendo passare con un cli-
ck alla lista di documenti (fatture, bolle, email,
fax) relative al cliente. Se poi vorremo gestire
procedure aziendali, per esempio legate all’in-
serimento di un ordine o al caricamento di un
documento da approvare, potremo attivare uno
dei workflow predefiniti e “classici” già presenti
in WSS 3.0, oppure creare i nostri con WWF, per
poi collegarli a Sharepoint. Per i programmatori
che hanno l’esigenza di estendere il motore di
WSS, un’altra novità interessante è la possibi-
lità di creare tipi di campi personalizzati, senza
più essere vincolati al solo set di dati predefini-
to. Se dovessimo trovare a oggi una carenza o
un punto debole in WSS 3.0, potremmo indica-
re l’assenza di supporto nativo per device mo-
bili. Tutto il resto di necessario, rispetto anche
alla nostra esperienza diretta con il prodotto in
versione attuale, è ormai presente nella prossi-
ma release. Il giorno in cui Microsoft dovesse
rendere accessibile WSS 3.0 a client Windows
Mobile (che ormai montano “di serie” il .NET
Compact Framework), quello sarebbe il giorno
della svolta, in cui tutte le aziende con gestio-
ne informatica delle procedure passerebbero a
Sharepoint!
Non ultimo troveremo una rinnovata interfac-
cia utente, in linea con l’evoluzione che anche
SPECIALE
12 VBJ N. 65 - Settembre/Ottobre 2005
Office 12 subirà. Il rilascio di WSS 3.0 è previsto
in concomitanza con quello di Office 12, indi-
cativamente dopo la prossima estate 2006.
C# 3.0Per gli sviluppatori .NET appassionati del
Framework e di C#, le sessioni sul futuro
C# 3.0 e sulla tecnologia Language Integra-
ted Query (Linq) sono state un cibo impagabi-
le per la mente. Quando parliamo di prossima
versione del linguaggio C# non ci riferiamo
a quella che uscirà sul mercato a novembre,
con il lancio di .NET 2.0 e Visual Studio 2005,
bensì a quella ancora successiva, indicativa-
mente prevista per il 2007/2008. La prossima
versione del linguaggio C# sarà arricchita da
una serie di funzionalità accessorie, pensate
per semplificare e rendere più rapida la scrit-
tura del codice, così come per supportare Linq,
di cui parleremo nella prossima sezione. Par-
tiamo dalle modifiche al linguaggio: sarà pos-
sibile estendere “virtualmente” tipi già defi-
niti, come se venissero definiti nuovi meto-
di di istanza di classi già dichiarate. Questo
comportamento “apparente” si otterrà tramite
metodi statici di altre classi (sempre statiche)
che estendono il tipo definito al primo para-
metro, decorato con il modificatore this.
C# 3.0
public static class MyExtension
{
public static String DoSomething(this Int32 param1,
String param2) {...};
}
public class OtherClass
{
public String Name;
}
OtherClass oc = new OtherClass();
String result = oc.DoSomething(10, oc.Name);
In questo breve esempio è definita una classe
statica di nome MyExtension, con un metodo
altrettanto statico e il primo parametro esteso
con l’informazione “this”. Nel codice poi viene
utilizzata un’istanza di una classe OtherClass
che non presenta il metodo DoSomething nel-
la sua definizione, ma sulla quale abbiamo co-
munque l’illusione di poterlo invocare, proprio
grazie agli Extension Methods, che rendono il
metodo DoSomething di MyExtension disponi-
bile su tutti gli altri tipi, purché venga importa-
to, tramite la parola chiave using, il namespace
che contiene MyExtension.
Un’altra comoda aggiunta al linguaggio sono
i “Type Initializers” e i “Collection Initializers”,
che consentono di inizializzare un oggetto sen-
za passare attraverso la valorizzazione manuale
di tutte le sue proprietà, ma nemmeno doven-
do definire una serie di costruttori ad hoc per
le varie configurazioni da inizializzare. Pensia-
mo al caso seguente:
C# 2.0
public class Cliente
{
public String Nome;
public String Cognome;
}
// ...
Cliente c = new Cliente();
c.Nome = “Mario”;
c.Cognome = “Rossi”;
Se volessimo inizializzare in modo più rapi-
do le istanze di Cliente dovremmo creare co-
struttori appositi e fornire i valori di Nome e
Cognome. Con C# 3.0 e i Type Initializers si
potrà scrivere:
C# 3.0
Cliente c = new Cliente {Nome = “Mario”, Cognome = “Rossi”};
senza avere bisogno di un costruttore dedi-
cato. Nel caso delle collezioni l’idea è la stes-
sa, ma si inizializzano elenchi di istanze:
C# 3.0
List<Cliente> clienti = new List<Cliente> {new Cliente
{Nome = “Mario”, Cognome = “Rossi”}, new Cliente {Nome =
“Luca”, Cognome = “Bianchi”}};
SPECIALE
13N. 65 - Settembre/Ottobre 2005 VBJ
Esistono poi gli “Anonymous Types”. Si trat-
ta di tipi creati automaticamente dal compi-
latore, generalmente utilizzati per il passag-
gio di dati o la creazione di sottoinsiemi di
tipi esistenti. Ripensiamo ancora alla classe
Cliente, però così definita:
C# 3.0
public class Cliente
{
public String Nome;
public String Cognome;
public String Telefono;
public List<Indirizzo> Indirizzi;
}
public class ClienteSemplice
{
public String Nome;
public String Cognome;
}
Ci sono situazioni in cui si vogliono utilizzare
solo Nome e Cognome di un oggetto Cliente,
appoggiandosi magari a un tipo intermedio, più
snello, come è il ClienteSemplice. Con la se-
guente sintassi, che utilizza i Type Initializers,
possiamo creare l’oggetto “più piccolo”:
C# 3.0
Cliente c = new Cliente {Nome = “Mario”, Cognome =
“Rossi”, Telefono = “030-123456”};
ClienteSemplice cs = new ClienteSemplice {Nome = c.Nome,
Cognome = c.Cognome};
Guardando questo codice ci rendiamo conto
che una serie di informazioni possono essere
date per scontate, ricavandole dal contesto. Il
fatto che il risultato di una nuova istanza della
classe ClienteSemplice sia memorizzato in un
oggetto di tipo ClienteSemplice è prassi comu-
ne. In C# 3.0 hanno coniato la parola chiave
var (da non confondersi né con il Variant di VB
e COM, né con var di Java o Javascript!) che
permette di lasciare al compilatore l’onere di
ricavare, in modo implicito, il tipo che risulta
dalla new. Si può inoltre omettere il nome delle
proprietà Nome e Cognome nell’inizializzazio-
ne di ClienteSemplice, in quanto viene dedot-
to dai nomi delle proprietà di c (tipo Cliente)
passate come parametri. Arriviamo dunque a
questa versione intermedia di codice:
C# 3.0
Cliente c = new Cliente {Nome = “Mario”, Cognome =
“Rossi”, Telefono = “030-123456”};
var cs = new ClienteSemplice {c.Nome, c.Cognome};
E se dessimo per scontato anche il tipo Clien-
teSemplice? In C# 3.0 possiamo definire im-
plicitamente un tipo deducendone la dichia-
razione dai parametri passati nel Type Initiali-
zer; quindi, per creare un tipo che sia sottoin-
sieme di Cliente, possiamo scrivere:
C# 3.0
Cliente c = new Cliente {Nome = “Mario”, Cognome =
“Rossi”, Telefono = “030-123456”};
var cs = new {c.Nome, c.Cognome};
Il compilatore C# 3.0 creerà per noi, in fase
di compilazione, un tipo .NET con la struttura
da noi desiderata e lo farà diventare il tipo del-
la variabile cs: nei fatti, var viene sostituito con
il nome del tipo (il compilatore ne genera uno
automaticamente). L’aspetto interessante è che
anche se apparentemente si sta utilizzando un
linguaggio “dinamico”, dove non sembra esserci
un continuo controllo sui tipi a livello dichiara-
tivo, il compilatore lavora sempre in modo for-
temente tipizzato, liberando il programmatore
dalla necessità di inventare tipi “di servizio” per
operazioni di manipolazione dei dati. Sempre a
livello sintattico sono state aggiunte le “Lamb-
da Expression”. Prese dal mondo accademico
e della ricerca, le Lambda Expression servo-
no principalmente per passare porzioni di co-
dice come parametro ad altre procedure. Par-
tiamo da un esempio più completo:
C# 3.0
string[] nomiDevLeap = { “Luca”, “Silvano”, “Marco”,
“Paolo”, “Roberto” };
var nomiLunghi = from n in nomiDevLeap
where n.Length > 5
orderby n
SPECIALE
14 VBJ N. 65 - Settembre/Ottobre 2005
select n.ToUpper()
foreach ( string s in nomiLunghi ) {
Console.WriteLine( s );
}
In pratica questo codice è esattamente iden-
tico al seguente:
C# 3.0
string[] nomiDevLeap = { “Luca”, “Silvano”, “Marco”,
“Paolo”, “Roberto” };
IEnumerable<string> nomiLunghi = nomiDevLeap
.Where( n => n.Length > 5 )
.OrderBy( n => n )
.Select( n => n.ToUpper() );
foreach ( string s in nomiLunghi ) {
Console.WriteLine( s );
}
In questo codice i metodi Where, OrderBy e
Select sono Extension Methods che lavorano
sull’array di stringhe nomiDevLeap e che ese-
guono al loro interno, tramite delegate, il co-
dice che segue il simbolo =>, cioè la Lamb-
da Expression. Tutte queste novità sintattiche
sono dovute sia alla volontà di semplificare la
scrittura del codice, sia per supportare Linq.
Come si può intuire dal codice, Linq fa anche
un grande uso dei generics sfruttando però le
Lambda Expression anziché i metodi anonimi
(come avviene spesso nelle librerie di .NET 2.0,
si pensi alla List<T>.FindAll) per sintetizzare
ancora di più il codice.
LINQIl .NET Language Integrated Query è un
progetto innovativo, che prevede l’estensio-
ne del linguaggio C# (ma anche di VB e al-
tri linguaggi .NET che lo vogliano supporta-
re) per potere scrivere all’interno del codice
query rivolte a una struttura dati generica con
una sintassi che sia ancora codice .NET, ma
simile al codice SQL che scriviamo oggi per
i database relazionali, il tutto senza modifica-
re il motore del CLR. La base dati può essere
in memoria, su un file XML o su un database
SQL Server, ma è possibile creare estensio-
ni al motore Linq, per supportare altri tipi di
persistenza. Linq permette di vedere i dati a
livello di codice come insieme di oggetti con
proprietà, anziché come tabelle con campi,
però mantenendo un legame con il substra-
to, in modo tale da poter replicare sul data-
base le modifiche apportate al modello ad og-
getti. Un aspetto interessante è la possibilità
di differire la risoluzione delle espressioni di
query. Ciò avviene con varie tecniche, anche
in funzione del punto in cui risiedono i dati.
Nel caso si voglia interrogare un db relazio-
nale, è possibile convertire la sintassi Linq
in unità minime, dette Expression, organiz-
zate in Expression Tree. In pratica le Lamb-
da Expression, anziché essere eseguite diret-
tamente, sono convertite in un “piano di ese-
cuzione” definito da questi Expression Tree,
che a loro volta sono poi convertiti in relative
sintassi SQL nel momento in cui sia neces-
sario accedere al database esterno. Il vantag-
gio di questo approccio è che si può interro-
gare un database o uno storage in generale,
appoggiandosi a modelli a oggetti fortemen-
te tipizzati, ma anche facilmente collegati alla
base dati reale. Avere un modello ad oggetti
fortemente tipizzato per gestire una base dati
vuol dire evitare potenziali problemi e avere
regole di validazione sui dati molto più rigi-
de. In pratica uno dei possibili utilizzi di Linq
è quello di creare un O/R mapper, cioè uno
strato che astrae un modello relazionale in
un modello a oggetti. In realtà questo è solo
uno degli usi possibili, precisamente DLinq,
ma Linq consente di ottenere anche altri ri-
sultati, come poter manipolare una struttura
dati XML attraverso comandi simili a SQL
(XLinq). Le attuali implementazioni di Linq
sono DLinq per accedere a basi dati relazio-
nali (al momento solo SQL Server o Access)
e XLinq per accedere a fonti dati XML. Bi-
sogna però ricordare che si tratta solo di una
Technical Preview, è evidente la possibile (e in
parte già realizzata) integrazione con WinFS e
soprattutto è importante notare come l’archi-
tettura sia completamente aperta e consenta
l’introduzione “indolore” di nuove estensioni
SPECIALE
15N. 65 - Settembre/Ottobre 2005 VBJ
(dal supporto di altri database per DLinq al-l’implementazione di astrazioni diverse o al-ternative allo stesso DLinq).
DLinq, come ogni O/R mapper, nasce per ren-dere più “semplice” l’accesso a strutture dati memorizzate in database relazionali da parte di un linguaggo a oggetti. Qual è il problema oggi nell’accesso ai database? Non ci sono pro-blemi operativi o limitazioni, ma bisogna con-siderare che verso il database si passano strin-ghe (anche quando usiamo stored procedure) e vengono restituite “cose” tabellari; nel 99% dei progetti che seguiamo questi dati tabella-ri vengono poi convertiti dal codice del Data Access Layer in oggetti e collezioni di ogget-ti. L’obiettivo di DLinq è semplificare questa fase sia nell’estrazione dei dati, che nell’ag-giornamento degli stessi e nello stesso tem-po semplificare l’intercettazione degli errori più comuni di “digitazione”: oggi non esistono compilatori in grado di indicare se è sbagliato il nome della stored procedure o di un para-metro oppure di un campo da estrarre.
Vediamo un esempio partendo dal classico codice C# 2.0 (in questo esempio semplifica-to e senza gestione eccezioni)
DAL e C# 2.0
SqlConnection conn = new SqlConnection();
SqlCommand cmd = new SqlCommand(conn);
cmd.CommandText = ”spListClienti”;
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter par = new SqlParameter();
par.ParameterName = “@IdProvincia”;
par.SqlDbType = SqlDbType.NVarChar;
par.Size = 2;
par.Value = “FI”;
cmd.Parameters.Add(parId);
List<Cliente> listaClienti = new List<Cliente>;
conn.open();
using (SqlDataReader dr = cmd.ExecuteReader(Command
Behavior.CloseConnection))
{
int nomeOrdinal = dr.GetOrdinal(“Nome”);
int cognomeOrdinal = dr.GetOrdinal(“Cognome”);
while (dr.Read())
{
Client cli = new Cliente();
cli.Nome = dr.GetString(nomeOrdinal);
cli.Cognome = dr.GetString(cognomeOrdinal);
listaClienti.Add(cli);
}
}
Utilizzando DLinq il codice diventa qualco-sa di simile a questo
DLinq
Table<Customers> clienti = db.Customers;
Var contatti = from c in clienti where c.Provincia == “FI”
select new {c.Nome, c.Cognome}
Oltre alla semplicità del codice, è bene notare come un compilatore possa essere d’aiuto su oggetti tipizzati, intercettando errori sui nomi dei campi, sulla loro tipologia e così via.
Per descrivere il mapping fra proprietà del-le classi e entità presenti nel database vengo-no utilizzati attributi sulla classe e sulle pro-prietà esposte e non file XML come avveniva nel “compianto” progetto ObjectSpaces di cui DLinq riprende le idee di base.
L’uso degli attributi (generabili automatica-mente con un apposito tool che analizza la struttura di un database) è stato oggetto di contestazioni da parte di molti sviluppatori, ma la filosofia attuale è di mantenere DLinq il più semplice possibile; comunque l’ultima parola su questi aspetti implementativi non è ancora stata scritta, anzi. Oggi Linq è un “fe-nomeno” appena nato e in crescita, da tene-re sotto controllo. Potrebbe segnare la svol-ta nell’uso dei linguaggi e nella definizione delle architetture (che fine fa il DAL?) così come potrebbe essere abbandonato o modi-ficato pesantemente come sintassi. Dipende molto anche dai feedback che tutti noi dare-mo a Microsoft.
È bene tenere presente che se le performan-ce sono l’elemento critico di un progetto, l’ap-proccio tradizionale, soprattutto per quanto riguarda l’accesso a basi dati SQL Server, re-sterà la strada migliore.
SPECIALE
16 VBJ N. 65 - Settembre/Ottobre 2005
Sicuramente è prematuro usarlo in un qual-
siasi scenario che non sia solo sperimentale;
dare però un’occhiata e mandare dei feedback
a Redmond è il modo migliore per ottenere
fra due o tre anni un prodotto più vicino alle
reali esigenze.
Windows Longhorn Servere Windows Vista
La nuova versione di Windows (Windows
Vista e Longhorn Server) porta molte novità
dal punto di vista dei servizi, dell’interfaccia
utente e delle numerose nuove funzionalità,
tanto che saranno scritti molti libri per trat-
tarle. In questo articolo ci vogliamo occupare
degli aspetti che hanno un impatto sugli svi-
luppatori, ma che magari sono anche meno
note perché meno “coreografiche”.
Ci sono molti cambiamenti nel kernel e ai
servizi di base di Windows. Da questo punto
di vista ci saranno alcune delle più rilevan-
ti novità da quando è nato Windows NT. L’in-
tento è quello di aumentare la sicurezza, la
robustezza e le prestazioni percepite (tempi
di risposta alle azioni dell’utente) del sistema
operativo. La caratteristica secondo noi più
interessante è quella dello scheduled I/O, im-
portante anche per tutti coloro che scrivono
software che deve avere prestazioni soft real-
time, per esempio chi gestisce un protocollo
di comunicazione su seriale che richiede un
controllo sui tempi di latenza. Vediamo pun-
to per punto le novità più significative. User
Mode Driver Framework: alcuni driver si pos-
sono eseguire in modalità User, pur avendo lo
stesso modello di sviluppo; questo garantisce
che un driver così caricato non possa danneg-
giare l’intero sistema. Molti driver non richie-
dono di andare realmente in modalità Kernel
(è indispensabile solo per agganciare inter-
rupt e accedere direttamente all’I/O). Ciò au-
menta la robustezza del sistema operativo. Ri-
spondendo a una domanda è stato detto che i
driver video in Windows Vista girano in mo-
dalità utente; evidentemente una parte della
comunicazione con la scheda video è gestita
da driver a più basso livello che girano in mo-
dalità kernel e che probabilmente sono inclu-
si nel sistema operativo. Questa mossa toglie
di mezzo una percentuale enorme dei moti-
vi per cui a volte si vedono “schermi blu” (la
stragrande maggioranza sono infatti dovuti ai
driver delle schede video). Scheduler: è sta-
ta introdotta una modalità chiamata “Multi-
media Class Scheduler Service” che dovreb-
be mantenere costanti i tempi di risposta nei
processi che gestiscono elementi multimedia-
li. Scheduled File I/O: si tratta di un sistema
per dare priorità alle richieste di I/O. Questo
tipo di funzionalità era atteso da tanti anni,
adesso bisogna capire meglio come è imple-
mentato. Se funziona come deve, il risulta-
to netto è una percezione per l’utente di mi-
gliore e più rapida risposta alle proprie azio-
ni, perché attività di I/O secondarie vengono
accodate, al contrario di quanto avviene oggi
dove le richieste di I/O finiscono nella stessa
coda, indipendentemente dal fatto che proven-
gano da un processo più o meno prioritario.
Protezione da malware/rootkit: ci sono tecni-
che per controllare il codice che gira in mo-
dalità kernel e per i processi critici che girano
in modalità utente, tra l’altro usando un con-
trollo per verificare che il codice sia firmato
digitalmente. Bisognerà vedere quanto que-
sto sia realmente a prova di rootkit, ma per
lo meno si dovrebbe ridurre un po’ (anche se
non del tutto) la superficie di attacco. Servi-
zi Windows: tante, tante novità.
Le più visibili sono il delayed auto-start (il
servizio parte con un processo a priorità più
bassa di CPU e di I/O, così da non rallentare
un’eventuale operatività dell’utente) e il re-
covery automatico anche in casi diversi dal
crash (per esempio memory leak e resource
leak). Le altre novità interessano la security,
con l’isolamento della sessione in cui girano
i servizi dalle sessioni interattive e l’harde-
ning dei token e dei privilegi (questo punto
meriterebbe un intero articolo).
Registry: oltre alla funzionalità transaziona-
le (disponibile anche per il file system NTFS)
c’è la virtualizzazione, che consente di ese-
guire con utenti non-admin anche quelle ap-
plicazioni che cercano di scrivere sul Regi-
stry dove non dovrebbero: tali modifiche al
SPECIALE
17N. 65 - Settembre/Ottobre 2005 VBJ
Registry sono visibili solo all’applicazione e all’utente che le ha fatte, è come se ci fosse un registro virtuale per ogni applicazione e ogni utente. Sembra una questione banale, ma ci sono un’enormità di effetti collaterali e di situazioni particolari da considerare (per esempio, un antivirus deve intercettare tutte le chiamate come se fossero reali) che richie-dono un lavoro piuttosto complesso dal pun-to di vista implementativo.
Questo ha un impatto diretto sui program-mi che devono filtrare le chiamate al registry (gli antivirus, appunto) che dovranno adattar-si a una nuova architettura per funzionare al meglio. WoW64: Windows on Windows 64 bit consente di eseguire processi a 32 bit. Non è una vera novità perché è presente anche sulle versioni a 64bit di Windows 2003 e Windows XP già esistenti.
I driver a 32 bit non sono supportati, un’ap-plicazione a 32 bit viene caricata in un “am-biente virtuale” a 32 bit dove non si possono richiamare altre DLL a 64 bit. Lo spazio di in-dirizzamento è 2Gb o 4Gb (per le applicazioni che supportano i 3Gb, è un attributo del Por-table Executable). C’è un impatto sul Registry, nel senso che le applicazioni a 32 bit vedono una vista del Registry che consente di isola-re le applicazioni a 32 bit da quelle a 64 bit. L’interoperabilità tra 32 e 64 bit può avvenire tramite COM, ma solo con componenti out-of-process e non con componenti in-process.
WinFSLa sessione su WinFS è stata replicata per con-
sentirne la visione a tutti coloro che erano ri-masti fuori dalla sala strapiena; ciò testimonia l’interesse verso questa tecnologia annunciata a PDC 2003, disponibile nella prima “Alpha” di Longhorn (adesso Windows Vista) e poi separa-ta da quest’ultimo nell’agosto 2004.
Dall’agosto 2005 è disponibile una prima Beta di WinFS (installabile su XP SP2), non sarà in-cluso nella prima release di Windows Vista, ma sarà reso disponibile come componente aggiun-tivo. Rispetto ai file system tradizionali consen-te di categorizzare le informazioni memorizzate tramite attributi definiti in uno schema. L’idea
è spostare nella piattaforma la conoscenza dei vari attributi “dei file”, che oggi è demandata alle singole applicazioni. È possibile mettere in relazione un dato o un file con un altro. WinFS fornisce il supporto per la memorizzazione del-le informazioni comuni a più applicazioni come Contatti, Aziende, Persone: questo consente alle applicazioni e agli utenti di eseguire ricerche mirate sugli item memorizzati, di evitare di me-morizzare gli stessi dati in location diverse e di utilizzare attributi diversi per la stessa tipolo-gia di informazione. L’organizzazione delle in-formazioni si basa su schemi.
Ogni schema descrive entità come eventi, per-sone, documenti, immagini e messaggi, defi-nendo gli attributi di ognuna di esse.
Per esempio una Persona può avere più in-dirizzi di posta elettronica, mentre un’Azienda può contenere diverse entità di tipo persona. Questi schemi sono estendibili: è possibile de-finirne di propri per le proprie informazioni. WinFS consente un’organizzazione gerarchica delle informazioni e una organizzazione rela-zionale: per questo spesso si legge “Relational File System”.
Vista la sua struttura è possibile ricercare dati utilizzando query relazionali tramite il modello a oggetti esposto direttamente, ma anche uti-lizzando ADO.NET e SQL. Se uno più uno fa sempre due, avrete già capito che si potrà in-terrogare WinFS anche tramite LINQ. Ecco un esempio semplice:
Linq e WinFS
Table<Customers> clienti = db.Customers
using System.Storage;
using System.Data.Objects;
using Druker.Sales;
SalesData sd = new SalesData(salesConfig);
foreach (Customer customer in sd.Customers where
LastName=’Brunetti’) Console.WriteLine(customer.FirstName);
// Aggiunta di un cliente
Customer cliente = new Customer(id, Nome, Cognome);
sd.Customers.Add(cliente);
sd.SaveChanges();
SPECIALE
18 VBJ N. 65 - Settembre/Ottobre 2005
Lo store WinFS è transazionale, consentendo l’esecuzione di operazioni utilizzando i classi-ci metodi BeginTransaction, CommitTransac-tion e AbortTransaction.
ATLASATLAS è un’estensione del motore di
ASP.NET per supportare il tanto discusso AJAX (Asyncronous Javascript And XML). Utilizzan-do oggetti server, simili ai Web Control, è in grado di produrre interfacce web che eseguo-no richieste a servizi esposti, senza eseguire i classici POST http. In pratica questi controlli inviano al client la “Client Script Library”, ba-sata appunto su Javascript, che fornisce una serie di servizi per invocare tramite XMLHt-tp la parte server.
Le richieste di informazioni passano da un Service Bridge (che insieme alla script library è incluso nel file AtlasCore.js) lato client, che a sua volta invoca i servizi server side. I servi-zi server-side possono essere i classici ASMX oppure servizi WCF (Indigo).
Grazie all’integrazione con ASP.NET 2.0, pro-xy e librerie lato client vengono generati in au-tomatico e sfruttano nativamente i moduli di autenticazione, autorizzazione e caching clas-sici di ASP.NET 2.0. I Web Service in un’appli-cazione ATLAS producono il codice javascript lato client in base ai metodi esposti dal web service stesso.
Allo sviluppatore dell’interfaccia utente non resta che scrivere le righe di codice Javascript che invocano i metodi esposti per far scatena-re la richiesta in background e utilizzare i dati per modificare l’interfaccia utente; molti con-trolli presenti in ATLAS (si utilizzano come i normali controlli asp: <atlas:TextBox>) ese-guono già queste operazioni in automatico. Sono presenti anche numerosi controlli che effettuano binding su tabelle HTML eseguen-do dietro le quinte le operazioni più comuni di inserimento, modifica e cancellazione. Anche i Validation Control possono sfruttare questa tecnologia per eseguire validazioni sui dati nel database senza eseguire POST. È disponibile uno starter kit [4] e nel 2006 dovremmo avere presto una prima beta “GoLive”.
Expression Interactive DesignerDurante la plenaria e con un paio di sessioni de-
dicate sono stati presentati i nuovi prodotti del-la famiglia Expression Web Developer. L’obietti-vo è fare un salto in avanti nella presentazione dei dati all’utente: il tema ricorrente degli ultimi anni (ma lo sarà anche per i prossimi) è “Enrich User Experience”. La famiglia dei prodotti com-prende Quartz Web Designer, Acrylic e Sparkle. Quartz Web Designer è il nuovo strumento per disegnare interfacce utente web che dovrebbe finalmente rendere più semplice la difficile in-terazione fra sviluppatori web, grafici, sviluppa-tori server-side e IT manager. Come prima cosa Quartz genera codice molto pulito e aderente a XTHML 1.0 sia Transitional che Strict, può uti-lizzare le diverse tecniche di posizionamento dei tag (dalle classiche tabelle a CSS-P) per lavora-re con vari browser. Con diversi “simulatori di browser” è in grado di effettuare una preview del risultato molto più aderente alla realtà: è possibile anche effettuare prove di binding con dati reali presenti in una sorgente dati qualun-que per testare il risultato senza dover portare le pagine su un server web. Code snippet e In-tellisense aiutano nella scrittura del codice di markup e di binding. Acrylic è invece uno stru-mento grafico per creare immagini e animazioni vettoriali o classiche; l’alternativa a PhotoShop per capirci. Acrylic è il secondo nato della fami-glia, e anche l’unico attualmente in Beta e sca-ricabile gratuitamente da www.microsoft.com/expression. Si tratta di un tool espressamente dedicato ai grafici. Affronta in modo “ibrido” la definizione di layer, ibrido perché permette di lavorare sia con vector-layer che con pixel-layer per consentire in qualsiasi momento di trasfor-mare un layer da un tipo all’altro. Tra le featu-re di rilievo segnaliamo elevate performance nel pixel painting, modifica delle dimensioni (size e dpi) di un documento, brushes, strokes gra-dient, pattern classici da strumento per dise-gnatori e la capacità di modificare il canale al-pha di un layer nella clipboard, utile per creare sfondi semitrasparenti da incollare in presenta-zioni Powerpoint o altri documenti.
La caratteristica di maggior interesse per gli sviluppatori è senz’altro la funzione di esporta-
SPECIALE
19N. 65 - Settembre/Ottobre 2005 VBJ
zione del layout finale in linguaggio XAML, so-lida base della piattaforma Windows Presenta-tion Foundation. Sarà così possibile integrare i grafici nel totale processo produttivo di un’appli-cazione Windows e non solo, come adesso, nella prima fase creativa del progetto. Sparkle, rea-lizzato completamente con Windows Presenta-tion Foundation, è il tool fondamentale per de-finire in modo visuale le interfacce utente del-la prossima generazione.
Le caratteristiche più interessanti sono l’im-portazione e la combinazione di elementi vet-toriali e bitmap, pieno supporto ai modelli 3D (geometry, materials, texture, camera, trasfor-mazioni XYZ ecc) realizzabili da zero o impor-tabili da famosi tool di terze parti.
Sarà facile definire animazioni 2D o 3D, grazie a comode form per realizzare timeline in modo intuitivo e alle funzioni rec-move-play dello stru-mento. Piena integrazione con le funzionalità le-gate a video, è infatti possibile “applicare” un vi-deo, come se fosse una texture 2D, a qualunque oggetto. Le avanzate caratteristiche tipografiche di Windows Presentation Foundation sono pie-namente supportate dal tool. Sparkle è un’appli-cazione dedicata ai designer professionisti, ma semplifica anche la vita agli sviluppatori .NET con comode toolbox per inserire controlli “tra-dizionali” (Canvas, DatePicker, Button, Textbox ecc.), creare controlli compositi unendo diversi oggetti semplici, applicare “trigger” per modi-ficare l’aspetto dei controlli in modo condizio-nale o definire sintassi di binding a design time con tanto di preview.
Il tool permette di definire sia l’aspetto del-l’applicazione sia il suo comportamento, con-sentendo l’editing dei file di code-behind C# o VB.NET; tali file ovviamente possono essere condivisi con Visual Studio 2005 per la gestione completa di un’applicazione enterprise. Signifi-cative le funzionalità legate al deployment per distribuire sia applicazioni stand-alone che ex-press application, ovvero applicazioni “ospitate” da Internet Explorer. Nascerà quindi un nuova categoria professionale di sviluppatori dell’in-terfaccia utente.
Chi saranno i pionieri di questa nuova occupa-zione: grafici evoluti o sviluppatori stanchi del
solito codice? Su Internet [5] si può avere una preview online delle funzionalità di questa fa-miglia di prodotti.
System.Transaction 2.0La versione 2.0 di .NET ha fatto un passo avan-
ti nella gestione delle transazioni: non occorro-no più componenti basati su Enterprise Servi-ces (e quindi COM+) e si è semplificata (e al-leggerita dal punto di vista dell’esecuzione) la gestione da codice. Quindi? Dalla Beta2 di Win-dows Vista e ovviamente in Longhorn Server sia il file system NTFS che il Registry saran-no transazionali!
Questo rende più semplice la scrittura di ap-plicazioni che gestiscono immagini: viene in mente un sito web con immagini memorizza-te sul file system e dati associati memorizzati in un database.
È possibile abbracciare sotto un’unica transa-zione la scrittura dell’immagine e dei dati nel DB. Le transazioni possono abbracciare SQL 2005 nativamente, MSMQ e SQL 2000 trami-te l’utilizzo trasperente del buon vecchio Mi-crosoft DTC.
ConclusioniÈ stata una PDC interessante e densa di no-
vità e informazioni utili. Ora ci aspettano cir-ca 2 anni di consolidamento delle conoscenze attuali, relativamente a .NET 1.x e .NET 2.0 durante i quali vedranno la luce WinFX, Win-dows Vista, Longhorn Server, Sharepoint 3.0, C# 3.0 e forse Linq.
In un certo senso possiamo affermare di aver dato uno sguardo attraverso una finestra che ci ha permesso di sapere come saranno i pros-simi 2 o 3 anni.
Ne è valsa decisamente la pena per non far-si trovare impreparati!
Riferimenti[1] http://www.windowsworkflow.com/[2] http://msdn.microsoft.com/winfx/[3] http://www.microsoft.com/windows/[4] http://atlas.asp.net[5] http://www.microsoft.com/products/
expression/en/default.aspx
SPECIALE
20 VBJ N. 65 - Settembre/Ottobre 2005
Il supporto base che VB6 offre, soprattutto al
programmatore neofita, per riprodurre un file
multimediale è il controllo ActiveX MS Multi-
media Control. Tutti i programmatori VB si sono
imbattuti in questo controllo e ne hanno potuto
apprezzare la semplicità d’utilizzo. Tuttavia esso
non è sufficiente per ogni tipo di applicazione.
Si vuole allora esaminare la libreria “winmm”, che
può risultare utile nell’ambito di applicazioni dai
contenuti multimediali più sofisticati.
L’articolo è rivolto, soprattutto, ai neofiti dello
sviluppo software in VB6.
Eseguire file AVI con VB6In questo caso, l’applicativo di esempio riguar-
derà la realizzazione di un lettore di file .avi, che
consente di effettuare le seguenti operazioni:
• Esecuzione in Finestra
• Esecuzione FullScreen
• Stop/Pausa
L’applicativo sarà altresì com-
pletato da funzioni di apertu-
ra e chisura del file. La libreria
“winmm” consente di riprodur-
re e registrare file audio, midi,
e CD musicali. Il Form del Pro-
getto si presenta come in Figu-
ra 1. Per cominciare occorre di-
chiarare le variabili e le funzio-
ni che entrano in gioco nell’ap-
plicativo (Listato 1) dove:
• nome_file: è il nome del file
che dovrà essere aperto e ri-
prodotto;
• comando: è il tipo di coman-
do che si vuole eseguire sul
file .avi;
• valore_ritorno: è il valore
che la funzione “mciSend-
String()”, restituisce all’uten-
te a seconda dell’operazione
da effettuare.
Anzitutto è necessario caricare
un file .AVI. Il controllo Com-
mon Dialog permette l’impo-
stazione dei filtri della tipolo-
gia del file e la procedura di
apertura (Listato 2). Si noti
che nella procedura di apertu-
Controlli multimediali
in Visual Basic 6
di Fabio Fabozzi
MULTIMEDIA
Non capita spesso di realizzare software dai contenuti multime-
diali. Questo articolo illustra le modalità di gestione di elementi
multimediali in VB6: non sarà forse molto originale, ma di sicuro
se ne potrà apprezzare la valenza evocativa per coloro che già
sanno ed educativa per coloro che ancora non sanno.
Fabio Fabozzi è progettista/sviluppatore software presso la S4BT s.rl. di Latina, azienda che produce software in ambito farmaceutico. È autore del libro”Intelligenza Artificiale con Visual Basic”, edito dal Gruppo Infomedia e collabora con le riviste del gruppo come articolista. Tra i suoi principali interessi: scienze cognitive, software per la disabilità, in-telligenza artificiale, crittografia, studio dei sistemi caotici, applicazioni per calcolatori palmari. Studia Psicologia dei Processi Cognitivi presso la Facoltà di Psicologia1 dell’Uni-versità “La Sapienza” di Roma. Può essere contattato via e-mail all’indirizzo [email protected]
21N. 65 - Settembre/Ottobre 2005 VBJ
trà rendere conto di quan-
to poco tempo e con quan-
te poche righe di codice è
possibile scrivere un’appli-
cazione multimediale (Li-
stato 3). Prendiamo ora in
considerazione il comando
“Play video”. Tale coman-
do, oltre ad eseguire un
file video desiderato, lo
colloca in finestra “tiled”,
cioè adatta alle dimensio-
ni proprie di quel file AVI.
L’effetto, che molti di voi
avranno visto, è quello vi-
sibile in Figura 2.
Tuttavia, però, potrebbe
essere desiderabile aprire
un file AVI direttamente
all’interno di un control-
lo PictureBox e, quindi, adattare le dimen-
sioni del file alle dimensioni del controllo
stesso. Ciò consente di creare un applicativo/
visualizzatore, discreto e sofisticato. La pro-
cedura che andiamo ad esaminare consente
anche di poter creare un logo roteante per un
applicativo. Tale logo, appunto, potrebbe es-
sere proprio un file AVI, di modeste dimen-
sioni, che viene mandato in playback con ri-
petizione. Partiamo proprio da questo pun-
to, cioè, dalla ripetizione di un file AVI e dal-
la sua implementazione. Ripetere un file AVI
all’infinito è una cosa molto semplice, basta
aggiungere la parola “repeat” al comando e il
gioco è fatto:
comando = “Play video” + “ repeat”
ra del file, il nome va tratta-
to in questo modo:
nome_file = Chr$(34) + nome_file +
Chr$(34)
Se si omette Chr$(34) – ossia
gli apici – il file verrà aperto
ma non letto. Si noti la sintas-
si del comando “Open”:
comando = “open “ + nome_file + “
alias video”
Si può notare, nell’ultimo
spezzone della riga di coman-
do, la dicitura “ alias video”. In
questo caso, il sistema, darà ad
un file .AVI di un certo nome,
il nome generico di “video”, su
cui verranno svolte tutte le operazioni a segui-
re. Tale nome, è comunque definibile dall’uten-
te: se avessi messo “alias cipolla”, avrei mani-
polato un file video con l’alias di “cipolla”. Per
eseguire un comando, sia esso un’esecuzione
FullScreen, normale o lo stop, viene utilizza-
ta la seguente sintassi:
comando = “<denominazione del comando> video”
valore_ritorno = mciSendString(comando, vbNullString, 1024, 0)
Questa sintassi è la stessa che già abbiamo
visto per l’apertura del file e, come si può no-
tare, è molto simile per gli altri comandi che
vengono lanciati. Voglio riportare tutti i co-
mandi che fanno parte di questo applicativo
di esempio. In questo modo, il lettore si po-
MULTIMEDIA
Li sta to 1 Variabili dell’applicativo
Option Explicit
Private Declare Function mciSendString Lib “winmm.dll” Alias “mciSendStringA” (ByVal lpstrCommand As String,ByVal lpstr-ReturnString As String, ByVal uReturnLength As Long, ByVal hWndCallback As Long) As Long
Private nome_file As StringPrivate valore_ritorno As LongPrivate comando As String
Fi gu ra 1 Applicativo prjAVI
22 VBJ N. 65 - Settembre/Ottobre 2005
Ricordatevi di rispettare lo spazio che inter-corre tra l’apice e l’inizio della parola “repeat”. Ora, la cosa più impegnativa sarà scrivere del codice che vada ad adattare un filmato AVI al-l’interno di una PictureBox. Consiglio di dise-gnare il controllo PictureBox in un nuovo Form, perché la procedura di apertura del file è legger-mente diversa da quella usata fino ad ora. Pri-ma di tutto copiate nelle dichiarazioni del nuo-vo Form le variabili e le funzioni precedenti ed aggiungete queste nuove variabili:
Const WS_CHILD = &H40000000
Private Height As Long
Private Width As Long
A questo punto, è possibile defini-re la procedura di apertura del file, che sarà quella riportata nel Listato
4. Dopo la fase di apertura, si passa alla fase di ridimensionamento del filmato AVI e del “filling” del con-trollo PictureBox (Listato 5). Una volta completate queste due proce-
dure, si può riprodurre il file in questo modo:
comando=”Play AVIFile”
Riproducendo un file AVI in una Picture-Box e con ripetizione (si ricordi l’aggiunta del comando repeat), è possibile adornare l’applicazione di un eventuale cliente con un logo animato creato “ad hoc”. Con que-sto si conclude la panoramica sulla riprodu-zione dei file AVI.
Eseguire file WAV con VB6
Il controllo dei file WAV, nel contesto della creazione di ap-plicazioni, è molto più importante della ripro-duzione di file AVI. Il perché, della mia pre-cedente affermazione, è molto semplice. È co-mune pensare che ap-plicativi che presenti-no al loro interno ri-produzione di filma-ti o di suoni, possa-no essere in genera-le programmi ludici. Come abbiamo visto, per la riproduzione dei file AVI è possibi-le adornare l’applicati-vo creato per un clien-te. Per ciò che concer-
Fi gu ra 2 Riproduzione del file in “tiled window”
Li sta to 2 Procedura di apertura del file .AVI
Private Sub Command2_Click() cd.Filter = “(*.avi)|*.avi” cd.FilterIndex = 0 cd.FileName = “” cd.ShowOpen nome_file = cd.FileName nome_file = Chr$(34) + nome_file + Chr$(34) comando = “open “ + nome_file + “ alias video” valore_ritorno = mciSendString(comando, vbNullString, 1024, 0)End Sub
MULTIMEDIA
23N. 65 - Settembre/Ottobre 2005 VBJ
ne i suoni, la loro importanza è di
gran lunga maggiore. Si pensi, ad
esempio, a tutte quelle applicazio-
ni critiche, in cui chi utilizza un sof-
tware ha bisogno di segnali, di allar-
mi, di avvisi. In questi contesti, po-
ter riprodurre un suono è una com-
ponente essenziale. Al di là di tutte
queste implicazioni, passiamo alla
riproduzione e all’esecuzione, più in
generale, dei suoni o dei file WAV.
La finestra del progetto di esempio
per i file WAV, sarà molto simile a
quella dei file AVI. Nel progetto al-
legato, è possibile vedere – nella se-
zione delle dichiarazioni – che que-
ste corrispondono a quelle presenti
nel progetto di esempio per gli AVI.
Le funzioni che si andranno ad im-
plementare sono le seguenti:
• Apertura di un file WAV
• Esecuzione di un file WAV
• Riavvolgimento di un file WAV
• Stop/Pausa di un file WAV
• Chiusura di un file WAV
L’apertura del file WAV è del tutto simile
a quella di un file AVI, ma cambia qualcosa
nella stringa di comando:
comando = “open “ + nome_file + “ type waveaudio alias sound”
valore_ritorno = mciSendString(comando, vbNullString, 1024, 0)
Ciò significa che l’alias del file waveaudio su
cui verranno effettuate le operazioni avrà l’alias
“sound”. Le funzioni che manipolano i file WAV
non sono né complesse né, tantomeno, dissimi-
li da quelle già viste per i file AVI. Una pecu-
liarità può essere rappresentata dalla funzione
di “Riavvolgimento di un file WAV”:
comando = “seek sound to start”
valore_ritorno = mciSendString(comando, vbNullString, 1024, 0)
Ho chiamato questa funzione “riavvolgimen-
to”, che evoca la vecchia funzione presenti sui
riproduttori a cassetta di una volta. Infatti tale
funzione riporta il file all’inizio. L’elenco com-
pleto delle funzioni di base è visibile nel Lista-
to 6. Una funzione particolare può essere quella
di dare la possibilità all’utente di registrare un
file audio. Le modifiche da fare, a tale propo-
sito, sono poche. Basta aggiungere due Com-
mandButton sul form del progetto che porti-
no ad esempio queste due etichette:
• Registra WAV
• Salva file registrato
Li sta to 3 Funzioni di manipolazione di un file AVI
Private Sub Play() comando = “play video” valore_ritorno = mciSendString(comando, vbNullString, 1024, 0)End Sub
Private Sub Play_FullScr() comando = “play video fullscreen” valore_ritorno = mciSendString(comando, vbNullString, 1024, 0)End Sub
Private Sub Chiudi() comando = “close video” valore_ritorno = mciSendString(comando, vbNullString, 1024, 0)End Sub
Private Sub Stop() comando = “stop video” valore_ritorno = mciSendString(comando, vbNullString, 1024, 0)End Sub
Li sta to 4 Apertura file AVI per la PictureBox
Private Sub Apri_File_PB( ) comando = = “open “ + nome_file + “ type AVIVideo alias AVIFile parent “ + CStr(PictureBox.hWnd) + “ style “ +
Cstr(WS_cHILD) valore_ritorno = mciSendString(comando, vbNullString, 1024, 0)End Sub
MULTIMEDIA
24 VBJ N. 65 - Settembre/Ottobre 2005
Si evince che la registrazio-
ne è suddivisa almeno in due
fasi; in realtà il processo è leg-
germente più lungo ma non
complicato. Se è stato carica-
to precedentemente un suo-
no, lo si chiude e se ne crea
uno vuoto disponibile per la
registrazione:
comando = “close sound”
valore_ritorno = mciSendString(comando, vbNullString, 1024, 0)
comando=”open new type waveaudio alias suono”
valore_ritorno = mciSendString(comando, vbNullString, 1024, 0)
Il passo successivo consiste nella registra-
zione vera e propria del suono, che è molto
semplice:
comando = “record sound”
valore_ritorno = mciSendString(comando, vbNullString, 1024, 0)
Si registra il suono desiderato per quanto
si vuole.
Quando si vuole interrompere la registrazio-
ne, si utilizza la funzione di “Stop” presente
nel Listato 6. Per salvare il suono si utilizza
questo semplice comando:
comando = “save sound” + nome_suono
valore_ritorno = mciSendString(comando, vbNullString, 1024, 0)
dove nome_suono è una variabile di tipo
String, in cui è stato immesso un nome da
inputbox o da textbox, una fun-
zionalità semplice da implemen-
tare nell’applicativo.
Questo conclude la panoramica
relativa alla manipolazione dei
file WAV.
ConclusioniAbbiamo visto solo alcune delle
funzionalità principali della libre-
ria “winmm”.
A tale proposito, credo che quel-
le relative alla manipolazione di
suoni siano importanti per avere
informazioni e allarmi da un pro-
cesso software.
Consiglio caldamente di consul-
tare la bibliografia alla fine di que-
sto articolo, dove potete trovare al-
tre funzione relative alla riprodu-
zione dei CD o dei file MIDI, che
possono sempre risultare utili.
Bibliografia[1] Francesco Balena – I trucchi di
Visual Basic 6, Mondadori Infor-
matica, 2003, ISBN 8883314778
Li sta to 6 Funzioni di manipolazione di un file WAV
Private Sub Esegui_WAV() comando = “play sound” valore_ritorno = mciSendString(comando, vbNullString, 1024, 0)End Sub
Private Sub Apri_WAV() cd.Filter = “(*.wav)|*.wav” cd.FilterIndex = 0 cd.FileName = “” cd.ShowOpen nome_file = cd.FileName nome_file = Chr$(34) + nome_file + Chr$(34) comando = “open “ + nome_file + “ type waveaudio alias sound” valore_ritorno = mciSendString(comando, vbNullString, 1024, 0)End Sub
Private Sub Riavvolgi_WAV() comando = “seek sound to start” valore_ritorno = mciSendString(comando, vbNullString, 1024, 0)End Sub
Private Sub Chiudi_WAV() comando = “close sound” valore_ritorno = mciSendString(comando, vbNullString, 1024, 0)End Sub
Private Sub Stop_WAV() comando = “stop sound” valore_ritorno = mciSendString(comando, vbNullString, 1024, 0)End Sub
Li sta to 5 Ridimensionamento del file AVI nella PictureBox
Private Sub Ridimensiona_In_PB( ) Height = PictureBox.ScaleHeight/Screen.TwipsPerPixelY Width = PictureBox.ScaleWidth/Screen.TwipsPerPixelX comando = = “Put AVIFile window at 0 0 “ + Cstr(Width) + “ “ + CStr(Height) valore_ritorno = mciSendString(comando, vbNullString, 1024, 0)End Sub
MULTIMEDIA
26 VBJ N. 65 - Settembre/Ottobre 2005
In questa seconda parte dedicata al nostro pro-
getto di controllo remoto in Visual Basic .NET,
spiegheremo in dettaglio il codice di implemen-
tazione della classe RemoteStructure.
Abbiamo detto che questa classe è estremamente
importante, in quanto costituisce la classe base dal-
la quale altre classi erediteranno alcune proprietà e
metodi fondamentali. Incominciamo subito a dare
uno sguardo alle linee di codice di un primo sem-
plice metodo pubblico.
Public Function getLogicalUnits() As String
oSequenzaDrives = “REPLYDRIVESSEQUENCE>”
oUnits = Environment.GetLogicalDrives()
For Each oDrive In oUnits
oSequenzaDrives &= oDrive & “*”
Next
Return oSequenzaDrives
End Function
Questo metodo, che chiamiamo getLogicalUnits,
consente di ottenere un array di tipo string conte-
nente le radici di tutte le unità logiche presenti nel
sistema della macchina controllata, quindi eventua-
li dischi fisici e partizioni logiche. Per ottenere tutto
questo è sufficiente invocare il metodo GetLogical-
Drives() della classe Environment. In questo caso,
come si può osservare, il Target (server) dovrà ri-
spondere al Controller (client)
per mezzo di un appropriato co-
mando in formato stringa (RE-
PLYDRIVESSEQUENCE>).
A questo punto dobbiamo com-
pletare la stringa di risposta con
tutte le lettere di unità individua-
te. Utilizziamo un ciclo For Each
Next per iterare automaticamen-
te l’array privato di tipo string
oUnits e collochiamo sequen-
zialmente tutti i valori all’inter-
no della nostra stringa, ciascuno
separato da un apposito caratte-
re separatore. In questo specifico
caso utilizziamo il carattere aste-
risco. A questo punto nel blocco
Select principale del server dob-
biamo collocare il codice neces-
sario per intercettare ed eseguire
questa specifica operazione.
Case Is = “GETDRIVESLIST”
writer.Write(objStruct.getLogicalUnits())
sentText.Clear()
sentText.Text = objStruct.getLogicalUnits()
I lettori più attenti certamen-
te avranno intuito che, in fase
di inizializzazione della Form1,
abbiamo già provveduto a istan-
ziare un oggetto (objStruct) dal-
la classe RemoteStructure. Non
resta quindi che invocare il me-
todo precedentemente illustrato
Controllo Remotoin Visual Basic .NET
di Stefano Corti
APPLICAZIONI
Seconda puntata
Stefano Corti si occupa di programmazione PHP e JSP lato server, della piattaforma .NET e di integrazione di sistemi legacy con le nuove realtà del web, soprattutto in ambito gestionale, bancario e finanziario. È attualmente alle dipendenze di un primario gruppo bancario italiano. Può essere contattato via email: [email protected].
27N. 65 - Settembre/Ottobre 2005 VBJ
te nella stringa ven-
gono estratte e col-
locate in un nuovo
array di tipo string
a_splitResult. Pos-
siamo quindi itera-
re questo array e,
all’interno del ci-
clo medesimo, ri-
chiamare il metodo
Add() per posiziona-
re in ListView1 tutte
le informazioni ne-
cessarie. Un altro
importante metodo
della nostra classe
RemoteStructure è
certamente getFile-
sAndDirectories().
Si tratta di un me-
todo pubblico che
restituisce varie ti-
pologie di informa-
zioni su file e directory residenti sulla macchi-
na remota. Questo metodo utilizza il metodo
privato getInformation(). Ci sembra opportuno
ricordare che getInformation() viene dichiara-
to Private dal momento che deve essere acces-
sibile solo all’interno della classe nella quale
viene definito, poiché i valori restituiti ven-
gono utilizzati esclusivamente da altri metodi
implementati all’interno della classe medesi-
ma. Al metodo GetInformation() viene passa-
to, per riferimento, il contenuto della variabile
stringa privata oFileDirName. Tale variabile,
come abbiamo visto, viene già inizializzata al-
l’interno del costruttore sovraccarico della no-
stra classe, ma anche all’interno del codice di
implementazione della proprietà Profile, come
si può chiaramente evincere osservando la se-
guente porzione di codice
Sub New()
Me.oFileDirName = “C:\”
End Sub
Sub New(ByVal FileName As String)
Me.oFileDirName = FileName
End Sub
ed iniettare nel socket di flusso la stringa così
ottenuta. Vediamo ora ciò che avviene nel pro-
gramma Controller.
If job(0) = “REPLYDRIVESSEQUENCE” Then
Dim a_delimStr As String = “*”
Dim a_delimiter As Char() = a_delimStr.ToCharArray()
Dim a_splitResult As String() = Nothing
a_splitResult = job(1).Split(a_delimiter)
Dim a_inList As String
ListView1.Items.Clear()
For Each a_inList In a_splitResult
ListView1.Items.Add(a_inList)
Next
End If
Anche in questo caso abbiamo previsto una
serie di condizioni If End If per analizzare tutti
i comandi provenenti da Target, laddove ogni
comando è contenuto nell’array job con indi-
ce 0 e i relativi parametri in indice 1. Tutte le
unità logiche trasmesse (separate dall’apposito
carattere separatore) devono popolare un con-
trollo ListView che chiamiamo ListView1. Tut-
te le lettere di unità contenute sequenzialmen-
APPLICAZIONI
Fi gu ra 1 I controlli per la gestione dei file
28 VBJ N. 65 - Settembre/Ottobre 2005
Public Property Profile() As String
Get
Return oFileDirName
End Get
Set(ByVal Value As String)
oFileDirName = Value
Set
End Property
In questo modo, la variabile privata oFileDir-
Name contiene sempre un percorso assoluto al-
l’interno del file system della macchina Target
che punta direttamente ad un qualsiasi file o ad
una qualsiasi directory. Il nostro metodo privato
utilizza una serie di metodi esposti dalla classe
File appartenente al namespace System.IO per
ricavare informazioni dettagliate su un particola-
re file o su una specifica directory, come ad esem-
pio la data di creazione, di modifica e dell’ultimo
accesso. Questi dati vengono restituiti dal meto-
do getFilesAndDirectories() che esegue un’anali-
si approfondita sulla tipo-
logia del file, tentando an-
che di eseguire una lettu-
ra, nel caso si tratti di un
file di testo (quindi non
file binari), ed eseguendo
un’esplorazione in profon-
dità nel caso che il percor-
so il questione non sia un
file bensì una directory. Ve-
diamo in dettaglio queste
funzionalità analizzando il
Listato 1.
Prima di tutto dobbiamo
stabilire se il percorso con-
tenuto nella variabile pri-
vata oFileDirName punta
ad un file oppure a una di-
rectory. Possiamo nuova-
mente utilizzare un meto-
do della classe File per ot-
tenere questo scopo. Rite-
niamo opportuno ricordare
che la classe File della FCL
(Framework Class Library)
del .NET Framework espo-
ne esclusivamente membri
statici, quindi non è necessario istanziare oggetti
da questa classe, bensì è possibile invocare di-
rettamente il metodo che ci interessa, passan-
do l’argomento al parametro del metodo stesso.
Utilizziamo, ad esempio, il metodo pubblico Exi-
sts() passando come argomento della funzione
il percorso all’interno del file system, prestando
particolare attenzione che il parametro specifi-
cato sia formalmente corretto, altrimenti verrà
generata un’eccezione che il nostro codice non
sarà in grado di intercettare e gestire adeguata-
mente. Il metodo Exists() restituisce un valore
boolean, quindi otteniamo True nel caso il pa-
rametro passato punti ad un file realmente pre-
sente sul computer, oppure False in caso con-
trario. Vediamo ora di applicare lo stesso me-
todo alla classe Directory che si comporta esat-
tamente come la classe File, esponendo quindi
una nutrita seria di metodi statici per il tratta-
mento delle directory. Nel caso il percorso spe-
cificato punti ad una directory – cosa che pos-
APPLICAZIONI
Li sta to 1 Il metodo pubblico getFilesAndDirectories() della classe Remote
Structure
Public Function getFilesAndDirectories() As String If File.Exists(oFileDirName) Then oReturned = GetInformation(oFileDirName) Try oStream = New StreamReader(oFileDirName) oReturned &= oStream.ReadToEnd() Catch ec As IOException oReturned &= “Errore di I/O su file: “ & ec.Message Catch ec As ArgumentException oReturned &= “Errore Intercettato: “ & ec.Message End Try ElseIf Directory.Exists(oFileDirName) Then Dim i As Integer Dim h As Integer oReturned = GetInformation(oFileDirName) oDirectoryList = Directory.GetDirectories(oFileDirName) oDirectoryFileList = Directory.GetFiles(oFileDirName) oReturned &= vbCrLf & _ “Contenuto della Directory: “ & vbCrLf For i = 0 To oDirectoryList.Length - 1 oReturned &= oDirectoryList(i) & vbCrLf Next For h = 0 To oDirectoryFileList.Length - 1 oReturned &= oDirectoryFileList(h) & vbCrLf Next Else oReturned &= “Errore: “ & oFileDirName & “ non trovato.” & vbCrLf End If Return oReturnedEnd Function
29N. 65 - Settembre/Ottobre 2005 VBJ
siamo sempre verificare con Exists() – inizializ-
ziamo due variabili di tipo Integer i e h. Innanzi
tutto invochiamo sempre il nostro metodo priva-
to getInformation() per ottenere informazioni di
base sulla nostra directory, dopo di ché dobbiamo
analizzare la directory per verificare se vi sono
contenuti dei file eventualmente insieme ad al-
tre directory. Chiamiamo quindi i metodi stati-
ci GetDirectories() e GetFiles() che restituiscono
matrici private a una dimensione di tipo string
contenenti rispettivamente la
lista delle eventuali directory
e degli eventuali file contenu-
ti nella directory analizzata. A
questo punto non ci resta che
iterare questi due array di tipo
string per mezzo di due cicli
For Next utilizzando la pro-
prietà Length (-1) per deter-
minare il numero totale degli
elementi presenti nell’array.
Tutti i file e tutte le directory
ricavate possono quindi esse-
re copiati nella variabile pri-
vata oReturned che viene uti-
lizzata per restituire il valore
in uscita dal metodo. Precisia-
mo che il metodo descrit-
to restituisce valori pura-
mente testuali che verran-
no visualizzati in un’appo-
sita area di testo all’inter-
no della GUI del Control-
ler. L’utente potrà quindi
vedere le caratteristiche
di un particolare file e i
contenuti di una partico-
lare directory senza ave-
re la possibilità di esegui-
re alcuna esplorazione
gerarchica. L’interfaccia
utente del Controller, il
cui progetto verrà tratta-
to approfonditamente in
seguito, prevede una se-
rie di schede selezionabili
mediante altrettanti Con-
trol Tabs. Una scheda par-
ticolarmente importante, alla quale facciamo su-
bito riferimento, è certamente quella contenen-
te tutti i controlli per le funzioni di file mana-
ger (vedi Figura 1). Possiamo facilmente nota-
re che la zona superiore della scheda contiene i
controlli per l’esplorazione delle directory e dei
file sul PC locale in uso, mentre nella parte sot-
tostante si possono trovare tutti i pulsanti che
consentono di eseguire le funzionalità di base
di file management sulla macchina remota. Il
APPLICAZIONI
Li sta to 3 Metodo pubblico per la rimozione di file e cartelle
Public Function deleteDirOrFil(ByVal pathTODEL As String) As String Dim retS As String = Nothing If Directory.Exists(pathTODEL) Then Directory.Delete(pathTODEL) retS = “Directory “ & pathTODEL & “ eliminata.” End If If File.Exists(pathTODEL) Then File.Delete(pathTODEL) retS = “File “ & pathTODEL & “ eliminato.” End If If retS Is Nothing Or retS = “” Then retS = “Attenzione: Il percorso “ & pathTODEL & “ non esiste.” End If
Return retSEnd Function
Li sta to 2 Gestione del comando GETREMOTESTRUCTURELIST all’interno
della struttura Select Case EndSelect
Case Is = “GETREMOTESTRUCTURELIST” If job(1) = “CONTENUTO DELLA DIRECTORY REMOTA” Then Try Dim root As DirectoryInfo = Directory.GetParent(objStruct.Profile) Dim abso As String = root.FullName objStruct.Profile = abso writer.Write(objStruct.exploreRemoteDirOrFil()) sentText.Clear() sentText.Text = objStruct.exploreRemoteDirOrFil() Catch nre As System.NullReferenceException writer.Write(“ERRORMAINDIRECTORY>NOARGS”) Catch nrg As Exception MessageBox.Show(“Eccezione Intercettata: “ & _ nrg.Message, “Eccezione Sollevata”, _ MessageBoxButtons.OK, MessageBoxIcon.Error) End Try Else objStruct.Profile = job(1) writer.Write(objStruct.exploreRemoteDirOrFil()) sentText.Clear() sentText.Text = objStruct.exploreRemoteDirOrFil() End If
30 VBJ N. 65 - Settembre/Ottobre 2005
pulsante “Unità Logiche” ci consente di ottene-
re la lista completa delle partizioni presenti su
Target, come abbiamo in precedenza visto. Un
altro pulsante molto importante è certamente
“Esplora Elemento Selezionato”, che consente
di scendere di un livello nella scala gerarchica
del file system remoto, popolando il ListView1
con tutti i file e le cartelle presenti nel percor-
so selezionato. La pressione di questo pulsan-
te scatena un evento il cui codice associato cat-
tura il percorso assoluto presente in Listview1
e costruisce la stringa da trasmettere a Target,
facendola precedere dal comando GETREMO-
TESTRUCTURELIST>. Tale comando, unita-
mente al parametro trasmesso, viene interpre-
tato dal server mediante la consueta struttura
Select Case End Select.
Case Is = “GETREMOTESTRUCTURELIST”
objStruct.Profile = job(1)
Try
writer.Write(objStruct.exploreRemoteDirOrFil())
sentText.Clear()
sentText.Text = objStruct.exploreRemoteDirOrFil()
Catch
...
End Try
End If
In questa fase andiamo quindi ad implementa-
re il metodo exploreRemoteDirOrFil all’interno
della nostra classe RemoteStructure, in quanto,
come possiamo vedere, dovrà essere invocato
per l’oggetto objStruct di tipo RemoteStructu-
re. Si noti che la proprietà Profile di objStruct
viene impostata sulla base del valore stringa
contenuto in job(1). Tale stringa contiene il per-
corso assoluto del file o della directory da esa-
minare selezionati nella GUI del Controller. In
APPLICAZIONI
Li sta to 4 Codice che gestisce la richiesta di conferma nella GUI del Controller in seguito al comando preposto
all’eliminazione di file o directory sulla macchina Target
Private Sub elimButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles elimButton.Click Dim messGo As String = “DELETESELECTEDFILEDIRECTORY>” Dim prFD As String Dim promptResult As DialogResult Dim list_x As ListView.SelectedListViewItemCollection list_x = Me.ListView1.SelectedItems Dim i_list_x As ListViewItem For Each i_list_x In list_x messGo &= i_list_x.Text.ToString() prFD = i_list_x.Text.ToString() Next If (messGo = “DELETESELECTEDFILEDIRECTORY>”) Then MessageBox.Show(“Dovete prima selezionare un file o una directory da eliminare.”, _ “Messaggio di Errore”, MessageBoxButtons.OK, MessageBoxIcon.Error) Else promptResult = MessageBox.Show(“ATTENZIONE !!! “ & vbCrLf & “Siete sicuri di volere definitivamente eliminare” & _ vbCrLf & prFD & “ ?”, “Attenzione !!! Richiesta di Conferma”, MessageBoxButtons.YesNo, MessageBoxIcon.Question) If promptResult = DialogResult.Yes Then Try writer.Write(messGo) inMessages.Clear() inMessages.Text &= vbCrLf & “Comando Inviato: “ & vbCrLf & _ messGo Catch exception As SocketException inMessages.Text &= “Errore di comunicazione con il computer remoto: “ & _ exception.Message & vbCrLf Catch ex As Exception inMessages.Text &= “Errore: “ & ex.Message & vbCrLf End Try End If End If End Sub
31N. 65 - Settembre/Ottobre 2005 VBJ
APPLICAZIONI
questo modo la variabile stringa privata della
nostra classe assumerà il valore di tale percor-
so. Implementiamo ora il metodo osservando
il Listato 2. Questa volta utilizziamo i metodi
di istanza della classe DirectoryInfo. Creiamo
dunque un oggetto di tipo DirectoryInfo pas-
sando come argomento del costruttore il valore
corrente della variabile privata oFileDirName.
Chiamiamo questo oggetto di. Se la directory
esiste e il percorso contenuto nella variabile
oFileDirName non punta ad un file, possiamo
iniziare a riempire la variabile privata oSequen-
zaDirFil con l’apposito comando da restituire,
mediante il nostro socket di flusso, al program-
ma Controller (REPLYREMOTEDIR>). Veri-
fichiamo quindi se all’interno della directory
corrente vi sono altre directory, mediante la
seguente linea di codice
Dim listadir As DirectoryInfo() = di.GetDirectories
Otteniamo così un array di elementi che pos-
sono essere manipolati ed iniettati sequenzial-
mente in una stringa mediante un carattere se-
paratore, tecnica che abbiamo già analizzato in
precedenza.
All’interno di questo specifico ciclo For Each
Next è importante eseguire un controllo sulla
correttezza formale del percorso assoluto del
file system e assicurarsi che la formazione del-
le stringhe che contengono i percorsi completi
delle directory siano perfettamente ricostruiti,
poiché, in caso contrario, esse verranno visua-
lizzate nel ListView1 all’interno della GUI del
Controller e, qualora selezionati per un’eventua-
le successiva operazione, l’errore si ribaltereb-
be nuovamente su Target, generando un erro-
re logico, previsto tra l’altro nelle ultime righe
di codice del Listato 2, nell’ultima condizione
Else, laddove il percorso fornito dal Controller
non sia corrispondente ad uno specifico file o di-
rectory esistenti all’interno del file system della
macchina remota. All’interno del ciclo iteratore
verifichiamo con il metodo EndsWith se l’ulti-
mo carattere della variabile oFileDirName cor-
risponda al carattere ASCII backslash (“\”). Se
il valore boolean ritornato dal metodo è True
proseguiamo la costruzione della nostra strin-
ga oSequenzaDirFil concatenando il valore re-
stituito dalla proprietà Name dell’oggetto dr di
tipo DirectoryInfo. In questo caso la proprietà
Name non restituisce il percorso completo ed
assoluto delle eventuali sottodirectory contenu-
te nella directory superiore di riferimento, ben-
sì solamente i nomi di tali cartelle. Noi abbiamo
invece bisogno di concatenare esclusivamente
percorsi completi. Tali percorsi devono inizia-
re sempre con la radice dell’unità logica di ri-
ferimento, poiché è in questo modo che vengo-
no visualizzati nel ListView1 del controller per
potere essere facilmente ritrasmessi al Target
sotto forma di concatenazioni di stringhe. Se la
nostra stringa oFileDirName non dovesse ter-
minare con il carattere backslash, è necessario
aggiungerlo, quindi concatenare il nome rela-
tivo della sottocartella individuata in ogni ciclo
dell’iterazione e infine terminare con il caratte-
re separatore asterisco.
Dim listadir As DirectoryInfo() = di.GetDirectories
Dim dr As DirectoryInfo
For Each dr In listadir
If oFileDirName.EndsWith(“\”) Then
oSequenzaDirFil &= oFileDirName & dr.Name & “*”
Else
oSequenzaDirFil &= oFileDirName & “\” & dr.Name & “*”
End If
Next
Per ottenere invece una lista completa dei
file presenti all’interno della cartella selezio-
nata, utilizziamo nuovamente il metodo stati-
co GetFiles() della classe Directory che ritor-
na una matrice facilmente attraversabile con
il consueto ciclo For Each Next. Dopo l’ese-
cuzione completa dei due cicli di cui abbia-
mo parlato, tutti i valori ricavati (in sequenza
tutte le directory, seguite da tutti i file presen-
ti nella cartella di riferimento, come sappiamo
contenuta nella variabile privata oFileDirName
che viene istantaneamente modificata in base
ai nuovi settaggi della proprietà profile) si trova-
no concatenati nella variabile stringa oSequen-
zaDirFil, il cui valore viene direttamente resti-
tuito dal nostro metodo. In ultima analisi, se il
percorso selezionato nel ListView1 punta ad un
32 VBJ N. 65 - Settembre/Ottobre 2005
APPLICAZIONI
file, tale procedimento non avrebbe senso, ra-
gione per cui ci limiteremo a ricavare le infor-
mazioni di base del file stesso invocando il me-
todo privato getInformation, precedentemente
descritto. Come abbiamo visto, se anche questa
condizione non viene soddisfatta, è facilmente
intuibile che il percorso del file system sia sta-
to trasmesso erroneamente o incompleto, caso
previsto dall’ultima condizione Else. Riteniamo
oppurtuno sottolineare l’importanza del meto-
do appena definito, in quanto, unitamente alla
proprietà Profile, ci consente di svolgere mol-
te operazioni di base su file e cartelle residenti
su Target. All’interno della struttura Select nel-
la Form1 del server, abbiamo previsto anche al-
cuni casi paricolari. Più precisamente vogliamo
gestire il caso in cui dal Controller venga gene-
rato un comando che ci chieda di risalire di un
livello all’interno della struttura gerarchica di
file e cartelle, senza modificare il codice di im-
plementazione della nostra classe.
Case Is = “UPONEREMOTELEVEL”
Try
Dim root As DirectoryInfo = Directory.GetParent(objStruct.
Profile
Dim abso As String = root.FullName
objStruct.Profile = abso
writer.Write(objStruct.exploreRemoteDirOrFil())
sentText.Clear()
sentText.Text = objStruct.exploreRemoteDirOrFil()
Catch nre As System.NullReferenceException
writer.Write(“ERRORMAINDIRECTORY>NOARGS”)
Catch nrj As Exception
MessageBox.Show(“Errore: “ & _
nrj.Message, “Messaggio di Errore”, _
MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
Non dobbiamo fare altro che invocare il me-
todo GetParent() della classe Directory passan-
do come argomento il valore (stringa) della pro-
prietà Profile dell’oggetto objStruct.
Per ottenere il percorso completo della di-
rectory così ottenuta utilizziamo la proprietà
FullName della classe DirectoryInfo. Il valore
restituito viene utilizzato per impostare nuova-
mente la proprietà Profile e quindi invocare il
nostro metodo exploreRemoteDirOrFil(). L’ulti-
mo metodo definito all’interno della classe Re-
moteStructure serve per eliminare cartelle e file
sul PC remoto.
Si tratta di un metodo molto semplice che uti-
lizza i metodi statici Delete() esposti dalle clas-
si File e Directory e restituisce un messaggio
stringa contenente l’esito positivo o negativo
dell’operazione. Si veda il Listato 3 per l’imple-
mentazione del relativo codice. In questo con-
testo, riteniamo opportuno soffermarci un poco
sul relativo codice scritto per il programma Con-
troller. Nella scheda di File Manager possiamo
trovare l’apposito pulsante la cui pressione sca-
tena l’evento richesto dalla nostra procedura.
Prima di tutto dobbiamo essere sicuri che
l’utente desideri effettivamente la cancellazio-
ne del file o della cartella selezionati nel Li-
stView1. Non appena il relativo comando vie-
ne immesso nel socket di flusso e ricevuto dal
server, questi provvederà immediatamente alla
cancellazione del file o della directory specifi-
cata nel parametro, senza alcuna possibilità di
recupero. Questa è la ragione per la quale rite-
niamo doveroso inserire una sorta di control-
lo “lato client” prima di procedere con l’invio
del comando.
Utilizziamo per questo scopo una semplice fi-
nestra di dialogo che ci chiede se siamo sicuri di
volere cancellare definitivamente sulla macchi-
na remota il file o la directory specificata.
In caso affermativo, l’esecuzione del program-
ma prosegue con il consueto blocco Try Catch,
che gestisce il codice che scrive nel socket TCP/
IP aperto la sequenza binaria corrispondente ai
caratteri ASCII della stringa che costituisce il
comando impartito insieme al relativo parame-
tro. Tale parametro, ovviamente, non sarà altro
che il percorso assoluto e completo della risorsa
selezionata nel nostro controllo ListView1.
ConclusioniNella prossima puntata descriveremo un’al-
tra importante classe del nostro progetto che
ci consente di controllare i processi in ese-
cuzione, di creare nuove cartelle e di otte-
nere particolari informazioni sulla configu-
razione del PC remoto.
33N. 65 - Settembre/Ottobre 2005 VBJ
XML (eXtensible Markup Language) ha rap-
presentato di fatto una rivoluzione nel con-
cetto di rappresentazione e di scambio dei
dati (vedi Riquadro 1). A suggerirne l’utilizzo negli
ambiti più disparati dell’informatica sono le sue pre-
ziose capacità intrinseche, come quella di astrarre il
contenuto di un documento dalla sua presentazione,
essere autodescrittivo, semplificare la condivisione
dei dati tra piattaforme indipendenti, essere leggi-
bile dall’uomo e usare una struttura gerarchica di
archiviazione dei dati. In particolare, il fatto di es-
sere un formato di dati auto-descrittivo implica la
possibilità di descrivere il medesimo dato con at-
tributi diversi: in altre parole, un dato caratterizza-
to da attributi variabili, ciò che si intende per dato
semi-strutturato (semi-structured data) o destrut-
turato. Poiché tale possibilità è sconosciuta al mo-
dello di dati relazionale, è proprio questo particola-
re aspetto dell’XML che mette in luce il vantaggio
maggiore di avere un supporto XML o, ancor me-
glio, un tipo di dato nativo XML in un database re-
lazionale puro come Sql Server. A questo proposito,
è bene tenere presente la distinzione fondamenta-
le che esiste tra database nativi XML (NDX) e da-
tabase relazionali con supporto
XML (XED), basata sul motore
di persistenza dei dati [1][2]: in
un database NDX il documen-
to XML costituisce l’unità fon-
damentale di persistenza, men-
tre in un XED la persistenza
continua ad essere affidata ad
un motore relazionale oppure
object oriented.
Il consorzio XML:DB Iniziati-
ve [3], che si occupa della defi-
nizione di una API standard per
la gestione dei database XML,
ha definito i seguenti requisiti
fondamentali per un database
nativo XML (NDX):
1. deve presentare un modello
logico per la gestione dei do-
cumenti XML e fornire stru-
menti, conformi a tale model-
lo, per memorizzare ed inter-
rogare questi documenti. Il
database può implementare
un proprio modello oppure
adottare uno di quelli dispo-
nibili come quelli utilizzati
da XPath o XML Infoset;
2. deve avere come unità fonda-
mentale di memorizzazione il
DATABASE
Supporto XML inSQL Server 2005
di Francesco Quaratino
Sql Server 2005 introduce il tipo di dato nativo XML per
trattare documenti e frammenti XML, insieme a metodi
specifici per interrogare e modificarne il contenuto. XQue-
ry è il linguaggio implementato per le interrogazione dei
dati XML attraverso i nuovi metodi di interrogazione.
Francesco Quaratino è consulente in ambito di proget-tazione e amministrazione di database OLTP e OLAP, oltre che di applicazioni software orientati ai dati. È certificato MCDBA e sviluppa in VB6, ASP, VB.NET e ASP.NET. Può essere contattatto attraverso il sito di divulgazione infor-matica http://www.xplayn.org.
34 VBJ N. 65 - Settembre/Ottobre 2005
CREATE TABLE xml_tab
(
id INT PRIMARY KEY,
xml_col XML
)
GO
Alla stregua di un campo tradizionale del
modello relazionale, per il campo XML si
può specificare se ammette valore NULL o
meno, fornire un valore di default, e defi-
nire un vincolo CHECK.
Nell’esempio seguente viene creato un vin-
colo CHECK sul campo di tipo XML che ve-
rifica l’esistenza dell’elemento titolo. I me-
todi XML (di cui parleremo dopo) devono
essere forniti attraverso una user-defined
function:
CREATE FUNCTION udf_check_xml (@xml_col XML)
RETURNS bit AS
BEGIN
RETURN (SELECT (@xml_col.exist(‘//titolo’)))
END
GO
CREATE TABLE xml_tab
(
id INT PRIMARY KEY,
xml_col XML NOT NULL DEFAULT(‘<libro><autore/><editore/
><titolo/></libro>’)
CONSTRAINT CK_name CHECK (dbo.udf_check_xml (xml_col) = 1)
)
GO
Nel campo xml_col si può inserire un docu-
mento o frammento XML well-formed (vedi
Riquadro 2), in caso contrario l’istruzione di
inserimento/aggiornamento fallisce:
INSERT INTO xml_tab VALUES(1, ‘<libro><autore/><editore/
><titolo/></libro>’)
INSERT INTO xml_tab VALUES(2, N’<autore/><editore/><titolo/>’)
--fallisce perché il frammento XML inserito non è well-formed
INSERT INTO xml_tab VALUES(3, ‘<autore><editore></autore></
editore>’)
documento XML, allo stesso modo in cui
la tabella è l’unità di base nei database re-
lazionali;
3. deve essere indipendente dal modello fi-
sico di storage.
In un’accezione più ampia, invece, possono es-
sere considerati database XML quei database
che, pur non offrendo un tipo di persistenza del
dato XML, espongono metodi di accesso tipici
della tecnologia XML (XPath, XQuery, DOM).
Sql Server 2005 migliora il supporto XML pre-
cedentemente offerto da Sql Server 2000 intro-
ducendo il tipo di dato nativo XML e metodi di
accesso ai dati XML, proponendo un modello
già da tempo consolidato nel DBMS Oracle –
rivale di sempre e oggi più che mai.
Passato e presente di XML in Sql ServerSql Server 2000 non aveva un tipo di dato
nativo XML. Si sopperiva a questa mancan-
za con l’uso di campi di tipo TEXT oppure
con la memorizzazione in formato relazio-
nale (sempre che la struttura del documen-
to XML fosse sufficientemente semplice da
rendere possibile la memorizzazione del do-
cumento in tabelle normalizzate) [1]. Usare
campi di tipo TEXT inibisce la possibilità di
usare un linguaggio di query (XPath) sul do-
cumento salvato, e con essa tutte le potenzia-
lità che XML è in grado di esprimere, mentre
la memorizzazione in formato relazionale co-
stringe a una sorta di conversione che implica
un notevole lavoro e, comunque, fa perdere la
capacità gerarchica di lavorare con XML. Con
Sql Server 2005 si possono memorizzare do-
cumenti o frammenti XML in un tipo di dato
nativo XML (un frammento è un documento
XML privo di una elemento radice). Ciò per-
mette di creare tabelle che registrino solo dati
XML o dati XML insieme a dati relazionali,
validare dati XML attraverso gli schema, crea-
re indici sui dati XML, interrogare e modifi-
care dati con XQuery, combinare i metodi di
interrogazione dei dati XML con query stan-
dard T-Sql per scrivere query che restituisca-
no dati relazionali insieme a dati XML. Ecco
come creare un campo di tipo XML:
DATABASE
35N. 65 - Settembre/Ottobre 2005 VBJ
--fallisce perché viola il CHECK CONSTRAINT
INSERT INTO xml_tab VALUES(4, ‘<autore></autore><editore></
editore>’)
Il dato XML è registrato internamente in un
formato binario compresso per consentire un
parsing più veloce rispetto ad una rappresen-
tazione testuale. Quando il dato viene usato, è
convertito in Varchar unicode (UTF-16).
Per determinare la dimensione in byte effet-
tiva di un dato XML si può valutare la funzio-
ne DATALENGTH():
SELECT DATALENGTH (xml_col) FROM xml_tab
Il tipo di dato XML può essere adoperato ol-
tre che per creare campi di tabella, anche per
definire variabili e parametri di input e output
di stored procedure e user-defined function.
CREATE PROCEDURE sp_xml (
@x XML,
@y XML OUTPUT)
AS
...
CREATE FUNCTION fn_xml (
@x NVARCHAR(max))
RETURNS XML
AS
DECLARE @a XML
SET @a = @x
...
RETURN @a
Metodi del tipo di dato XMLPer interrogare un dato XML estraendo un
frammento o l’intero documento XML, è possi-
bile usare metodi esposti dal dato XML, i quali
accettano come parametro di input un’espres-
sione XQuery. XQuery 1.0 è un linguaggio di
interrogazione standard di dati XML definito
dal Wide Web Consortium (W3C) e basato su
XPath 2.0, un linguaggio di navigazione che
usa una sintassi path-based per l’identificazio-
ne dei nodi di un documento XML. XQuery è
un linguaggio dichiarativo, tipizzato e funzio-
nale, e trattasi, fondamentalmente, di un’esten-
sione (superset) di XPath 2.0. Sql Server 2005
supporta un sottoinsieme di XQuery 1.0 basa-
to sul draft di Novembre 2003 [4]. I metodi ap-
plicabili sul dato XML sono i seguenti: exist(),
query(), value(), nodes() e modify().
Il metodo exist() permette di valutare l’esi-
stenza di elementi o attributi nelle clausole
WHERE o nei CHECK CONSTRAINT, e re-
stituisce il valore 1 se la valutazione ha esito
positivo, oppure 0 (zero) in caso di esito negati-
vo. Di seguito, un esempio che fa uso di exist()
nella clausola WHERE di una SELECT, allo
scopo di selezionare le righe che presentano
nel campo XML denominato xml_col il valore
“Infomedia” in un qualsiasi attributo (@*) del-
l’elemento “editore”, indipendentemente dalla
posizione (//) di quest’ultimo nel dato XML.
SELECT * FROM xml_tab
WHERE xml_col.exist(‘//editore[@*=”Infomedia”]’) = 1
Il metodo query() restituisce un untyped
XML (documento o frammento), come risul-
tato della valutazione dell’espressione XQue-
ry su una lista di nodi XML. Il metodo va-
lue() restituisce un dato scalare convertito
nel tipo di dato T-SQL specificato come se-
condo argomento della funzione. Di seguito
DATABASE
Ri qua dro 1 Come nasce XML
Nel 1996, l’XML Working Group creò XML (eXtensible
Markup Language) basandosi sul meta-linguaggio SGML
(Standard Generalized Markup Language) costituito da
un insieme di regole per la creazione di linguaggi di
marcatura (markup languages). XML scaturì dal tenta-
tivo di superare le limitazioni dell’HTML, altro linguaggio
di marcatura derivato da SGML e divenuto popolarissi-
mo con la diffusione di internet. Infatti, l’HTML non è in
grado di presentare una strutturazione semanticamente
corretta delle informazioni, demanda l’elaborazione dei
dati interamente ad altri linguaggi e, soprattutto, non è
estendibile, costringendo i produttori di software a creare
propri standard. Fondamentalmente, rispetto all’HTML,
XML ha introdotto la gestione dei tag e degli attributi,
una strutturazione di tipo gerarchico, e la validazione del
documento attraverso gli schema. L’XSL (eXtensible Style-
sheet Language), nato un anno dopo, ha reso possibile la
presentazione del documento XML attraverso fogli di stile
(style sheet) che si occupano di trasformare il documento
XML per una sua più facile comprensione.
36 VBJ N. 65 - Settembre/Ottobre 2005
due esempi che fanno uso di value() prima
nella SELECT e poi nella clausola WHERE.
SELECT xml_col.value(‘/libro[1]/autore[1]’, ‘vachar(50)’)
FROM xml_tab
SELECT * FROM xml_tab
WHERE xml_col.value(‘/libro[1]/autore[1]’, ‘varchar(50)’) =
‘F.Quaratino’
Il metodo nodes() scompone il contenuto di
un tipo di dato XML restituendo ogni elemen-
to su una riga diversa. Poiché XQuery non de-
finisce una sintassi per la modifica dei docu-
menti XML, Microsoft ha sviluppato un pro-
prio XML Data Modification Language (DML)
[6] utilizzabile dal metodo modify(), il quale
consente la modifica del dato XML accettando
come parametro di input un’istruzione XML
DML di inserimento (insert), cancellazione
(delete) o sostituzione (replace value of).
Gli indici XMLLa natura destrutturata di un dato XML de-
termina un inconveniente non irrilevante per
un database: una gestione fondamentalmente
lenta del dato. Da qui la necessità di creare de-
gli indici su un campo di tipo XML. Sql Server
2005 prevede la creazione di un indice primario
e fino a 248 indici secondari, a patto che esista
un indice primario (clustered) sulla chiave pri-
maria della tabella. L’indice primario XML in-
dicizza tutti i tag, i valori e i percorsi del con-
tenuto di un campo XML. La chiave primaria
è usata per correlare le righe dell’indice XML
con le righe della tabella di database di cui fa
parte il campo stesso. Di seguito l’istruzione T-
SQL di creazione dell’indice XML primario sul
campo xml_col della tabella xml_tab
CREATE PRIMARY XML INDEX xml_idx on xml_tab (xml_col)
GO
Dopo aver creato un indice primario sulla
colonna XML, è possibile creare indici XML
secondari per velocizzare particolari tipi di
query. Sono disponibili tre tipi di indici XML
secondari: PATH, PROPERTY e VALUE:
• PATH per le ricerche di valori quando si
conosca l’esatto percorso dell’elemento o
attributo da cercare (per esempio: SELECT
* FROM xml_tab WHERE xml_col.exist (‘/
libero[@anno = “2005”]’) = 1)
• VALUE per le ricerche di valori quando
non si conosca il nome o l’esatto percorso
dell’elemento o dell’attributo che contiene
tale valore ( è il caso delle cosiddette query
“wildcard” come: /libro [@* = “poesie”], in
cui la query cerca ogni elemento <libro>
che abbia un qualsiasi attributo che abbia
il valore “poesia” oppure (‘//libro/@genere[.
= “poesia”]’) = 1 in cui viene fornito un
path parziale attraverso //)
• PROPERTY per le ricerche di valori spe-
cificando il nome di un elemento(/libro/
autore)
Ecco la sintassi per la creazione di indici XML
secondari:
CREATE XML INDEX <index_name> on <table_name> (<xml_
column_name>)
DATABASE
Ri qua dro 2 Well-formed e Typed XML
Un documento XML si dice well-formed (ben formato) se osserva le seguenti regole sintattiche:
• tutti gli elementi devono essere chiusi da un tag di chiusura (<persona></persona> o alternativamente <persona/> se non c’è un testo e si tratta di un ele-mento foglia);
• tutti gli elementi devono essere annidati, nonché chiusi nella sequenza opposta a quella con cui sono stati aperti, quindi non ammettendo sovrapposizioni di elementi (<persona><nome></nome></persona> e non <persona><nome></persona></nome>);
• esiste un elemento root che contiene tutti gli altri;• gli elementi sono case sensitive;• il valore degli attributi deve essere racchiuso tra
apici o doppi apici.
Un documento XML si dice typed (tipizzato) se associato ad uno schema, ovvero una struttura definita attraverso una grammatica. Un documento XML si dice valido se segue uno schema. È possibile fare in modo che un do-cumento XML sia sempre conforme alle regole stabilite validandone i dati inseriti e le modifiche apportate alla struttura del documento.
37N. 65 - Settembre/Ottobre 2005 VBJ
USING XML INDEX <index_name> FOR [PATH | VALUE | PROPERTY]
ConclusioniLa combinazione di dati relazionali con dati
XML offre nuove e interessanti possibilità nel-
la modellazione dei dati, in grado di avvici-
narsi maggiormente al mondo reale sempre
suscettibile di cambiamenti. L’introduzione di
un tipo di dato nativo XML consentirà anche
ai progettisti di database che adoperano Sql
Server di progettare applicazioni molto più
flessibili, in quanto capaci di assorbire me-
glio i cambiamenti che intervengono nel do-
minio applicativo dell’applicazione, nel corso
del suo intero ciclo di vita, grazie alla possibi-
lità di modellare i dati destrutturati.
Occorre però fare attenzione a non farne un
uso spregiudicato, dettato dalla moda del mo-
mento o dalla voglia di provare ad ogni costo
il nuovo giocattolo messo a disposizione dal-
la tecnologia emergente. Sarà, quindi, buo-
na norma continuare ad usare il modello re-
lazionale per la maggior parte dei dati, intro-
ducendo campi XML per ospitare informa-
zioni non obbligatorie o che potrebbero cam-
biare col tempo.
Bibliografia e Riferimenti[1] G. Veneri – “DB e XML: prodotti”, Compu-
ter Programming/Infomedia, Maggio 2005
[2] M. Simi – “Database XML nativi”, Compu-
ter Programming/Infomedia, Maggio 2005
[3] XML:DB Initiative –
http://xmldb-org.sourceforge.net
[4] http://www.w3.org/TR/xquery
[5] M. Nunn – “Extending XML in SQL Ser-
ver 2005”, Sql Server Magazine/Penton,
June 2005
[6] P.Vithanala – “Introduction to XQuery
in SQL Server 2005”, Microsoft Corpora-
tion, June 2005 http://msdn.microsoft.com/
library/default.asp?url=/library/en-us/
dnsql90/html/sql2k5_xqueryintro.asp
[7] S. Pal et al. – “XML Best Practices for Micro-
soft SQL Server 2005”, Microsoft Corpora-
tion, April 2004 http://msdn.microsoft.com/
SQL/archive/default.aspx?pull=/library/
en-us/dnsql90/html/sql25xmlbp.asp
[8] S. Pal et al. – “XML Support in Microsoft
SQL Server 2005”, Microsoft Corporation,
May 2005 http://msdn.microsoft.com/library/
default.asp?url=/library/en-us/dnsql90/html/
sql2k5xml.asp
DATABASE
38 VBJ N. 65 - Settembre/Ottobre 2005
In ambiente Windows ci sono applicazioni più
discrete di altre. Applicazioni che sono in ese-
cuzione ma rimangono in disparte, non si fan-
no vedere, talvolta giocano con il disco fisso e si
fanno sentire ma per la maggior parte del tempo
non ci accorgiamo della loro presenza.
Eppure ci sono. Basta aprire il Task Manager per
vedere un lungo elenco di applicazioni in esecu-
zione… Ma chi le ha lanciate e soprattutto: cosa
fanno?
Per chi non lo avesse ancora capito, stiamo par-
lando dei Servizi Windows, quelle particolari ap-
plicazioni che girano in background per svolgere
compiti “di sistema”.
Nel presente articolo analizzeremo cosa sono e
come vengono implementati i Servizi, ne vedre-
mo i vantaggi e i vincoli e vedremo cosa il .NET Fra-
mework mette a disposizione per realizzarne uno.
Cos’è un Servizio WindowsPrima di tutto diamo una definizione di servizio.
Un Servizio Windows è un’applicazione che gira
in background e che normalmente viene manda-
ta in esecuzione non appena il
sistema operativo è avviato, in
una sessione separata da quel-
la dell’eventuale utente che si
è loggato.
Analizziamo meglio questa de-
finizione:
• Un Servizio Windows è un’ap-
plicazione che gira in back-
ground: vuol dire che il ser-
vizio non ha interfaccia uten-
te e la sua esecuzione non è
“visibile” agli utenti che uti-
lizzano il PC su cui gira;
• Normalmente viene mandato
in esecuzione non appena il
sistema operativo è avviato:
infatti i servizi sono spesso
utilizzati per quelle applica-
zioni che devono sempre
essere attive (ad esempio i
server) per cui è importante
che siano attivati dal sistema
operativo senza che ci sia un
utente che acceda e lo mandi
in esecuzione;
• Sono in esecuzione in una
sessione separata da quello
dell’eventuale utente che si è
loggato: infatti se come dice-
vamo sopra i servizi sono ap-
.NET
Sviluppare ServiziWindows con .NET
di Emanuele Delbono e Claudio Maccari
Servizi
In passato scrivere Servizi Windows richiedeva la
conoscenza del C o del C++ ma con l’avvento del framework
.NET e dei suoi nuovi linguaggi C# e VB.NET, lo sviluppo
di questo tipo di applicazioni non è mai stato così semplice.
Vediamo come scriverli, installarli e testarli
Claudio Maccari, la programmazione per lui è una
passione diventata un vero lavoro. Lavora come analista,
progettista e sviluppatore di applicazioni in particolar modo
su piattaforma .NET
Emanuele Delbono si occupa di progettazione e sviluppo
di applicazioni su piattaforma Microsoft .NET. Svolge attività
di formazione e partecipa come speaker a conferenze e
workshop nazionali.
39N. 65 - Settembre/Ottobre 2005 VBJ
ce Control Manager (SCM), il Service Applica-
tion (SA) e il Service Control Program (SCP).
Il SCM è esso stesso un servizio (services.exe)
che gira con privilegi di sistema e si occupa
di gestire gli altri servizi avviandoli, ferman-
doli, mettendoli in pausa, ecc…
Il SA è il servizio vero e proprio quindi un
eseguibile avviato dal SCM che esegue le
operazioni per cui è stato scritto. Un SA avrà
sempre almeno due eventi: OnStart e OnStop.
Questi si verificheranno nel momento il cui il
servizio verrà rispettivamente avviato e fer-
mato. Il SCP è l’interfaccia che permette al-
l’utente di interagire con il servizio inviando
comandi al SCM per avviare, fermare, modi-
ficare le credenziali, ecc… del servizio.
plicazioni silenziose
che vengono esegui-
te all’avvio del siste-
ma operativo, non è
necessario che un
utente sia logga-
to per mandarli in
esecuzione.
Quest’ultima carat-
teristica deve esse-
re tenuta ben presen-
te quando si sviluppa
un servizio: è fonda-
mentale che il servi-
zio non abbia interfac-
cia utente.
Siccome la maggior
parte dei servizi ven-
gono avviati automa-
ticamente dal siste-
ma operativo e gira-
no quindi in un desk-
top virtuale, cosa ac-
cadrebbe se il servizio
mostrasse una finestra
modale e aspettasse il
clic di un pulsante per
continuare la sua ese-
cuzione? Sarebbe cer-
tamente un problema
che renderebbe il ser-
vizio inutilizzabile. Queste caratteristiche fan-
no si che il Servizio sia ottimo per compiti la
cui esecuzione deve essere continua. Si pen-
si ad esempio ad un server web: altro non
è che un’applicazione che rimane in ascolto
sulla porta 80 ed elabora le richieste che arri-
vano dai client. Un’applicazione server (web,
POP3, ecc…) è il tipico esempio di servizio,
tant’è che Microsoft stessa ha implementato
il suo server web (Internet Information Ser-
ver) come servizio (InetInfo.exe).
Le componenti di un servizio L’infrastruttura che Windows mette a dispo-
sizione per l’implementazione e la gestione di
un servizio è composta da 3 elementi: il Servi-
.NET
Fi gu ra 1 La finestra delle proprietà del servizio
40 VBJ N. 65 - Settembre/Ottobre 2005
Di questi 3 componenti quello che il pro-
grammatore andrà ad implementare (tra poco
vedremo come) è il servizio vero e proprio
(SA) in quanto il SCM è un componente già
presente nel sistema operativo e il SCP è an-
ch’esso un’applicazione del pannello di con-
trollo di Windows, pertanto già disponibile (la
troviamo nel Pannello di Controllo | Strumen-
ti di Amministrazione).
Per la scrittura di un servizio, Visual Studio
.NET, ci viene incontro preparando parte del
codice necessario.
VS.NET crea una classe Service1 che eredita
da ServiceBase, classe base di tutti i servizi.
Di questa classe viene fatto l’override di al-
meno 2 metodi: OnStart e OnStop. Il primo,
OnStart, è chiamato dal SCM quando deve
avviare il servizio e dovrà contenere il codice
necessario allo startup delle operazioni che il
servizio deve svolgere, il secondo invece vie-
ne chiamato quando il servizio viene fermato
e deve implementare i meccanismi di chiusu-
ra e rilascio delle risorse.
Inoltre il template di Visual Studio prepa-
ra il metodo Main per l’avvio del servizio da
parte del SCM chiamando il metodo shared
Run della classe ServiceBase:
Dim ServicesToRun() As System.ServiceProcess.ServiceBase
ServicesToRun = New System.ServiceProcess.ServiceBase()
{New Service1}
System.ServiceProcess.ServiceBase.Run(ServicesToRun)
.NET
Fi gu ra 2 La console per la gestione dei servizi
41N. 65 - Settembre/Ottobre 2005 VBJ
Questo è quanto serve per avere un servizio
minimale. Oltre a questi metodi è possibile fare
l’override di: OnPause, OnContinue, OnShu-
tDown, OnCustomCommand, OnPowerEvent
per gestire finemente le risposte del servizio
agli eventi elencati.
Sviluppare il nostro primoServizio Windows
Il servizio che andremo a creare avrà il com-
pito di processare gli ordini ricevuti. Gli or-
dini sono creati da un’ipotetica applicazio-
ne dei nostri clienti ed inviati in una coda
di messaggi presente sui nostri server e ge-
stita da un’altro servizio: Microsoft Messa-
ge Queue (MSMQ). La nostra applicazione,
grazie al modello ad oggetti messo a dispo-
sizione dal .NET framework nel namespa-
ce System.Messaging, ha il compito di pro-
cessare i messaggi arrivati in coda. Iniziamo
quindi a scrivere qualche riga di codice per
implementare il servizio. Grazie ai templa-
te di Visual Studio l’infrastruttra di codice
necessaria la troveremo quasi tutta imple-
mentata. Aperto Visual Studio, dal menù File
scegliamo Progetto. Selezioniamo il proget-
to di tipo Servizio Windows e lo chiamiamo
per esempio VBJService. Rinominiamo il file
Service1.vb in MSMQWatcher.vb.
Per prima cosa possiamo notare che l’Inte-
grated Development Environment (IDE) ha
già creato gli eventi fondamentali per il no-
stro servizio ovvero OnStrat e OnStop.
Nel Listato 1 aggiungiamo agli eventi car-
dine il codice necessario per fare il log ed
utilizzare la piccola libreria (Listato 2) crea-
ta per interfacciarsi con la coda degli ordini.
Ricordiamo sempre che in un servizio l’inte-
razione con l’utente non può avere le solite
modalità come finestre e messaggi.
Ora che il nostro servizio è pronto per
l’uso, si può avviare e fermare tramite
.NET
Li sta to 1 La classe MSMQWatcher
Imports VBJService.MSQMPublic Class MSMQWatcher Private myTimer As New System.Timers.Timer(10000)
Protected Overrides Sub OnStart(ByVal args() As String) ‘Threading.Thread.Sleep(15000) ‘da ultizzare solo in fase di debug AddHandler myTimer.Elapsed, AddressOf myTimer_Elapsed Try EventLog.WriteEntry(String.Format(“Avviato il servizio di ricezione ordini Controllo eseguito ogni {0}
secondi”,myTimer.Interval 1000)) myTimer.Enabled = True Catch ex As Exception EventLog.WriteEntry(String.Format(“Errore durante l’avvio del servizio.{0}, Err.Description”)) End Try End Sub
Protected Overrides Sub OnStop() EventLog.WriteEntry(“Fermato il servizio di ricezione ordini”) End Sub
Private Sub myTimer_Elapsed(ByVal pSender As Object, ByVal pArgs As System.Timers.ElapsedEventArgs) Dim myQueue As New MSMQHelper Dim myOrder As New Order Try myOrder = myQueue.ReceiveOrder() EventLog.WriteEntry(String.Format(“Ricevuto l’ordine {0} del {1}”, myOrder.Id, myOrder.OrderDate)) Catch ex As Exception EventLog.WriteEntry(String.Format(“Errore durante la ricezione degli ordini.{0}”, Err.Description)) End Try End SubEnd Class
42 VBJ N. 65 - Settembre/Ottobre 2005
SCP e, una volta avviato, grazie ad un ti-mer controlla la coda dei messaggi in at-tesa di ordini, inserendo un record nel log degli eventi di Windows ogni volta che vie-ne eseguita una di queste operazione. In-somma cosa volere di più da un servizio? Bene, allora perché non lanciarlo per vede-re se tutto è ok e cominciare a scrivere codi-ce più interessante? Purtroppo, a differenza della maggior parte dei progetti creati in Vi-sual Studio .NET, i progetti di Servizio Win-dows non possono essere eseguiti direttamen-te dall’ambiente di sviluppo premendo F5. È
invece necessario prima installare il servizio e poi lanciarne l’esecuzione.
Per installare Servizi Windows, il framework mette a disposizione l’utilità da riga di co-mando InstallUtil.exe. Prima di usare questo strumento però dobbiamo aggiungere ancora qualcosa al nostro servizio. Andiamo nella fi-nestra di design del servizio. Facciamo clic con il tasto destro e quindi selezioniamo la voce del menu Aggiungi programma d’installazio-
ne. Per impostazione predefinita, al progetto sarà aggiunto un nuovo componente dal nome ProjectInstaller. Questo contiene i program-
.NET
Li sta to 2 La classe MSMQHelper
Imports System.Messaging
Public Class MSMQHelper
Dim myQueue As MessageQueue
Public Sub New() Dim path As String path = String.Format(“{0}\private$\OrderQueue”, My.Computer.Name) ‘se non esiste la coda la creo If MessageQueue.Exists(path) = False Then MessageQueue.Create(path, False) End If ‘L’istanza della coda locale chiamata OrderQueue myQueue = New MessageQueue(path) ‘crea un’istanza del formatter per convertire il body del messaggio in ordine myQueue.Formatter = New XmlMessageFormatter(New Type() {GetType(Order)}) End Sub
Public Function ReceiveOrder() As Order ‘riceve il messaggio Dim myMessage As Message = myQueue.Receive() ‘converte la proprietà Body in un’istanza di Order Dim myOrder As Order = CType(myMessage.Body, Order) Return myOrder End Function
Public Sub SendOrder(ByVal order As Order) SendOrder(order, True) End Sub
Public Sub SendOrder(ByVal order As Order, ByVal recoverable As Boolean) Dim myMessage As New Message myMessage.Recoverable = recoverable ‘perdiamo in efficenza ma facciamo in modo che anche in caso di riavvio
del servizio i messaggi restino in coda myMessage.Body = order myQueue.Send(myMessage) End Sub
End Class
43N. 65 - Settembre/Ottobre 2005 VBJ
mi d’installazione del servizio e del processo
associato al servizio. Facendo doppio clic sul
file appena aggiunto noteremo i due oggetti.
Per quanto riguarda il ProcessInstaller dovre-
mo prestare attenzione alla proprietà Account,
ovvero l’utente con cui sarà avviato il nostro
servizio: nel nostro caso dovrà essere “Local-
Service”; mentre analizzando il componente
ServiceInstaller dovremo modificare le pro-
prietà ServiceName, Description e DisplayNa-
me che saranno i valori visualizzati nel SCP.
Ora abbiamo davvero tutto quello che serve
per installare ed eseguire il servizio. Dopo aver
compilato – per fare prima CTRL+SHIFT+B
– possiamo lanciare il Command Prompt di
Visual Studio. Una volta posizionati nella
cartella bin\debug del progetto che contiene
l’eseguibile fresco di compilazione e lancia-
mo il comando
VS Prompt
InstallUtil vbjservice.exe
Ricordiamoci che la nostra applicazione usa
il servizio MSMQ [1] (in italiano Accodamento
Messaggi). Bisogna quindi accertarsi di averlo
installato sulla nostra macchina. Ora il nostro
servizio è installato. Possiamo avviarlo usan-
do SCP oppure usando il comando
VS Prompt
net start msmqwatcher
Ora che il servizio è attivo possiamo con-
trollare il log degli eventi.
Troveremo un nuovo record che indica l’av-
vio del nostro servizio. Per rendere le cose
più interessanti possiamo riempire la coda
dei messaggi con qualche ordine da far pro-
cessare al nostro servizio.
Per far questo nell’esempio allegato all’ar-
ticolo troverete una semplice applicazione
console che una volta lanciata inserisce 10
messaggi nella coda OrderQueue (Listato 3).
Nel momento in cui il servizio trova i mes-
saggi può cominciare a fare il suo vero la-
voro. Per verificarlo controlliamo ancora il
log degli eventi dove avremo un nuovo re-
cord per ogni ordine processato dal servizio.
Una volta processati tutti gli ordini possia-
.NET
Li sta to 3 Il generatore di ordini
Imports VBJService.MSQM
Module Module1
Sub Main() Dim myQueue As New MSMQHelper() Dim myOrder As New Order() Try ‘ genero 10 ordine in circa 10 secondi per la felicità del direttore :P For index As Integer = 1 To 10 myOrder.Id = DateTime.Now.Millisecond myOrder.OrderDate = DateTime.Now myQueue.SendOrder(myOrder) Console.WriteLine(String.Format(“Inviato l’ordine {0} con data {1}”, myOrder.Id, myOrder.OrderDate)) Threading.Thread.Sleep(10) Next Catch err As Exception Console.WriteLine(String.Format(“Si è verificato l’errore {0} “, err.Message)) End Try Console.WriteLine(“Premere un tasto per continuare”) Console.Read()
End Sub
End Module
44 VBJ N. 65 - Settembre/Ottobre 2005
mo fermare il nostro servizio dal SCP op-
pure usando il comando
VS Prompt
net stop msmqwatcher
DebugIl nostro servizio è talmente semplice da non
richiede un debug; in un caso reale più com-
plesso però potremmo avere bisogno di que-
st’importante feature messa a disposizione dal
nostro ambiente di sviluppo. Per questo è bene
sapere come fare in caso di bisogno; infatti a
differenza delle altre applicazioni, se da Visual
Studio.NET premiamo F5 per mandare in ese-
cuzione il servizio, per il debugging non accade
nulla. Il debug di un servizio è un’operazione
leggermente più complessa. L’idea è di utilizza-
re il debugger dei processi di VS.NET per ag-
ganciarsi al servizio creato, quindi si inserisce
un breakpoint nel punto in cui vogliamo fer-
mare il programma (non nel metodo OnStart)
e poi facciamo partire il servizio come visto in
precedenza. A questo punto dovremo ritornare
nell’IDE e scegliere Processi dal menu Debug.
Sarà visualizzata la finestra di dialogo Proces-
si. Verificheremo che il flag Mostra processi di
sistema sia attivo.
Nella sezione Processi disponibili, faremo
clic sul processo del servizio, e ci aggancere-
mo tramite il pulsante Connetti. A questo pun-
to siamo in modalità di debug e l’esecuzione
si interromperà sul breakpoint settato prima.
Questa tecnica, benché permetta il debug del
servizio, ha alcune limitazioni. Infatti può ca-
pitare che il servizio abbia un bug nel meto-
do OnStart.
Quando andiamo ad agganciare il processo
tramite VS.NET, il metodo OnStart è stato già
eseguito e intercettare gli errori in quel meto-
do risulta quasi impossibile. Qualora fosse ne-
cessario eseguire il debug dell’evento OnStart
è possibile utilizzare una “trucchetto” molto
semplice e veloce. La prima istruzione del me-
todo OnStart dovrà essere
VB.NET
‘da utilizzare solo in fase di debug
‘Max 30 secondi altrimenti il servizio va in timeout
Threading.Thread.Sleep(15000)
Questo ci darà 15 secondi di tempo per ag-
ganciare il processo del servizio al debugger
di Visual Studio. Ricordiamoci di non andare
oltre i 30 secondi altrimenti l’avvio del servi-
zio darà errore di timeout. Così facendo bi-
sogna ricordarsi di commentare l’istruzione
prima del rilascio in produzione.
Una tecnica alternativa che permette di de-
buggare interamente il servizio, compreso il
metodo OnStart, è quello di scrivere un’ap-
plicazione Windows Forms che assume il ruo-
lo di Service Control Manager, cioè avvia il
servizio, lo ferma, ecc…
L’applicazione Windows Forms avrà inter-
faccia utente e utilizzerà il servizio come se
fosse una sua libreria chiamando i metodi
OnStart, OnStop, ecc…in questo modo ogni
eventuale errore sul metodo OnStart può es-
sere intercettato visto che stiamo debuggan-
do una normale applicazione Windows.
ConclusioniCome abbiamo visto, lo sviluppo di un ser-
vizio non è molto diverso da altri tipi appli-
cazione Windows.
Quindi se da un lato la nostra applicazio-
ne può scalare di molto, dall’altra bisogna
prima considerare alcuni punti fondamen-
tali, quali l’iterazione con l’utente e la ge-
stione degli errori.
Una nota dolente può essere l’esecuzione
del debug.
Per ovviare a questo inconveniente è buo-
na regola spostare la logica applicativa in
un componente esterno – noi l’abbiamo fatto
con la libreria che fa da proxy con MSMQ –
e testarlo separatamente tramite strumenti
di Unit Testing (per es. NUnit).
Riferimenti[1] Microsoft TechNet – Accodamento mes-
saggi http://www.microsoft.com/technet/
prodtechnol/windowsserver2003/it/library/
ServerHelp/192eb6e0-e4ac-4dd0-bc44-
dd26a43f5fa8.mspx
.NET
45N. 65 - Settembre/Ottobre 2005 VBJ
Microsoft Web Services Enhancements
(WSE, si pronuncia “uisi”) è una libre-
ria per estendere il motore di Web Ser-
vice di base del Framework .NET. Giunta alla ver-
sione 2.0 Service Pack 3 [3], affiancata nell’ultimo
periodo da una Technology Preview della versione
3.0, rappresenta ormai un prodotto maturo e stabi-
le per la creazione di servizi SOAP in architettura
Service Oriented ([1] e [2]). In questo articolo ve-
dremo come utilizzare WSE2 per creare applicazio-
ni in grado di scambiarsi messaggi SOAP.
Perché WSE?La prima domanda che viene generalmente posta
quando si parla di WSE è: “Perchè WSE?”. In .NET
abbiamo infatti un motore per la creazione di Web
Service, i cosiddetti Web Service ASMX, e per mol-
ti non è chiara la ragione per cui debba esistere una
libreria aggiuntiva che li estende, a volte rappresen-
tandone un’alternativa. WSE nasce con l’obiettivo
di fornire il supporto alle specifiche più moderne
relative a SOAP e ai (Web) Service. Si tratta di una
libreria esterna al motore degli ASMX, in quanto
deve essere in grado di evolvere rapidamente e agil-
mente, senza sottostare alle regole di validazione e
rilascio del codice cui sono soggetti prodotti com-
plessi come Visual Studio .NET
e il .NET Framework. Negli ul-
timi 3 anni abbiamo utilizzato
.NET Framework 1.x e solo ora
sta per vedere la luce il .NET Fra-
mework 2.0. Nel frattempo sono
uscite diverse release di WSE di
cui 2 maggiori (WSE 1.0 e WSE
2.0) e diverse minori (vari Servi-
ce Pack), oltre a un’anteprima di
WSE 3.0. Tutte queste versioni,
rilasciate in meno di due anni,
sono il frutto della rapida e incon-
trollabile crescita di WSA (Web
Services Architecture) e di tutte
le numerose specifiche (WS-Se-
curity, WS-Addressing, WS-Atta-
chments, ecc.) ad essa collegate.
Potremmo descrivere WSE come
lo sforzo, da parte di Microsoft,
di rimanere allineata con l’evo-
luzione tecnologica della specie
(SOAP). Dall’altro lato, proprio
per come è pensato, WSE è da
utilizzare essendo consapevoli
del fatto che ogni 6 mesi o al mas-
simo ogni anno dovremo riscri-
vere parte del nostro codice, per
aggiornarlo a una nuova versio-
ne della libreria. WSE2 e WSE1
infatti non sono compatibili tra
loro, né come codice e funzionali-
tà, né in termini di compatibilità
binaria dei messaggi che viaggia-
no sul cavo. Anche il passaggio
.NET
SOAP Messaging
con WSE
di Paolo Pialorsi
WSE
Vediamo le principali caratteristiche di Microsoft Web Services Enhancements
dal punto di vista del SOAP Messaging.
Paolo Pialorsi è un consulente e autore specializzato nello
sviluppo di Web Service e soluzioni Web con il Framework
.NET di Microsoft. Lavora nell’omonima società Pialorsi
Sistemi S.r.l. e fa parte del gruppo DevLeap. Mantiene un
blog all’indirizzo: http://blogs.devleap.com/paolo/.
46 VBJ N. 65 - Settembre/Ottobre 2005
prevede un’architettura pesantemente basa-
ta sul concetto di messaggio, che essendo un
messaggio SOAP assume la forma di un og-
getto di tipo SoapEnvelope. Una SoapEnve-
lope non è altro che una classe, derivata da
System.Xml.XmlDocument, che fornisce al-
cune funzionalità di uso ricorrente per la ge-
stione di un messaggio SOAP. Per esempio at-
traverso un’istanza di SoapEnvelope possiamo
accedere direttamente al Body e agli Header
del messaggio SOAP. Sempre dalla SoapEn-
velope abbiamo accesso a una serie di meta-
informazioni sul messaggio, relative alla sicu-
rezza, al routing, al messaging, agli eventuali
file allegati al messaggio, ecc.
Ogni volta che un messaggio SOAP viene
gestito da WSE, esso attraversa una pipeline
di filtri, detti SoapFilter, che processano sia
in ingresso (SoapInputFilters) che in uscita
(SoapOutputFilters) le singole SoapEnvelo-
pe (Figura 1). Esistono dei SoapFilter prede-
finiti come quelli per gestire la sicurezza dei
messaggi, il loro instradamento e in caso di
esigenza il logging a fini di diagnostica. Pos-
siamo creare nostri SoapFilter derivando da
classi base molto comode.
Le SoapEnvelope attraversano queste pipe-
line in quanto il motore di WSE prevede il
concetto di SoapPort, della quale esistono di-
verse implementazioni che vedremo nel cor-
so dell’articolo. Ad ogni SoapPort sono asso-
ciate una lista (Pipeline) di filtri e un cana-
le (Channel). L’architettura di messagging di
da WSE2 a WSE3, quando avverrà, non è ga-
rantito che sia completamente indolore.
Occupandoci della versione attualmente rila-
sciata, WSE2 supporta le seguenti specifiche:
• SOAP 1.1
• WSDL
• WS-Security
• WS-SecurityPolicy
• WS-SecureConversation
• WS-Trust
• WS-Referral
• WS-Addressing
• WS-Policy
• DIME
• WS-Attachments
La preview di WSE3, ad oggi e per comple-
tezza, sostituisce il supporto agli allegati nei
messaggi SOAP, che lo scorso anno erano ge-
stiti con WS-Attachments e DIME, con la com-
patibilità con MTOM (Message Transmission
Optimization Mechanism [5]), oltre a fornire
la possibilità di essere utilizzato con .NET 2.0.
Probabilmente WSE4 non vedrà mai la luce,
infatti nel 2006 dovrebbe essere rilasciato In-
digo [7] che andrà a sostituirsi a tutte le at-
tuali tecnologie di comunicazione e che do-
vrebbe (il condizionale è d’obbligo) essere in
grado di “parlare” con WSE3.
SoapEnvelope - il cuore di WSEPer utilizzare WSE dobbiamo innanzitutto
scaricarlo da MSDN [3] - consiglio l’installa-
zione di tipo Visual Studio .NET Developer,
per avere un addin di configurazione di WSE a
disposizione nell’IDE di Visual Studio .NET -
e referenziarlo nei nostri progetti, cercando la
class library Microsoft.Web.Services2.dll. WSE
Fi gu ra 1 Flusso di un messaggio SOAP attraverso
una Pipeline di WSE
.NET
Microsoft WSE è una libre-
ria per estendere il motore
di Web Service di base del
Framework .NET
47N. 65 - Settembre/Ottobre 2005 VBJ
WSE è pensata per essere utilizzata in due
differenti modalità:
• affiancata al motore ASMX per estender-
lo, sfruttando una SoapExtension [6] lato
server e una specializzazione di SoapHt-
tpClientProtocol lato client;
• come alternativa ad ASMX, utilizzando un
motore di comunicazione ad hoc.
Il fatto che WSE2 esponga le sue funzionalità
sia come aggiunta al motore degli ASMX, che
come sistema alternativo ad essi, ci consente di
creare server e client di servizi SOAP senza bi-
sogno di un server IIS e/o ASP.NET. Da questo
momento in poi ci concentreremo sullo scambio
di messaggi SOAP, per utilizzare WSE2 come in-
frastruttura di comunicazione tra processi, ser-
vizi e sistemi senza utilizzare IIS e ASP.NET.
Questo ci consente di avere un approccio com-
pletamente orientato a SOA.
Soap MessagingIl motore di comunicazione di WSE2 si basa
sull’uso di classi derivate da SoapPort (Figu-
ra 2). Nello specifico esistono due modalità
di comunicazione, che corrispondono a due
differenti paradigmi di dialogo:
• SoapReceiver/SoapSender: prevede un si-
stema di scambio paritetico di messaggi
SOAP. Si utilizza quando si devono creare
sistemi di comunicazione monodirezionale,
oppure peer-to-peer ovvero sistemi di co-
municazione asincrona, dove il client (che
di solito viene chiamato “endpoint” e non
più client) può richiamare l’altro endpoint
(quello che tradizionalmente sarebbe il ser-
ver). In questo modo si possono creare dia-
loghi asincroni.
• SoapService/SoapClient: pensato per un
approccio più classico, dove esiste un ser-
ver che espone dei servizi, utilizzati dai
client, che si limitano ad invocarli e atten-
derne il risultato.
Aspetto chiave di questa architettura è il fat-
to che i protocolli di trasporto dei messaggi
SOAP sono intercambiabili ed estendibili, ri-
spetto all’architettura del singolo servizio.
Esistono diverse implementazioni per vari
protocolli di uso comune. Già WSE2 offre il
supporto per HTTP, TCP e un protocollo IN-
PROCess per le comunicazione all’interno di
uno stesso AppDomain. Esistono inoltre sulla
rete implementazioni indipendenti di MSMQ,
UDP, SMTP, ecc. Quando sviluppiamo i servi-
zi possiamo prescindere dal protocollo di tra-
sporto che andremo a utilizzare per esporli, con
un approccio pienamento SOA. Solo nel mo-
mento in cui vorremo esporre i servizi dovre-
mo preoccuparci di definire un punto di acces-
so (EndpointReference) e configurarlo affiché
utilizzi un determinato protocollo.
SoapSenderVediamo un primo esempio di utilizzo di Soa-
pReceiver e SoapSender, sfruttando il proto-
collo TCP. Immaginiamo di voler inviare tra-
mite SOAP Messaging un oggetto che rappre-
senta un ordine. Dobbiamo innanzitutto crea-
re una SoapEnvelope che descriva il messag-
gio da inviare:
C#
// Nella variabile order immagino di avere i dati di un
ordine
Order order = new Order();
order.IdOrder = 10;
order.Description = “Ordine dimostrativo 10”;
SoapEnvelope envelope = new SoapEnvelope();
.NET
Fi gu ra 2 Schema funzionale di una SoapPort in
WSE
48 VBJ N. 65 - Settembre/Ottobre 2005
envelope.CreateBody();
envelope.SetBodyObject(order, “http://schemas.devleap.com/
order”);
Con queste prime righe stiamo creando un oggetto DOM XML - ricordiamoci che SoapEn-velope deriva da XmlDocument - che avrà la struttura di una SOAP Evenlope e conterrà al suo interno l’oggetto order, serializzato con XmlSerializer, che è lo stesso motore di seria-lizzazione che utilizzano anche gli ASMX. Po-tremmo in alternativa costruire il contenuto del messaggio SOAP manualmente, creando i singoli nodi XML all’interno del Body del messaggio SOAP.
Come si vede abbiamo quindi la massima versatilità rispetto alla gestione del contenu-to del messaggio SOAP, potendo sfruttare al massimo il SOAP messaging. Per verificare cosa sta succedendo dietro le quinte, imma-ginando che il nostro ordine sia definito nel modo seguente:
C#
public class Order
{
public Int32 IdOrder;
public String Description;
}
possiamo provare a salvare la SoapEnvelope su disco e vederne il contenuto XML:
C#
envelope.Save(“order.soap.xml”);
XML (SOAP)
<?xml version=”1.0” encoding=”utf-8”?>
<soap:Envelope xmlns:soap=”http://schemas.xmlsoap.org/
soap/envelope/”>
<soap:Body>
<Order xmlns:xsd=”http://www.w3.org/2001/XMLSchema”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xmlns=”http://schemas.devleap.com/order”>
<IdOrder>10</IdOrder>
<Description>Ordine dimostrativo 10</Description>
</Order>
</soap:Body>
</soap:Envelope>
Si può notare la struttura di un classico mes-saggio SOAP, costituito dalla Envelope, dal Body e dal contenuto (nel nostro caso l’ordi-ne). A questo punto possiamo creare un og-getto SoapSender, per inviare il messaggio ad un altro EndpointReference (cioè al destina-tario del messaggio):
C#
envelope.Context.Addressing.Action = new Action(“urn:
sendOrder”);
EndpointReference ep = new EndpointReference(
new Uri(“soap.tcp://localhost:34000/DemoReceiver”));
SoapSender sender = new SoapSender(ep);
sender.Send(envelope);
Si vede che dobbiamo per prima cosa crea-re un EndpointReference che rappresenterà il riferimento al servizio da raggiungere, com-presi il protocollo di comunicazione (soap.tcp in questo caso) e la porta di comunicazione ri-servata a questo scambio di messaggi.
Inoltre è di fondamentale importanza l’in-dicazione della Action SOAP del messaggio che stiamo inviando, per consentire al desti-natario di capire cosa gli stiamo chiedendo o dicendo.
La Action, esattamente come tutte le altre meta-informazioni di sicurezza, routing, ecc. si configura attraverso una proprietà specia-le della SoapEnvelope, di nome Context, che rappresenta un riferimento al contesto della singola richiesta o risposta SOAP.
È all’interno di Context che troviamo pro-prietà come Security, Addressing, Attachmen-ts, ecc. che ci permettono di configurare ap-punto il contesto di dialogo SOAP.
SoapReceiverPer ricevere il messaggio appena creato ed
inviato dal SoapSender, dobbiamo dichiara-re una classe derivata da SoapReceiver, della quale dovremo ridefinire il metodo Receive:
.NET
49N. 65 - Settembre/Ottobre 2005 VBJ
C#
public class DemoReceiver: SoapReceiver
{
protected override void Receive(SoapEnvelope envelope)
{
// Il SoapEnvelope è anche un XMlDocument
// quindi so come cercare e sfogliare
// i nodi al suo interno
envelope.Save(Console.Out);
}
}
In questo esempio ci limitiamo a salvare sul-
la finestra Console del receiver il messaggio
ricevuto dal sender. In condizioni normali do-
vremmo valutare la Action (envelope.Context.
Addressing.Action) e decidere il da farsi. Infi-
ne dobbiamo registrare, lato server, il fatto che
vogliamo stare in ascolto di messaggi SOAP
destinati al nostro SoapReceiver particolare:
C#
public class ReceiverHostCode
{
static void Main()
{
EndpointReference ep = new EndpointReference(
new Uri(“soap.tcp://localhost:34000/DemoReceiver/ “));
SoapReceivers.Add(ep, typeof(DemoReceiver));
Console.ReadLine();
}
}
Come si vede ci appoggiamo alla classe
SoapReceivers che esponde un metodo sta-
tico Add, che ci consente di aggiungere un
Receiver su un determinato EndpointRefe-
rence. Da notare che con un singolo Recei-
ver potremmo stare in ascolto su diversi En-
dpointReference, quindi anche su diversi pro-
tocolli e indirizzi.
Dal momento che il motore di WSE rimane
in ascolto su un thread diverso da quello prin-
cipale della nostra applicazione, dobbiamo so-
spendere il progamma host aspettando la pres-
sione del tasto INVIO a Console. In condizioni
di regime ci converrà realizzare un’applicazio-
ne Windows Forms o ancor meglio un servizio
del sistema operativo, che rimangano in esecu-
zione e quindi in ascolto per i nostri messaggi
SOAP. Il messaggio stampato a Console conter-
rà qualche informazione in più rispetto a quel-
lo salvato in precedenza, principalmente per il
fatto che il messaggio questa volta sarà passato
attraverso il Channel della SoapPort di uscita
e poi di ingresso, subendo quindi l’azione dei
vari SoapFilter configurati nelle rispettive Pi-
peline (Output prima e Input poi), che aggiun-
gono, verificano e tolgono informazioni associa-
te a diversi namespace XML. Si tratta proprio
dei namespace XML che troviamo aggiunti al
messaggio finale.
Rispondere ai messaggiSe volessimo a questo punto rispondere al
sender, dovremmo avere anche dal suo lato un
oggetto derivato da SoapReceiver e posto in
ascolto su un determinato EndpointReferen-
ce. Il sender potrebbe per esempio dire:
C#
envelope.Context.Addressing.ReplyTo = new ReplyTo(new
Uri(“soap.tcp://localhost:35000/Sender”));
per comunicare al receiver l’indirizzo al qua-
le inviare eventuali risposte (ReplyTo).
Il receiver dal canto suo potrebbe risponde-
re chiedendo alla SoapEnvelope di generare
la risposta per il messaggio appena ricevuto,
nel modo seguente:
C#
SoapEnvelope response = new SoapEnvelope();
response.SetBodyObject(orderResponse, “http://
schemas.devleap.com/Response”);
envelope.Context.Addressing.SetResponseHeaders(response.
Context.Addressing);
In pratica dobbiamo creare una nuova Soa-
pEnvelope, inserire al suo interno la risposta
(orderResponse nel nostro esempio) e chiede-
re alla richiesta di configurare l’indirizzamen-
to SOAP della risposta. L’oggetto SoapEnvelo-
pe ricevuto come richiesta compilerà i cam-
pi corretti della risposta, per consentire al de-
.NET
50 VBJ N. 65 - Settembre/Ottobre 2005
stinatario di capire che il messaggio inviato-
gli costituisce una risposta per il precedente
messaggio. Non ci resterà quindi altro da fare
che inviare la risposta utilizzando una classe
SoapSender, come abbiamo già visto.
L’endpoint che ha originato il dialogo potrà
riconoscere la risposta in base al fatto che
tramite WS-Addressing i messaggi SOAP
possono riportare l’indicazione di un Messa-
geID, che rappresenta univocamente i singo-
li messaggi.
Inoltre esiste una proprietà, sempre di WS-
Addressing, di nome RelatesTo che mette in
relazione tra loro i messaggi.
SoapClient e SoapServiceSe la nostra esigenza è quella di realizza-
re un paradigma di dialogo di tipo richiesta/
risposta, possiamo utilizzare direttamente le
classi SoapClient e SoapService, che altro
non sono che specializzazioni di SoapSender
e SoapReceiver.
In particolare SoapService rappresenta
l’equivalente di un WebService ASMX in WSE
e un SoapClient è ciò che si ottiene costruen-
do una sorta di Web Reference WSE verso un
servizio, anche non necessariamente esposto
con WSE. Partiamo questa volta dall’imple-
mentazione del servizio. Dobbiamo definire
una classe che derivi dalla classe base Soap-
Service e che presenti l’attributo .NET Soap-
Service al posto del classico WebService degli
ASMX. Quindi possiamo decorare i singoli me-
todi del servizio con l’attributo SoapMethod
invece di WebMethod. Ecco un esempio:
C#
[SoapService(“http://schemas.devleap.com/DemoService/”)]
public class DemoService: SoapService
{
[SoapMethod(“urn:SendOrder”)]
public String SendOrder(Order order)
{
return(String.Format(“Ordine {0} ricevuto!”,
order.IdOrder));
}
}
Si noti che l’attributo SoapService riporta il
namespace XML del SOAP Service che stiamo
definendo, mentre l’attributo SoapMethod in-
dica il nome della Action dell’operazione che
descrive.
Mettendo un SoapReceiver in ascolto su un
determinato EndpointReference e protocollo,
per questo servizio, siamo già pronti a riceve-
re richieste a lui destinate.
C#
EndpointReference ep = new EndpointReference(
new Uri(“soap.tcp://localhost:34000/DemoService”));
SoapReceivers.Add(ep, typeof(DemoService));
Qualora volessimo avere un’unica istanza di
servizio in ascolto per tutte le richieste, per
esempio per condividere informazioni di stato,
potremmo assegnare alla classe SoapReceivers
l’EndpointReference unitamente ad una parti-
colare istanza della classe SoapService, invece
che fornire solo il tipo (typeof) generico.
C#
EndpointReference ep = new EndpointReference(
new Uri(“soap.tcp://localhost:34000/DemoService”));
SoapReceivers.Add(ep, new DemoService());
Se avessimo sviluppato un WebService con
dei WebMethod, a questo punto potremmo
chiedere a Visual Studio .NET di creare una
Web Reference verso la URL del servizio. Per
altro Visual Studio .NET, quando creiamo del-
le Web Reference, non fa altro che eseguire lo
stesso codice che potremmo eseguire autono-
mamente chiamando dal prompt dei comandi il
tool WSDL.EXE. Ecco che WSE2 fornisce qual-
cosa di molto simile: WSEWSDL2.EXE. Possia-
mo invocarlo dandogli come argomento la URI
di un servizio, per ottenere in cambio il codice
di un SoapClient pronto da istanziare.
Command Prompt
C:\Program Files\Microsoft WSE\v2.0\Tools\Wsdl\WseWsdl2.exe
URI-Servizio file.cs
.NET
51N. 65 - Settembre/Ottobre 2005 VBJ
Nel nostro caso avremo:
Command Prompt
WseWsdl2.exe soap.tcp://localhost:34000/DemoService
DemoServiceClient.cs
Ed ecco che verrà auto-generato per noi un file di codice che descriverà la classe Order e il SoapClient del servizio.
Per brevità riporto solo le parti salienti del codice e rimando agli allegati all’articolo per i dettagli:
C#
[SoapService(“http://schemas.devleap.com/DemoService/”)]
public class DemoService : SoapClient
{
public DemoService() : base( new Uri(“soap.tcp:
//localhost:34000/DemoService”) )
{
}
[SoapMethod(“urn:SendOrder”)]
public System.String SendOder( Order request )
{
return (System.String)base.SendRequestResponse(“SendOrder”,
request).GetBodyObject( typeof(System.String), SoapService
Attribute.TargetNamespace);
}
// omissis...
}
Il codice contiene la definizione di una classe di nome DemoService, che deriva da SoapClient ed espone un metodo Sen-dOrder. Si noti che sia la classe che il me-todo sono decorati anche lato client rispetti-vamente dagli attributi SoapService e Soap-Method.
Non entro nel merito dell’implementazione del metodo SendOrder, ma sottolineo soltan-to il fatto che WSEWSDL2.EXE ha generato per noi anche i metodi BeginSendOrder ed EndSendOrder, per consentirci di invocare il SoapService in modo asincrono, lato client [8]. Una nostra applicazione client, che vo-glia utilizzare il SoapService, dovrà limitar-si ad includere o referenziare il codice ap-
pena generato e poi utilizzare la classe De-moService creata:
C#
DemoService svc = new DemoService();
Order order = new Order();
order.IdOrder = 10;
order.Description = “Ordine 10”;
Console.WriteLine(svc.SendOrder(order));
Console.ReadLine();
ConclusioniSpero con questi esempi di aver stimolato la
vostra fantasia e di avervi fatto venire la vo-glia di provare a creare qualche applicazione in grado di comunicare tramite SOAP con al-tri servizi o sistemi.
È doveroso sottolineare che, dal punto di vi-sta della interoperabilità tra piattaforme e si-stemi, ad oggi il SOAP Messaging di WSE2 è utilizzabile solo da WSE2 stesso.
Se vogliamo utilizzare WSE per rivolgerci ad altre piattaforme dobbiamo pensarlo solo come estensione di ASP.NET e dei Web Servi-ce ASMX. Ciò nonostante il SOAP Messaging risulta molto comodo in diverse situazioni in cui si vogliono mettere in comunicazione tra loro applicazioni .NET sfruttando le potenzia-lità di SOAP.
Bibliografia[1] P. Pialorsi – “Service Oriented Architecture”,
Visual Basic Journal n° 61[2] P. Pialorsi – “SOA e il .NET Framework”,
Visual Basic Journal n° 62
Riferimenti[3] http://msdn.microsoft.com/webservices/[4] http://www.devleap.com/wse2/ [5] http://www.w3.org/TR/2005/REC-soap12-
mtom-20050125/[6] http://www.devleap.com/SchedaArticolo.a
spx?IdArticolo=10450[7] http://winfx.msdn.microsoft.com/[8] http://www.devleap.com/SchedaArticolo.a
spx?IdArticolo=10610
.NET
.NET TO OLS
52 VBJ N. 65 - Settembre/Ottobre 2005
DTSBackup 2000di Angelo Ossola
Probabile, anche se poco auspicabile, scenario
aziendale: un sistema basato su Microsoft SQL 2000
esegue trasferimenti ed elaborazioni di dati attra-
verso dei DTS, fondamentali per la realtà produtti-
va, tra piattaforme eterogenee (ad esempio da e ver-
so AS400), magari schedulati automaticamente per
girare in fase notturna. Un “bel” giorno: crash del
server! Si rende necessario rimettere in piedi tut-
to il sistema. Ovviamente, lo spero, nessuno è così
scellerato da non avere backup dei dati periodici e
delle applicazioni fondamentali al buon funziona-
mento dell’ambiente che deve gestire. I backup, se
fatti a regola d’arte, consentono di ripristinare tutti i
database in modo completo e rigoroso ma (c’è sem-
pre un ma …) c’è un problema: i DTS? Non ci sono
nei backup! Sfido chiunque a riscriverli in un mo-
mento del genere senza commettere qualche errore
o dimenticanza. La soluzione veramente facile ed
immediata ce la propone DTSBackup, un tool tanto
semplice da usare quanto efficace rispetto al proble-
ma appena esposto. Av-
viando il programma ed
osservando l’ambiente
di lavoro possiamo im-
mediatamente intuire la
logica davvero “easy” con
la quale è stata svilup-
pata l’applicazione; pre-
mendo il pulsante per la
selezione della sorgente
dei dati ci viene presen-
tata una finestra di dialo-
go che risulterà molto fa-
miliare a tutti gli avvezzi
di Microsoft SQL 2000 e
che permette di selezio-
nare il server (o la named
instance) SQL.
Una volta impostato il server sorgente viene espo-
sto l’elenco di tutti i DTS presenti nella basi di dati
dal quale è possibile selezionare quelli per i quali
si vuole eseguire il backup. A questo punto è ne-
cessario impostare la destinazione del backup ed è
qui che la versatilità del programma balza agli oc-
chi dell’utente: possiamo impostare un altro server
nel quale salvare i DTS (a questo punto possiamo
usare questo tool anche per copiare DTS tra un ser-
ver ed un altro), salvarlo in un file con estensione
.dts, in uno Structured Storage File oppure in un
Meta Data Services Packages. Avviando il trasfe-
rimento dei DTS viene proposto un report di fun-
zionamento in puro stile SQL 2000 nel quale viene
proposto l’esito di ogni operazione eseguita nel job
appena avviato.
Vi sono, inoltre, interessanti opzioni che rendono
questo strumento ancor più elastico e flessibile, tra
cui la possibilità di inserire la password da usare
con package criptati, esportare la lista dei DTS in
formato txt e, ancor più utile in determinate circo-
stanze, la possibilità di “pilotare” il software anche
da riga di comando. Dalla
linea di comando è pos-
sibile impostare i server
sorgente e destinazione,
la modalità di connessio-
ne ai server, username e
password per le varie
connessioni ed altro an-
cora. Da sottolineare, in-
fine, anche la possibili-
tà di criptare anche nel-
la linea di comando sia
lo username che la pas-
sword. Per quanto con-
cerne, invece, l’operazio-
ne di restore essa avviene
in modo del tutto analo-
go, seppur a ruoli ovvia-
.NET TOOLS
53N. 65 - Settembre/Ottobre 2005 VBJ
mente invertiti, rispetto a quella di backup. Tiran-
do le somme siamo in presenza di un tool, tra l’al-
tro frequentemente aggiornato dai suoi creatori, che
sopperisce ad una mancanza dell’enterprise mana-
ger di SQL 2000 in modo semplice ed efficace.
CodeColorizerdi Angelo Ossola
CodeColorizer, ovvero quando la semplicità è
tutto; vi è mai capitato di dover
realizzare una pagina HTML (da
distribuire in internet o nel vo-
stro gruppo di lavoro) che pre-
senti codice sorgente con lo stes-
so appeal grafico che siete abi-
tuati a vedere nell’ambiente di
sviluppo che usate per realizza-
re le vostre applicazioni? Se si,
e se, magari, avete anche perso
diverse decine di minuti per im-
paginare il vostro codice con le
tabulazioni ed i colori adeguati
a far apparire il tutto il più pos-
sibile simile alla struttura pre-
sentata ad esempio da Visual
Studio .NET, allora CodeColo-
rizer è il tool che avreste potu-
to usare per risparmiare tempo e per avere un
risultato davvero congruente con la formatta-
zione del codice usata negli ambienti di svilup-
po. Questo tool, free, e scaricabile velocemente
dal sito di riferimento (sono solo circa 50KB) si
presenta con soli due file: l’eseguibile ed una
dll a corredo.
Lanciando il programma siamo accolti in un
ambiente decisamente user-friendly, come si
può vedere dall’immagine, che è essenzialmen-
te composto da quattro pulsanti e da un com-
boBox. Nell’elenco presente è possibile sceglie-
re il linguaggio del file sorgente che andremo
a caricare e per il quale vogliamo sviluppare la
pagina HTML; i linguaggi che vengono gestiti
dal programma sono diversi: C#, VB.NET, VB
Script, Java Script, C++, SQL, Cascading Stye
Sheet, Cobol, Algol e i linguaggi di markup qua-
li ad esempio HTML ed e vari dialetti derivati
dall’XML (XSL, VXML, ecc.).
Una volta scelto il linguaggio con il quale vo-
gliamo operare, passiamo a caricare il file sor-
gente che ci interessa; questo può essere fatto
attraverso il pulsante relativo oppure con un
comodissimo drag&drop in puro stile Windows.
A questo punto il documento viene presentato
nell’area di testo più in alto. Per “colorizzare”
il nostro sorgente è sufficiente cliccare l’omoni-
mo pulsante; il relativo risultato viene presen-
tato, in formato HTML nell’area di testo più in
ProdottoDTSBackup 2000 UI
Url di riferimento http://www.sqldts.com/dtsbackup/
Sta to Release1.1.6
Semplicità d’uso �����L’interfaccia in puro stile Microsoft SQL 2000 permette ai vete-rani di questo ambiente di essere subito a proprio agio con que-sta applicazione.
Utilità �����È un tool che sopperisce ad una insufficienza dell’enterprise ma-nager in modo davvero apprezzabile.
Qualità prodotto ����� Software che implementa ogni sfaccettatura della funzionalità per cui è stato progettato con elevata stabilità ed efficienza.
Qualità documentazione �����Magari l’help in linea lascerà un po’ delusi (anche se molto conci-so illustra tutte le funzionalità del programma) ma sul sito di rife-rimento si possono trovare tutte le informazioni necessarie.
.NET TOOLS
54 VBJ N. 65 - Settembre/Ottobre 2005
basso. La presenza di queste due aree di testo è veramente comoda per apportare modifiche in corsa al codice sorgente per poi vederle imme-diatamente applicate al codice sviluppato dal programma (sempre dopo essere passati per il tasto “colorize”).
Un’altra comodità offerta dal software è la pos-sibilità di visualizzare un’anteprima del risulta-to ottenuto all’interno di una finestra del nostro browser predefinito. Volendo salvare, infine, il nostro lavoro abbiamo la possibilità di farlo sia in formato HTML che in formato RTF.
Un unico appunto che potrebbe essere mosso all’autore del tool è l’impossibilità di modifica-re l’output prodotto per poter, ad esempio, por-tare piccoli adattamenti al codice ottenuto sen-za doversi affidare ad altri strumenti. Se la se-conda area di testo diventasse un editor HTML, anche semplice, il lavoro sarebbe ulteriormen-te semplificato.
E verrebbe in grande aiuto qualora si avesse la necessità di inserire in una pagina di un sito del codice che possa, però, mantenere la format-tazione originale.
Sul sito del programma, oltre ad altri tool mol-to interessanti per gli sviluppatori, è possibile anche registrarsi ad una mailing list che per-mette di restare sempre informati su eventua-li aggiornamenti.
SharpWebMaildi Raffaele Di Natale
Nel panorama delle WebMail application, ricco nelle soluzioni e nelle tecnologie adottate, Shar-
pWebMail si distingue principalmente per la sem-plicità dell’installazione e della configurazione. Il progetto che sta alle sue spalle è sicuramente de-gno di nota, poiché l’autore ha utilizzato tre mo-duli software, sempre open source, tutti leader nel proprio ambito. Un’interfaccia senza fronzoli e funzionalità base efficienti consentono un fa-cile adattamento alle più comuni configurazioni dei servizi di posta elettronica. Le pagine .ASPX sviluppate in C# richiamano cinque moduli, dei quali i primi tre sono legati direttamente all’ap-plicazione ed i restanti sono di supporto:
� SharpWebMail.dll, il modulo principale;� SharpMimeTools.dll, modulo in versione beta
per il parsing dei messaggi MIME;� SharpWebMail.resources.dll, per le risorse mul-
tilingua;� Log4tNet.dll, modulo per i servizi di login;� OpenSmtp.dll, modulo per i servizi SMTP;� FredCK.FCKeditorV2.dll, modulo dell’html edi-
tor più conosciuto.
L’applicazione si basa sul .Net Framework 1.1 di Microsoft e su Mono 1.0, ma all’interno della directory bin sono presenti i binari per il .Net Framework 2.0 e per e Mono 2.0. Pertanto que-sta web application può girare indistintamente sia su Windows sia sugli altri sistemi suppor-tati da Mono. Per quanto concerne il web può essere utilizzato con gli IIS (Internet Informa-
tion Services) oppure con Apache, ovviamente insieme a Mono se non si tratta di un sistema Windows.
È necessario predisporre l’indirizzo di almeno un server POP3 (o IMAP) e di un server SMTP. SharpWebMail è stato testato con i browser internet più diffusi al momento e vale a dire Internet Explorer 6.0 e FireFox 1.0. L’applica-zione descritta in quest’articolo è stata instal-lata su Windows XP SP2 con gli IIS. SharpWeb-Mail, in versione 0.11 beta, può essere scarica-to gratuitamente: il pacchetto comprende sia i file sorgente che i binari. Dopo aver scaricato il
ProdottoCarlosAg.CodeColorizer
Url di riferimento http://www.carlosag.net/
Sta to Releasev1.0.0.1
Semplicità d’uso �����L’uso di questo tool risulta già dal primo approccio decisamen-te banale.
Utilità �����Permette di realizzare un’operazione, probabilmente tediosa, in un attimo.
Qualità prodotto ����� Realizza un’unica funzionalità ma in modo egregio: massimo risul-tato con il minimo sforzo.
Qualità documentazione �����Considerato l’evidente facilità d’uso non si può certo chiede-re di più.
.NET TOOLS
55N. 65 - Settembre/Ottobre 2005 VBJ
/>
</servers>
<servers>
<server
name=”Default SMTP Server”
regexp=”*”
protocol=”smtp”
host=”smtp.dominio.it”
port=”25”
/>
</servers>
Come si evince dai tag è possibile in-
serire anche più di un server SMTP e
POP3/IMAP. I commenti presenti all’in-
terno di questo file aiutano a capire il
significato di questi ed altri campi del-
le varie sezioni. Non resta che salvare il
file modificato e lanciare l’applicazione:
l’indirizzo http://localhost/webmail/ pun-
terà direttamente alla pagina login.aspx che mo-
strerà il form di login.
Il titolo della finestra della pagina web può esse-
re personalizzato tramite il campo title della sezio-
ne general cosi come il titolo del form di login me-
diante title della sezione login e la lingua di default
mediante il campo default_lang.
Relativamente al campo username le possibili-
tà sono tre:
� Richiedere l’indirizzo completo, per esempio
[email protected], fissando mode=‘1’;
� Richiedere semplicemente il nome, per esem-
pio raffaele, con mode=‘2’;
� Accodare al nome inserito un’ulteriore stringa
standard per tutti gli utenti, mediante il campo
append. Per esempio se append=“@dominio.it”
e lo username è raffaele allora la stringa finale
sarà [email protected]. In questo caso sarà
però necessario definire il campo mode=‘3’.
Un’applicazione di posta elettronica che si ri-
spetti non può far mancare la rubrica ai propri
utenti: gli indirizzi potrebbero essere collocati in
un file .MDB di Access o più semplicemente ge-
stiti da un servizio LDAP/Active Directory.
Supponiamo di aver predisposto un database
denominato rubrica.mdb, all’interno del quale
file ZIP ed averne estratto il contenuto, si può
procedere all’installazione. Come accennato in
precedenza questa fase è semplicissima ed è
descritta all’interno del file readme.txt presen-
te nella directory doc. Il contenuto della cartel-
la asp.net deve essere spostato all’interno della
cartella di destinazione del server web, configu-
rando in esso la directory Webmail.
A questo punto non resta che personalizzare
l’applicazione in base ai servizi che ci sono mes-
si a disposizione, alla modalità d’accesso pre-
ferita e alla tipologia della rubrica prescelta.
SharpWebMail è una web application ASP.NET
e pertanto la configurazione avviene mediante
il consueto file web.config che si trova sempre
all’interno della cartella WebMail. Per una con-
figurazione minima basta intervenire sulle due
sezioni principali read e send, che si riferisco-
no rispettivamente alle impostazioni dei server
della posta in entrata e in uscita. Di seguito si
propone un esempio per read e per send, da
adattare alle proprie esigenze:
<servers>
<server
name=”Default POP3 Server”
regexp=”*”
protocol=”pop3”
host=”pop3.dominio.it”
port=”110”
.NET TOOLS
56 VBJ N. 65 - Settembre/Ottobre 2005
abbiamo definito una tabella denominata Ta-
ble1 formata da due colonne nome ed email ri-spettivamente.
Salviamo il file in C:\ e inseriamo una sezione <addressbook> nel file web.config. A seconda della tipologia della rubrica prescelta potrebbe essere necessario impostare la corrispondente sorgente dati ODBC.
<addressbook
Name=”MS Access Address Book”
Type=”odbc”
ConnectionString=”Driver={Microsoft Access Driver(*.mdb)};DBQ=C:
\rubrica.mdb”
SearchString=”SELECT nome, email FROM Table1”
NameColumn=”nome”
EmailColumn=”email”
PageSize=”10”
SearchStringRealName=”SELECT nome, email FROM Tabella1 WHERE
email=’$USERNAME$’”
/>
È possibile inserire anche più di una rubrica.L’applicazione può filtrare i messaggi ricevuti,
eliminando dal contenuto degli stessi sia codi-ce html superfluo sia script potenzialmente pe-ricolosi. Per far questo poniamo il campo sani-
tizer_mode= ‘1’ nella sezione message. Questa funzionalità non è ancora del tutto affidabile. Da notare infine la sezione authentication che con-sente di scegliere tra quattro modalità differen-ti per il login: tramite il form standard dell’ap-plicazione, il form di Windows, quello passport oppure non definirne alcuno.
SharpWebMail si presenta con un’interfaccia ormai standard per questo tipo di applicazioni. Sulla parte alta sono presenti i pulsanti di navi-gazione, di logout e d’aggiornamento; a sinistra si trovano i comandi principali e sulla parte de-stra il form relativo al messaggio in uscita.
Nella parte bassa è visibile la finestra della ru-brica. Intervenendo sul file Sharpwebmail.css è
.NET TOOLS
57N. 65 - Settembre/Ottobre 2005 VBJ
possibile definire stili differenti per l’applicazio-
ne. Da quanto emerso appare evidente che si trat-
ta di un programma semplice e ben congegnato.
Un aspetto migliorabile, anche se secondario, è il
numero delle funzionalità a disposizione.
ZanebugLo Unit Testing visuale
di Fabio Perrone
Per “Unit Testing” s’intende l’effettuazione di
verifiche funzionali e d’affidabilità riguardan-
ti il comportamento di determinati componenti
rispetto al soddisfacimento di requisiti defini-
ti in fase di progettazione. Nello sviluppo di un
progetto software, lo Unit Testing sta assumen-
do un ruolo sempre più preponderante, senza
dubbio anche perché rappresenta una “pietra
miliare” dell’Extreme Programming o XP. Gli
unit test sono scritti all’interno del codice che
deve essere testato.
Come si può quindi dedurre, la scrittura di test
per progetti particolarmente complessi può esse-
re un’operazione particolarmente lunga e labo-
riosa. Per semplificare la creazione e la gestio-
ne dei test, esistono i cosiddetti “Unit Testing
framework”, che aiutano a scrivere codice, ad
effettuare il debug del codice e ad integrare nel
miglior modo possibile i test all’interno del co-
dice. Uno dei migliori “Unit Testing framework”
per Microsoft .NET è senza dubbio NUnit [1],
che permette di segnare il codice con attribu-
ti per indicare quali metodi devono essere ese-
guiti quando un test ha successo.
Per chi avesse già utilizzato altri framework,
la seguente nomenclatura potrebbe essere fami-
liare, anche se è bene avere sempre chiare in
mente le definizioni di Test, che è un metodo
che esegue delle convalide interne e può avere
esito positivo o negativo; TestFixture, che è una
classe che contiene più metodi di test; TestAs-
.NET TOOLS
58 VBJ N. 65 - Settembre/Ottobre 2005
sembly, che è una collezione di TestFixture in
un assembly; TestSuite, che è una collezione di
TestAssembly costruita dinamicamente da Za-
nebug per ogni assembly che viene caricato al-
l’interno del programma. Prima di analizzare le
notevoli possibilità offerte dalla parte grafica di
Zanebug, vediamo come scrivere test all’inter-
no del codice che possano poi essere elaborati
ed analizzati dal nostro software.
Il primo passo consiste nel mettere un riferi-
mento alla dll che costituisce il motore di Za-
nebug: Adapdev.UnitTest.dll, quindi importia-
mo il namespace Adapdev.UnitTest all’interno
del nostro codice; così facendo siamo in grado
di utilizzare tutti gli attributi messi a disposi-
zione da Zanebug per identificare una classe
come classe di test (attributo TestFixture) e un
metodo come metodo di test (attributo Test).
Portando a termine questi semplici passi, ab-
biamo già creato la base per l’effettuazione di
qualsiasi unit test a cui vogliamo sottoporre il
nostro codice.
Quando si esegue il testing “a mano” senza
usare alcun framework, assumono una notevo-
le importanza le asserzioni, caratteristica che si
riflette in maniera più avanzata anche in Zane-
bug tramite la classe Assert, che prevede meto-
di per controllare se due oggetti sono uguali, se
due oggetti hanno lo stesso riferimento (in poche
parole se puntano allo stesso oggetto), se una
determinata condizione è falsa e altre interes-
santi opzioni ben documentate nella guida.
Oltre a questi fondamentali attributi che forni-
scono l’ossatura per approntare un buon test, è
possibile inserire una descrizione per ogni test
che si compie, la categoria che si vuole fare ap-
partenere un determinato test, se da un deter-
minato metodo ci si aspetta una ben specifi-
ca eccezione, oppure se un metodo deve essere
ignorato in fase d’esecuzione.
Dopo aver brevemente esaminato le istruzioni
che devono essere inserite nel codice per poter
effettuare i test, passiamo ora all’analisi dell’in-
terfaccia utente di Zanebug, che senza dubbio
rappresenta l’aspetto più interessante e più po-
tente di tutto il tool.
La parte principale dell’interfaccia utente del
programma è occupata dalla cosiddetta Test Bar,
che permette di eseguire o interrompere i test,
mostrare la percentuale d’elaborazione dei test
correnti e, a test ultimato, individuare grafica-
mente la percentuale di test che hanno avuto
successo, il tutto evidenziato dalla colorazione
differente in base all’esito dei test: ovviamente
rosso se uno o più test non ha avuto esito posi-
tivo, verde altrimenti.
Il TreeView presente nella schermata princi-
pale elenca la struttura ad albero dei Test, Te-
stFixture, TestAssembly e TestSuite, permet-
tendo di selezionare o meno un test per la sua
eventuale esecuzione. Selezionando una qual-
siasi voce del TreeView vengono evidenziate tut-
te le caratteristiche del test che si possono im-
mettere in fase di scrittura all’interno del co-
dice, già menzionate in precedenza (categoria,
descrizione, ecc.).
D’assoluto interesse sono i numerosi Tab pre-
senti nell’interfaccia principale che permetto-
no di filtrare in numerosi modi i test: tutti, solo
quelli che hanno avuto esito positivo, solo quel-
li negativi oppure quelli ignorati.
Per ognuno di questi tab vengono illustrati
una notevole mole di dati, quali il tipo di test,
il messaggio di un’eventuale eccezione genera-
ta, il tempo medio d’esecuzione del test, la du-
rata in percentuale del test rispetto al TestSui-
te, la quantità di memoria consumata dal test,
il numero d’iterazioni del test.
Oltre a queste caratteristiche, il menu conte-
stuale d’ogni tab prevede ulteriori interessanti
analisi grafiche, come il confronto tra più test
o la media di un test evidenziato rispetto alla
media totale. Oltre a tutto ciò, il tab “Perfmon”,
come suggerisce il nome, offre un Performance
Monitor per tener traccia di statistiche presta-
zionali senza dover lasciare l’ambiente di Za-
nebug ricorrendo magari ad altri strumenti o al
Performance Monitor nativo di Windows.
Due ulteriori caratteristiche rendono il pro-
dotto completo sotto ogni punto di vista: la
console di Zanebug e l’integrazione con Visual
Studio.NET.
La prima permette l’esecuzione dei test da riga
di comando con una gamma di scelte molto am-
pia, simile a quella della parte grafica (escluse
le statistiche avanzate e i grafici, ovviamente),
59
.NET TOOLS
N. 65 - Settembre/Ottobre 2005 VBJ
ProdottoZanebug
Url di riferimento http://www.adapdev.com
Sta to ReleaseStabile (versione corrente 1.5.0.1)
Semplicità d’uso �����La semplice ma funzionale interfaccia grafica facilita molto.
Utilità �����Per chi utilizza lo Unit Testing è uno strumento fondamentale per semplificare la creazione e l’utilizzo di test visuali.
Qualità prodotto ����� Affidabile, nei test sul prodotto eseguiti non ha mai mostrato par-ticolari problemi.
Qualità documentazione �����Presenti sia help on line che documentazione su Web.
permettendo così di utilizzare la modalità batch;
la seconda installa un add-in nell’IDE di Visual
Studio.NET (solo versione 2003, per ora), che in-
serisce una voce al menu di contesto utile per
aggiungere in modo rapido gli attributi necessa-
ri in quel punto attivo del codice sorgente, non-
ché una Toolbar per poter eseguire i test diret-
tamente all’interno di Visual Studio.Net.
La versione attuale, la 1.5.0.1, scaricabile gra-
tuitamente, fornisce, come si è potuto dedurre,
buone funzionalità per l’automazione dei test,
oltre ad una dettagliata analisi dei risultati con-
seguiti. Oltre ad essere completamente gratui-
to, è anche possibile effettuare il download del
codice sorgente, caratteristica che per i più vo-
lenterosi rende ancora più appetibile quest’ot-
timo strumento.
60 VBJ N. 65 - Settembre/Ottobre 2005
I design pattern
più famosi implementati
in VB.NET
di Lorenzo Vandoni
Ipattern descritti nel libro “Design Pattern” di
Gamma, Helm, Johnson e Vlissides sono or-
ganizzati in tre categorie: pattern di creazio-
ne, di comportamento e strutturali.
Nelle due puntate precedenti abbiamo esaminato
due tra i più noti pattern di comportamento, Itera-
tor e Observer, e un pattern di creazione, Factory
Method. Concludiamo questa piccola serie mostran-
do un pattern strutturale, Adapter.
Il pattern Adapter, descrizioneCome al solito, la descrizione del pattern verrà
suddivisa in tre sezioni.
In questa prima sezione ne verranno discussi sco-
po, motivazioni e applicabilità.
• Intent. Lo scopo del pattern è quello di per-
mettere ad una classe A di utilizzare i servizi
di una classe B, nell’ipotesi che B implementi
le funzionalità desiderate, ma fornisca un’in-
terfaccia pubblica incompatibile con quella ri-
chiesta da B.
• Motivation. A volte può capi-
tare che un’applicazione che
si sta sviluppando richieda da
parte di alcune classi un’in-
terfaccia ben precisa. Questo
capita soprattutto durante le
operazioni di manutenzione,
quando cioè un’applicazione
viene modificata per rispon-
dere a nuove esigenze.
Per esempio, potrebbe capita-
re che le funzionalità di log di
un programma, inizialmente
dirette verso un normale file
di testo, debbano in un secon-
do tempo essere convertite in
modo da memorizzare le righe
di log in una tabella di databa-
se. In questi casi, si può veri-
ficare la necessità di sfruttare
delle classi di libreria che of-
frono le funzionalità deside-
rate, ma tramite un’interfac-
cia di programmazione diver-
sa da quella richiesta dall’ap-
plicazione. Le alternative sono
tre: o si modificano le classi di
libreria, o si modifica il codice
dell’applicazione, o si crea un
adattatore che funga da trami-
DP 4
Il pattern Adapter suggerisce come modificare una classe
server in modo da adattarsi all’interfaccia richiesta da
altre classi client
Quarta puntata
Lorenzo Vandoni è laureato in Informatica, ed è uno spe-
cialista di progettazione e sviluppo con tecniche e linguaggi
object-oriented. Ha collaborato alla realizzazione di framework,
strumenti di sviluppo e software commerciali in C++, Java e
Visual Basic. Può essere contattato tramite e-mail all’indirizzo
SOFTWARE ENGINEERING
61N. 65 - Settembre/Ottobre 2005 VBJ
teServer, sfruttando però un’interfac-
cia diversa. Il fatto che il programma
client sia rappresentato tramite una sola
classe è ovviamente una semplificazio-
ne, che però non modifica la struttura
della soluzione.
° ServerInterface rappresenta l’interfac-
cia che l’applicazione client intende uti-
lizzare. A seconda dei casi, si potrà trat-
tare di una vera interfaccia, di una clas-
se base, oppure di un insieme di classi
ed interfacce. In pratica, ServerInter-
face rappresenta l’insieme di funzioni
utilizzate dalla classe Client.
° ConcreteServer identifica la classe, che
si suppone già presente e implementa-
ta all’interno di un’altra applicazione, di
un toolkit o di una libreria, che forni-
sce le funzionalità desiderate, ma che si
rende accessibile tramite un’interfaccia
di programmazione (cioè un insieme di
proprietà e funzioni) diversa e non com-
patibile da ServerInterface.
° Adapter è la classe che fornisce il lega-
me tra Client e ConcreteServer. Questa
classe implementa l’interfaccia Serve-
rInterface, ovvero presenta l’insieme di
proprietà e funzioni che il programma
client si aspetta di usare, e ne delega
l’esecuzione al ConcreteServer.
Sono due i modi con cui questa delega
te. Il pattern Adapter suggerisce appunto la
creazione di un adattatore.
• Applicabilità. Il pattern è applicabile ogni
volta in cui sia impossibile o non conve-
niente modificare sia il codice client sia
il codice server, e sia necessario accedere
alle funzionalità di una classe utilizzando
un’interfaccia di programmazione diversa
da quella fornita dal codice server.
Soluzione del problemaPer questo problema il pattern suggeri-
sce due diverse soluzioni. La prima utilizza
l’ereditarietà, la seconda l’incapsulamento. La
struttura delle classi, nei due casi, è mostrata
nelle Figure 1 e 2.
• Structure. Le due figure sono molto simi-
li. L’unica differenza è data dalla relazione
tra le classi Adapter e ConcreteServer. Nel
primo caso abbiamo una relazione di ere-
ditarietà, mentre nel secondo caso l’Adap-
ter incapsula il ConcreteServer per forni-
re le funzionalità imple-
mentate da quest’ultimo
tramite l’interfaccia Ser-
verInterface.
• Participants. Vediamo più
in dettaglio le responsabi-
lità delle varie classi ed in-
terfacce:
° La classe Client rap-
presenta l’applicazio-
ne client, che ha la
necessità di sfruttare
i servizi del Concre-
Fi gu ra 1 Una possibile soluzione del pattern Adapter
SOFTWARE ENGINEERING
A volte può capitare che
un’applicazione richieda
da parte di alcune classi
un’interfaccia ben precisa
62 VBJ N. 65 - Settembre/Ottobre 2005
può essere implemen-
tata, rappresentati ri-
spettivamente dalle
Figure 1 e 2.
Nel primo caso viene
utilizzata l’ereditarietà
di implementazione,
mentre nel secondo
caso la delega avviene
in modo esplicito tra-
mite incapsulamento.
La prima tecnica è ap-
plicabile solo in C++,
unico linguaggio che
fornisce la possibilità di ereditare il com-
portamento di una classe senza ereditar-
ne l’interfaccia, nonché unico linguaggio
che supporta l’ereditarietà multipla (ne-
cessaria nel caso in cui ServerInterface
sia una classe base). Per questo motivo,
nell’implementazione di esempio verrà
utilizzata la seconda tecnica.
• Collaborations. La struttura dinamica di
questo pattern non ha nulla di particolare.
La classe Client istanzia un Adapter trami-
te l’interfaccia ServerInterface. L’Adapter, a
sua volta, crea un istanza di ConcreteSer-
ver. Tutte le successive chiamate da parte
di Client a metodi implementati dall’Adap-
ter verranno da questo convertiti in chiama-
te al ConcreteServer.
Conseguenze e beneficiVediamo ora quali siano i punti di forza del
pattern ed alcune applicazioni pratiche:
• Consequences. La conseguenza principale
derivante dall’utilizzo di Adapter risiede nel
fatto che esso permette di non modificare né
l’applicazione client, né il codice del server,
normalmente incluso in una libreria, con-
sentendo però all’applicazione di sfruttare
le funzionalità di quest’ultimo.
• Known uses. La maggior parte dei casi pra-
tici in cui questo pattern si rende utile na-
scono nel contesto di operazioni di ristrut-
turazione di vecchie applicazioni per in-
corporare nuove funzionalità. Esempi noti
di applicazione di Adapter possono esse-
re considerati i due assembly che consen-
tono di sfruttare all’interno di applicazio-
ni .NET i vecchi provider OLEDB e i vec-
chissimi driver ODBC.
Questi assembly implementano un’inter-
faccia ben specifica, costituita dalle varie
interfacce definite in System.Data, come
IDBConnection e IDBCommand, ma de-
legano l’esecuzione delle varie funzioni ai
provider e ai driver sottostanti.
Implementazione del patternin VB.NET
Come esempio di implementazione conside-
riamo un’applicazione VB.NET al cui interno
sia stato implementato un meccanismo di log
“artigianale”, e supponiamo che si voglia so-
stituire in un secondo tempo questo mecca-
nismo con qualcosa di più evoluto, costituito
nell’esempio dall’utilizzo della classe Trace
del namespace System.Diagnostics.
L’esempio è costituito da una form, nel cui
evento Form_Load è stato introdotto un er-
rore. L’errore viene gestito all’interno di un
blocco Try Catch con una chiamata al meto-
do Trace dell’interfaccia GenericLogger. L’im-
plementazione “artigianale” prevede che il
GenericLogger sia implementato da una clas-
se DummyLogger, che si limita a visualiz-
zare il messaggio di trace all’interno di un
message box. Il pattern Adapter è costituito
SOFTWARE ENGINEERING
Fi gu ra 2 Una soluzione alternativa per il pattern Adapter
63N. 65 - Settembre/Ottobre 2005 VBJ
dalla classe LoggerAdapter, che implementa
l’interfaccia GenericLogger in modo differen-
te, delegando l’esecuzione del log alla classe
System.Diagnostic.Trace.
Questa classe del framework implementa le
funzioni di trace informando dei listener che
si possono registrare richiamando il metodo
SOFTWARE ENGINEERING
Listeners.Add. Nell’esempio come listener vie-
ne utilizzata un’istanza della classe TextWri-
terTraceListener, che scrive il messaggio di
trace sulla console.
ConclusioniAdapter è un pattern che risulta utile soprat-
tutto durante la manutenzione o la ristruttu-
razione di applicazioni e librerie, in quanto
consente di sfruttare nuove funzionalità sen-
za modificare in modo sensibile il codice ori-
ginale dell’applicazione.
Perché il pattern possa essere sfruttato, però,
è necessario che l’applicazione sia stata ori-
ginariamente progettata in modo corretto ed
estendibile, incapsulando bene i vari moduli
e le loro interfacce.
Il pattern è applicabile ogni
volta in cui sia impossibile
modificare il codice client e
il codice server
VBJ 65
IN OFFERTA VBJ 65
Scrivi a
specificando
nell’oggetto della
e-mail:
IN OFFERTAVBJ n. 65
OPPURE
inviaci il coupon
sottostante
al numero di fax
0587/732232
Potrai acquistare
i libri qui riportati con
uno
SCONTOECCEZIONALE
del 10% anche se
acquisti solo un libro
OPPURE
del 20% se acquisti
3 libri
Java and SOAPdi R. Englander
O’ReillyISBN 0596001754
276 pp - 41,40 €
Starting Outwith Visual Basic.Net
di T. Gaddis et al.
Addison WesleyISBN 1576760944890 pp - 62,70 €
Programming Windows Presentation Foundation
di C. Sells - I. Griffiths
O’ ReillyISBN 0596101139447 pp - 39,95 €
Web ServicesPlatform Architecture
AA. VV.
Prentice HallISBN 0131488740456 pp - 46,95 €
Microsoft SQL Server 2005.Changing the Paradigm
SamsISBN 0672327783504 pp - 34,70 €
Head FirstDesign Patterns
di Eric Freeman et al.
O’ReillyISBN 0596007124688 pp - 44,95 €
65
L I B R I
N. 65 - Settembre/Ottobre 2005 VBJ
Obiettivo di questo libro è guidare il lettore attraverso la progetta-zione e l’implementazione di un compilatore per un linguaggio compatibile con lo storico QuickBasic, interamente realizzato
in Visual Basic .NET e in grado di produrre codice assembly per la piattaforma .NET. Dopo un piacevole excursus storico sui compilatori e, più in particolare, del linguaggio BASIC, il testo presenta una breve introduzione al freamework .NET. Non si tratta della solita presentazione dell’ambiente, ma di una analisi ragionata dei componenti fondamentali (CTS, CLS e CLR) con l’obiettivo di scrivere un compilatore per esso. L’autore illustra i concetti base della teoria dei compilatori e una analisi sintattica del linguaggio QuickBasic, cui segue lo sviluppo dei primi componenti del quickBasicEngine vero e proprio. Dopo aver disegnato la modellazione ad oggetti del linguaggio in uso, vengono discussi nel dettaglio il modulo parser e il generatore di codice. Il lettore è guidato attentamente sia sugli aspetti teorici (espressioni regolari, BNF…) che in quelli pratici (ottimizzazione del codice). Tutto il sorgente dell’ambiente presentato nel libro è disponibile online (evitando, dunque, di appesan-tire inutilmente il volume); al fine di avere una lettura proficua del testo, è consigliabile avere il codice a disposizione sul proprio PC e seguire dettagliatamente i passi indicati dall’autore. Lo studio del compilatore prosegue con una breve analisi del funzionamento di assembler e interpreti e delle implicazioni nello sviluppo dell’applicazione. Prima di concludere, l’autore si sofferma su alcune problematiche legate alla scelta del linguaggio che si intende supportare. Il tema trattato è estremamente particolare, destinato a un pubblico specialistico. Se ne sconsiglia una lettura “casuale”, distratta o saltuaria! Gli studenti potranno trovarci spunti interessanti per comprendere il funzionamento dei compilatori o cimentarsi nella progettazione di un linguaggio.
ProÈ un testo “coraggioso”, perché affronta un tema fondamentale (teoria
e pratica dei compilatori) rendendolo attuale attraverso l’implementazio-ne all’interno del Framework .NET. Ottimo come base di partenza per progetti più complessi (eventualmente per supportare altri linguaggi), sicuramente consigliato come testo didattico di riferimento.
ControLa scelta di VB.NET per l’implementazione del compilatore è discu-
tibile; probabilmente sarebbe stato più interessante vederne una in C# (a questo proposito l’autore sottolinea che tutti i programmatori C# conoscono VB.NET, ma non è vero il viceversa...).
Stefano Sanna
Build Your Own .NETLanguage and Compiler Autore Edward G. Nilges Editore Apress ISBN 1590901348 Lingua Inglese Anno 2004 Pagine 388 Prezzo € 50,50
Trovare in un titolo di libro le parole “SQL Server” e “Perl” può suscitare qualche perplessità. In effetti, uno dei punti di forza di questo libro consiste proprio nel mostrare a chi usa un
ambiente Microsoft che possono esserci dei casi in cui può valere la pena di usare altri prodotti, come appunto Perl, per semplificare i compiti di amministrazione. Si può anche aggiungere che il fatto stesso di rendere nota l’esistenza di Activestate Perl è un bonus di per sé!
Purtroppo questo pregio diventa anche la maggiore limitazione del libro. Chi è un esperto amministratore di SQL Server ma non conosce nulla di Perl viene guidato passo passo alla comprensione di concetti astrusi quali le pattern e le espressioni regolari, o a leggere un file di configurazione; viceversa, chi proviene da un ambiente Unix e sperasse di comprendere meglio il funzionamento pratico di SQL Server si trova a disagio, quasi come fosse capitato in un mondo alla rovescia. Gli algoritmi e le procedure presentati nel libro sono inoltre molto specializzati, e quindi non particolarmente utili per chi volesse usare ad esempio MySQL come database; insomma non lo si può definire certo un libro per tutte le stagioni.
Occorre però riconoscere che se si fa parte del target cui il libro è dedicato, il suo valore si nota subito. Infatti i vari problemi scelti sono indubbiamente quelli che possono capitare nella vita di chi gestisce basi di dati; inoltre la spiegazione di contorno alla solu-zione è sempre molto dettagliata, e cerca di spiegare anche cosa ci sta sotto, senza limitarsi a porgere la risposta. Risulta più facile quindi adattare gli esempi al proprio caso particolare. Fortunata-mente presso il sito dell’editore è possibile scaricare una versione elettronica di tutti gli esempi, a partire da http://www.apress.com/book/bookDisplay.html?bID=171.In definitiva, un libro per una fascia selezionata di lettori che però lo troveranno di grande utilità.
Pro
Le spiegazioni sono non solo dettagliate, ma danno anche un’idea di cosa c’è dietro alla soluzione proposta.
ControIl libro è davvero utile solo per chi deve amministrare sistemi
SQL Server.
Maurizio Codogno
Real World SQLAdministration with Perl Autore Linchi Shea Editore Apress ISBN 159059097X Lingua Inglese Anno 2003 Pagine 798 Prezzo € 64,15