v2006 05 vbj71

68

Upload: turing-club

Post on 07-Jun-2015

211 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: v2006 05 vbj71
Page 2: v2006 05 vbj71
Page 3: v2006 05 vbj71
Page 4: v2006 05 vbj71

�����������������������������������������������������������������������

��������������������������������������������������������������������������������������������������������������������������������������

�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������

���������������������������������������������������������������������������������������������������������������������������������������

018915-Visual 410x275 M 1 15-03-2006 17:45:46

Page 5: v2006 05 vbj71

�����������������������������������������������������������������������

��������������������������������������������������������������������������������������������������������������������������������������

�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������

���������������������������������������������������������������������������������������������������������������������������������������

018915-Visual 410x275 M 1 15-03-2006 17:45:46

Page 6: v2006 05 vbj71
Page 7: v2006 05 vbj71

��������

�����������������������������������

����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������

���������������

����

�� ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������

��������

�� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������

���

�� �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������

����������

�� ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������

���

�� ����������������������������������������������������������������������������������������������������������������������������������������������������������������

������

�����

����������

����������

�������������

��������

Page 8: v2006 05 vbj71
Page 9: v2006 05 vbj71

�������������������

����������������������������������� �

�������������������������

�������������������������

����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������

����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������

������������������������������������������

� � � � � � � � � � � � � � � � � � �������������������������������

����������������������������

����������������������������������������������������������������

�������������������������������������������������������������

�����������������������������������������������

����������������������������������������������

����������������������������������������������������������������������������

������������������������������������������

�����������������������������������������������������������������������

��������������������������

������������������������������

�����������������������������������������

��������������������������������������������

������������������������

�������������������

������������������������������

����������������������

��������������������������������������������������������������������������������������

����������������

�������������������������������������������������������������������������������

������������������������������������������������������

�������������������������

�������������������������������������������������������������������������������������������������������������

������������������������������������

����������������������������������������������������������������

���������������������������������������������������������

��������������������������������������������������������������������������������������������������������������

�����������������������������������������������������

Page 10: v2006 05 vbj71

VBJ 68

IN OFFERTA VBJ 71Scrivi a

[email protected]

nell’oggetto dellae-mail:

IN OFFERTAVBJ n. 71 OPPURE

inviaci il couponsottostante

al numero di fax0587/732232Potrai acquistare

i libri qui riportati con uno

SCONTOECCEZIONALEdel 10% anche seacquisti solo un

libroOPPURE

del 20% se acquisti3 libri

Web Services Platform Architecture

AA.VV

Prentice HallISBN 0131488740456 pp, euro 46,95

Core Security Patternsdi C. Steel, R. Nagappan

Prentice HallISBN 0131463071

1088 pp, euro 52,95

ASP.NET 2.0 Illustrated

di A. Homer, D. Sussman

Addison WesleyISBN 0321418344800 pp, euro 48,95

ASP.NET 2.0 Cookbook, Second Edition di M.A. Kittel, G.T. LeBlond

O’ ReillyISBN 0596100647

1014 pp, euro 54,95

ASP.NET 2.0 Unleashed

di S.Walther

SamsISBN 06723282321992 pp, euro 52,95

How to Break Web Softwaredi M.Andrews,

J.Whittaker

Addison WesleyISBN 0321369440240 pp, euro 30,95

Page 11: v2006 05 vbj71

11N. 71 - Settembre/Ottobre 2006 VBJ

La paginazione dei record

di Paolo Pialorsi (www.devleap.com)

Da anni esiste un problema che assilla gli sviluppatori di applicazioni web e non solo: la paginazione dei record.

Tutte le volte che si parla di questo argomento c’è chi storce il naso e sostiene che è un falso problema. Probabilmente il più delle volte ha ragione! Spesso infatti abbiamo l’esigenza di paginare i record perché non abbiamo fornito ai nostri utenti gli strumenti adatti o non siamo stati abbastanza convincenti, per far capire loro che ottenere una lista di 850.000 record da pagi-nare 20 alla volta non serve poi un granché... o no? In questo senso spesso si dice che paginare migliaia di record non è un problema da risolve-re ma è un problema da evitare.D’altra parte sappiamo però che non sempre si può realizzare tutto come si vorrebbe. A volte gli utenti dobbiamo accontentarli, soprattutto se sono clienti o responsabili d’ufficio che ci pagano in proporzione a quanto li rendiamo contenti...Inoltre, molto spesso forniamo agli utenti degli strumenti di consultazione dei dati che sono personalizzabili e che in funzione di come ven-

gono personalizzati possono restituire tanto 10 quanto 10.000 record."Pensiamo a un caso sicura-mente noto a tutti: un moto-re di ricerca su Internet. Se cerchiamo <<“XML Schema Definition” XAML>> otterre-mo un certo risultato (ad oggi 1.880 righe su Google), se in-vece cerchiamo “XML” ne ot-terremo un altro (929.000.000 righe, sempre su Google). Il risultato sarà diverso sia in termini di qualità che di quantità. Eppure i motori di ricerca ci forniscono una lista paginata e maledettamente veloce da sfogliare!Il problema principale, per una tipica applicazione di consultazione dati, è fornire una lista che sia anche ordi-nabile e ricercabile secondo dei filtri che sono definibili liberamente dall’utente fina-le dell’applicazione. È infatti relativamente facile restituire una lista di record, ordinati secondo un preciso criterio, che non cambierà mai, con-

La paginazione dei dati è un problema che da sempre si pre-senta nelle applicazioni moderne, in particolare con interfac-cia web. Esaminiamo le tecniche più diffuse per rispondere a questa esigenza

Paolo Pialorsi è un consulente e autore specializzato nello sviluppo di servizi SOA e soluzioni in architettura distribuita basate sul 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]. Mantiene il blog personale all’indirizzo http://blogs.devleap.com/paolo/

Paginazione

SPECIALE

Page 12: v2006 05 vbj71

12 VBJ N. 71 - Settembre/Ottobre 2006

e confrontandomi con il resto del gruppo DevLeap ho deciso di provare a ricondurre il problema a una serie di casi.Ho preso come esempio un’applicazione web, utilizzando quasi sempre una griglia ASP.NET, perché è comoda e perché è quella che 9 sviluppatori su 10 utilizzano – magari abusandone – se devono fornire una lista paginata, ordinabile e filtrabile in un’applicazione Intranet/Internet, utiliz-zando un database demo con una tabella di 1 milione di record così strutturata:

T-SQL

CREATE TABLE [dbo].[tabCustomers] (

[idCustomer] [int] INDENTITY(1,1) ,

[CustomerName] [varchar] (30) NOT NULL ,

[CustomerEMail] [varchar] (50) NOT NULL ,

[CustomerBirthday] [datetime] NOT NULL,

[CustomerSex] [bit] NOT NULL ,

[SysTimestamp] [timestamp] NOT NULL

) ON [PRIMARY]

GO

sentendo all’utente di spostarsi solo avanti o indietro di una pagina per volta, rispetto alla pagina correntemente visualizzata. Un altro discorso è fornire una lista filtrata e ordinata a piacere, paginandola in modo casuale con una finestra di N (di solito 10 o 20) pagine per volta, ciascuna con 20/30/50 record.

Le possibili soluzioniEsistono diverse possibili soluzioni a que-sto problema, tutte che possono andare bene, ma a seconda dell’obiettivo da rag-giungere. Questo significa che non esiste la soluzione, ma esistono delle soluzioni possibili. Sta a noi e alla nostra competen-za di analisti e non solo di programmatori capire quando applicare quale soluzione.L’obiettivo sarà sempre e comunque quello di fornire ai nostri utenti la possibilità di elencare dei record, eventualmente filtrati e/o ordinati a piacere (entro certi limiti di fil-tro e ordinamento dettati dal buon senso).Partendo quindi da queste considerazioni,

Tabella 1 Riepilogo delle tecniche esaminate

Tecnica Pro Contro

Paginazione con DataAdapter

Richiede poco sforzo Al crescere del numero di pagina, cresce il costo. Non è una soluzione ottimale perché “spreca” tutti i record prima di quelli della pagina corrente

Cursore Server-Side Consuma solo i record necessari

Richiede un cursore lato server

Tabella temporanea Non richiede cursori La tabella temporanea determina la ricompilazione del piano di esecuzione della stored procedure

Paginazione custom con colonna dinamica

Ottimi risultati, anche con alto numero di record

Richiede impegno per la codifica della stored procedure

Paginazione SQL Server 2005 con CTE e ROW_NUMBER()

Ottimi risultati, anche con alto numero di record

Richiede SQL Server 2005

SPECIALE

Page 13: v2006 05 vbj71

13N. 71 - Settembre/Ottobre 2006 VBJ

La paginazione dei record è spesso un falso problema

ALTER TABLE [dbo].[tabCustomers] WITH NOCHECK ADD

CONSTRAINT [PK_tabCustomers] PRIMARY KEY CLUSTERED

(

[idCustomer]

) ON [PRIMARY]

GO

ALTER TABLE [dbo].[tabCustomers] ADD

CONSTRAINT [DF_tabCustomers_CustomerSex] DEFAULT (0)

FOR [CustomerSex]

GO

Come si vede ho creato una PrimaryKey con un indice clustered (cioè che defini-sce l’ordinamento dei record nella tabella) sulla colonna idCustomer, definita come INDENTITY (ho cercato di riprodurre un caso abbastanza tipico).Con uno script banale ho popolato la tabel-la con 1 milione di record e ho predisposto le varie soluzioni e le ho eseguite, visualiz-zando diverse pagine, con diversi filtri e ordinamenti.In tutti i casi focalizziamoci sul codice SQL e non sul codice ASP.NET, che è solo un dettaglio applicativo. Paginare una gri-glia ASP.NET non c’entra con i criteri di paginazione sul DB e si possono trovare centinaia di articoli e libri che spiegano come farlo in modo più o meno automa-tico. In tutti i casi costruiamo dinami-camente, all’interno di apposite stored procedure, lo statement SQL di selezione delle righe, in funzione dei criteri di filtro e ordinamento scelti dall’utente, quindi invochiamo la stored procedure di siste-ma sp_executesql per ottenere il risultato. Alla prima richiesta avremo prestazioni modeste, ma dalla seconda potremo sfrut-tare il caching del piano di esecuzione del-la query costruita dinamicamente, quindi, per ricerche uguali in termini di filtro, avremo probabilmente già in cache i loro piani di esecuzione.In Tabella 1 c’è un breve riepilogo delle tecniche valutate, alcune delle quali an-dremo a sviluppare di seguito.Nell’articolo analizzeremo le query risul-

tato e non tutti gli statement SQL delle stored procedure. Questi ultimi saranno disponibili nel codice allegato all’articolo, che contiene gli script SQL completi di tutti gli esempi.

Non dimentichiamoci la sicurezza!Tutte le soluzioni proposte prevedono che le applicazioni che ne fanno uso siano pro-gettate e sviluppate senza trascurare gli aspetti e i problemi legati alla sicurezza.Alcune delle stored procedure proposte, se alimentate con parametri “grezzi” non controllati e filtrati con regular expression o soluzioni analoghe, potrebbero dare adito a problemi di SQL Injection.Questo è un articolo che concentra la sua attenzione sugli statement SQL e sulle tecniche di paginazione, non sull’archi-tettura di un’intera applicazione, quindi non avremmo tutti gli elementi necessari a svolgere delle valutazioni serie sul conte-sto di sicurezza del codice proposto. Prima quindi di utilizzare le soluzioni proposte occorre un’attenta valutazione dei rischi e delle problematiche di security, contestua-lizzandone l’uso.

Paginazione con DataAdapterIl DataAdapter di ADO.NET ci fornisce la possibilità di popolare un DataSet indi-cando da quale record vogliamo iniziare e per quanti record ci vogliamo spostare in avanti.

C#

da.Fill(ds, gridCustomers.PageSize * gridCustomers.

Curren tPageIndex,

gridCustomers.PageSize, “tabCustomers”);

SPECIALE

Page 14: v2006 05 vbj71

14 VBJ N. 71 - Settembre/Ottobre 2006

Sappiamo che il DataAdapter internamen-te utilizza un DataReader per riempire il DataSet. Ecco che allora risulta immediato capire come si comporti in questo caso: scorre in modalità forward-only e read-only il DataReader e quando arriva al pri-mo record utile del resultset inizia a riem-pire la DataTable di destinazione; quando sono stati raggiunti gli N record di pagina, annulla la parte restante della richiesta. Questa soluzione non risparmia per nulla la rete e il Server SQL, in particolare se richiediamo numeri di pagina alti. Quin-di è applicabile su resultset di modeste dimensioni o comunque su pagine basse. Sicuramente è preferibile al caso della pa-ginazione automatica operata dai controlli ASP.NET. Dal punto di vista del codice SQL non dobbiamo fare nulla, perché tutto il lavoro sarà a carico del DataAdapter. La nostra stored procedure di selezione dei record fornirà comunque tutti i record:

T-SQL

CREATE PROCEDURE spListCustomersForDataAdapterPaging

(

@CustomerName varchar(30) = ‘’,

@CustomerEMail varchar(50) = ‘’,

@CustomerBirthDayStart datetime = NULL,

@CustomerBirthDayEnd datetime = NULL,

@CustomerSex bit = NULL,

@SortExpression nvarchar(100) = NULL,

@RecordCount int OUTPUT

)

AS

-- Non devo fare altro che richiamare la spListCusto-

mersForAutoPaging aggiungendo il numero di record che ho

ottenuto

EXEC spListCustomersForAutoPaging @CustomerName, @Custo-

merEMail, @CustomerBirthDayStart, @CustomerBirthDayEnd,

@CustomerSex, @SortExpression

SET @RecordCount = @@ROWCOUNT

GO

Paginazione con cursore lato serverUn’altra possibile soluzione da valutare è quella di utilizzare un cursore lato server, che ci consenta di posizionare il server e non più il client sulla pagina corretta, per poi caricare la rete dei soli record di no-stro interesse. Se non dovessimo fornire al nostro utente la possibilità di filtrare e ordinare liberamente i record, basterebbe definire un cursore “classico” con DECLA-RE ... CURSOR FOR e farne la FETCH per spostarci sui record di nostro interesse. Qualcosa come:

T-SQL

-- Cursore per scorrere i record di tabCustomers

DECLARE curCustomers SCROLL CURSOR FOR

SELECT idCustomer, CustomerName, CustomerEMail, Customer-

Birthday, CustomerSex

FROM tabCustomers FOR READ ONLY

-- Apro il cursore

OPEN curCustomers

-- Mi sposto sul primo record della pagina

DECLARE @FirstRecordPosition int

SET @FirstRecordPosition = (@PageSize * (@CurrentPage

- 1)) + 1

FETCH ABSOLUTE @FirstRecordPosition FROM curCustomers

-- Ottengo i record della pagina richiesta

DECLARE @CurrentPosition int

SET @CurrentPosition = 1

WHILE ((@@FETCH_STATUS = 0) AND (@CurrentPosition < @Pa-

geSize))

BEGIN

SET @CurrentPosition = @CurrentPosition + 1

FETCH NEXT FROM curCustomers

END

-- Rilascio le risorse allocate

CLOSE curCustomers

DEALLOCATE curCustomers

SELECT @RecordCount = Count(*) FROM tabCustomers

GO

SPECIALE

Page 15: v2006 05 vbj71

15N. 71 - Settembre/Ottobre 2006 VBJ

Non esiste una soluzione, ma esistono delle soluzioni

tra cui scegliere

Il problema è che a noi serve poter definire dinamicamente l’oggetto della SELECT su cui aprire il cursore. Osservando come si comporta il buon vecchio Recordset ADO-DB possiamo però vedere che esistono delle extended stored procedure di siste-ma come sp_cursoropen, sp_cursorfetch e sp_cursorclose. Usate opportunamente (al di là, per un attimo, delle valutazioni filosofiche sull’opportunità di farne uso) possiamo definire una stored procedure come la seguente:

T-SQL

CREATE PROCEDURE spListCustomersServerSideCursor

(

[ ... omissis: filtri e ordinamenti ...]

-- Stabilisco qual è il primo record della pagina

DECLARE @FirstRecordPosition int

SET @FirstRecordPosition = (@PageSize * (@CurrentPage

- 1)) + 1

-- Dichiaro e uso il cursore dinamico

DECLARE @CursorID int

DECLARE @ScrollOpt int

DECLARE @CCOpt int

DECLARE @RowCount int

SET @ScrollOpt = 4

SET @CCOpt = 1

SET @RowCount = -1

EXEC sp_cursoropen @CursorID OUT, @SqlStatement, @Scrol-

lOpt output,

@CCOpt output, @RowCount output

EXEC sp_cursorfetch @CursorID ,32, @FirstRecordPosition,

@PageSize

EXEC sp_cursorclose @CursorID

SET @SqlStatement = ‘SELECT @RC = Count(*) FROM tabCusto-

mers’ + @SqlCondition

EXEC sp_executesql @SqlStatement, N’@RC int OUTPUT’, @RC-

= @RecordCount OUTPUT

GO

Come si vede sp_cursoropen apre un curso-

re sulla base di uno statement SQL da noi definibile dinamicamente (proprio quello che ci serve!). Il risultato della sp_curso-ropen è l’ID del cursore, con il quale pos-siamo chiedere a sp_cursorfetch di darci N record (per noi @PageSize) partendo da un certo record (@FirstRecordPosition). Dob-biamo poi ricordarci di chiudere il cursore con sp_cursorclose.Bene! Dobbiamo essere consapevoli del fatto che non stiamo facendo una bella cosa! Però funziona, potrebbe dire qual-cuno. Sì, funziona, ma non è particolar-mente performante. Sicuramente non carica l’applicazione web ASP.NET o lo strato business che ne fa uso. Carica de-cisamente di più il server SQL. Non cari-ca per nulla la rete, visto che passeranno solo N record, dove N sarà pari a @Page-Size, e il numero complessivo dei record che corrispondono al criterio di ricerca impostato, per gestire la generazione dei numeri di pagina.

Paginazione con tabella temporaneaProviamo allora a evitare di utilizzare cur-sori lato server, senza rinunciare a lasciare scarico il client e la rete. Possiamo intanto pensare che se lavoriamo con gli indici giusti e non dobbiamo cambiare l’ordina-mento predefinito dei record nella tabella, una buona soluzione è quella che prevede proprio di ragionare in base alla colonna chiave primaria e indice clustered della tabella.Come posso identificare gli N record della pagina X ragionando sulla base della Pri-maryKey? Ecco un esempio pratico, men-tre negli allegati all’articolo è disponibile la

SPECIALE

Page 16: v2006 05 vbj71

16 VBJ N. 71 - Settembre/Ottobre 2006

I problemi derivano dall’esi-genza di filtrare e ordinare i dati in modo personalizzato

per l’utente

stored procedure che genera questa query dinamicamente:

T-SQL

SELECT TOP 20 idCustomer, CustomerName, CustomerEMail,

CustomerBirthday,

CustomerSex FROM tabCustomers WHERE idCustomer >

(SELECT Max(idCustomer) FROM tabCustomers WHERE

idCustomer IN (SELECT TOP 862900 idCustomer FROM tabCu-

stomers))

Con SQL Server 2005 potremmo anche eseguire una SELECT TOP @Parametro. Si tratta di una soluzione normalmente adeguata, in quanto sfruttiamo l’ordina-mento fornito dall’indice clustered senza ulteriori overhead. Se non dobbiamo permettere ai nostri utenti di cambiare ordinamento direi che è la soluzione da preferire, perché carica poco sia SQL, sia la rete, sia il client.Se però la dimensione in byte di una riga è voluminosa, non è detto che la soluzio-ne basata sull’indice clustered sia la più efficiente: in presenza di record con una o più colonne di tipo testuale molto lunghe, potrebbe risultare più performante creare l’indice sulla chiave primaria in modalità NONCLUSTERED, senza alcun indice CLUSTERED; tale configurazione può risultare molto più performante della pre-cedente in caso di query completamente coperte dall’indice (situazione in cui SQL Server legge solo l’indice senza accedere alle pagine che contengono i dati della ta-bella vera e propria). Purtroppo è difficile stabilire a priori quale sia la soluzione più performante, fondamentalmente ci sono molte variabili in gioco e la cosa migliore è provare le due varianti e fare dei bench-mark specifici. Certamente in casi estre-mi, per esempio una riga con dimensione effettiva di circa 1.000 byte, può essere estremamente conveniente avere un indi-ce NONCLUSTERED che risolve la query, perché questo significa leggere circa 2.000 record per pagina sull’indice, contro gli 8

record per pagina della tabella reale (par-liamo di operazioni di I/O, i risultati sono visibili già a occhio nudo su tabelle con decine di migliaia di record, in assenza di cache).

Spostiamo il problema al caso in cui vo-gliamo scegliere anche il criterio di ordi-namento. Lo statement SQL dovrà essere modificato in modo tale da confrontare i record ordinati secondo il criterio scelto dall’utente e non dall’indice clustered. Ecco che una possibile soluzione è quella di utilizzare una tabella temporanea in cui andremo a inserire solo la chiave primaria di ciascun record, nell’ordine scelto dal-l’utente, e nella quale definiremo una no-stra chiave di servizio, con tanto di indice clustered, che ci permetterà di riapplicare il concetto visto nel caso precedente. Ecco il codice SQL:

T-SQL

CREATE PROCEDURE spListCustomersTempTable

(

[ ... omissis ...]

-- Definisco una tabella temporanea di appoggio

CREATE TABLE #tmpCustomers

(

idRecord int IDENTITY(1,1) PRIMARY KEY CLUSTERED,

idCustomer int

)

[ ... omissis ...]

SPECIALE

Page 17: v2006 05 vbj71

17N. 71 - Settembre/Ottobre 2006 VBJ

-- Costruisco lo statement che popola la tabella tempo-

ranea

SET @SqlStatement = ‘INSERT INTO #tmpCustomers (idCu-

stomer) SELECT TOP ‘ + CONVERT(nvarchar, (@PageSize *

@CurrentPage)) + ‘ idCustomer FROM tabCustomers’

[ ... omissis: filtri e ordinamenti ...]

-- Riempio la tabella temporanea di appoggio

EXEC sp_executesql @sqlStatement

-- Preparo lo statement di SELECT dei dati per fornire il

vero risultato all’utente

SET @SqlStatement = ‘SELECT idCustomer, CustomerName,

CustomerEMail,

CustomerBirthday, CustomerSex FROM tabCustomers WHERE

idCustomer IN (SELECT TOP ‘ + CONVERT(nvarchar, @PageSi-

ze) + ‘ idCustomer FROM #tmpCustomers ‘

IF (@CurrentPage > 1)

SET @SqlStatement = @SqlStatement +

‘ WHERE idRecord > (SELECT Max(idRecord) FROM #tmpCu-

stomers WHERE idRecord

IN (SELECT TOP ‘ + CONVERT(nvarchar, (@PageSize *

(@CurrentPage - 1))) +

‘ idRecord FROM #tmpCustomers))’

SET @SqlStatement = @SqlStatement + ‘)’

-- Eseguo lo statement di SELECT

EXEC sp_executesql @sqlStatement

-- Elimino la tabella temporanea

DROP TABLE #tmpCustomers

-- Conto quanti sono i record che corrispondo al criterio

di filtro impostato dall’utente (per il VirtualI-

temCount)

SET @SqlStatement = ‘SELECT @RC = Count(*) FROM tabCust-

omers’ + @SqlCondition

EXEC sp_executesql @SqlStatement, N’@RC int OUTPUT’, @RC

= @RecordCount OUTPUT

GO

Come si vede non cambia molto rispetto a prima. Solo che stiamo chiedendo di ese-guire:

T-SQL

SELECT idCustomer, CustomerPosition, CustomerName, Custo-

merEMail,

CustomerBirthday, CustomerSex FROM tabCustomers WHERE

idCustomer IN

(SELECT TOP 20 idCustomer FROM #tmpCustomers WHERE

idRecord >

(SELECT Max(idRecord) FROM #tmpCustomers WHERE idRecord

IN

(SELECT TOP 862900 idRecord FROM #tmpCustomers)))

Questa soluzione paga solo se definiamo

Tabella 2

ComInterfaceType

InterfaceIsDualIndica che l’interfaccia esposta a COM è un’interfaccia duale, che consente sia l’associazione anticipata sia l’associazione tardiva. InterfaceIsDual è il valore di default.

InterfaceIsDispatchIndica che l’interfaccia esposta a COM è un’ interfaccia dispatch che consente solo l’associazione tardiva.

InterfaceIsIUnknownIndica che l’interfaccia esposta a COM è un’ interfaccia derivata dal-la IUnknown che consente solo l’associazione anticipata.

SPECIALE

Page 18: v2006 05 vbj71

18 VBJ N. 71 - Settembre/Ottobre 2006

degli opportuni indici sulla tabella, al-trimenti rischiamo di dover attendere il risultato per diversi secondi. Inoltre ha senso applicarla solo quando le pagine sulle quali ci si sta muovendo sono di numero basso. Infatti più si sale, più cre-sce la quantità di record da copiare nella tabella temporanea (ricordatevi di non fare una INSERT INTO sempre di tutti i record, ma solo di quelli minori o uguali a quelli della pagina richiesta dall’utente), penalizzando quindi in modo lineare le prestazioni della query e il carico di lavo-ro per il server SQL. Il client e la rete non sono assolutamente penalizzati da queste soluzioni.

Paginazione con colonna dinamicaL’uso delle tabelle temporanee è mal sop-portato da molti, seppur a volte utile. E se provassimo a fondere l’idea del filtro basato sulla chiave primaria e dell’or-dinamento personalizzabile? Possiamo inserire nella SELECT una colonna ge-nerata dinamicamente in funzione del criterio di ordinamento scelto dall’utente e costruita concatenando la condizione di sorting con la colonna PrimaryKey. In questo modo otteniamo l’univocità della colonna dinamica generata e l’ordina-mento secondo le richieste dell’utente. Se indicizziamo correttamente la tabella possiamo avere dei buoni risultati in ter-mini di prestazioni. Vediamo la query ri-sultante nel caso di ordinamento in base al CustomerEMail:

T-SQL

SELECT TOP 20 idCustomer, CustomerName, CustomerEMail,

CustomerBirthday, CustomerSex, (CONVERT(nvarchar(100),

CustomerEMail, 20) + CONVERT(nvarchar(10), idCusto-

mer)) AS CustomKey FROM vwListCustomersByEmail WHE-

RE (CONVERT(nvarchar(100), CustomerEMail, 20) +

CONVERT(nvarchar(10), idCustomer)) > (SELECT TOP

1 Max((CONVERT(nvarchar(100), CustomerEMail, 20) +

CONVERT(nvarchar(10), idCustomer))) AS CustomKey FROM

vwListCustomersByEmail WHERE (CONVERT(nvarchar(100),

CustomerEMail, 20) + CONVERT(nvarchar(10), idCustomer))

IN (SELECT TOP 220 (CONVERT(nvarchar(100), CustomerEMail,

20) + CONVERT(nvarchar(10), idCustomer)) AS CustomKey

FROM vwListCustomersByEmail ORDER BY CustomKey) ORDER BY

CustomKey) ORDER BY CustomKey

In questa soluzione conviene fare atten-zione alle colonne di tipo datetime, che per default nel cast su nvarchar forniscono un valore testuale che rende difficile ordi-nare correttamente i dati. In questo caso il valore del parametro @SortExpression dovrà essere opportunamente modificato per contenere la lista di colonne di ordina-mento concatenate e non separate da una virgola.Per il resto eseguiamo una query abba-stanza simile a quella del caso precedente, solo che la chiave con la quale eseguiamo il confronto non è più la Primary Key della tabella temporanea, ma la colonna dinami-ca generata nella query.È assolutamente opportuno definire degli indici sulla tabella che comprendano le possibili combinazioni di ordinamento (@SortExpression) sempre seguite da idCustomer, altrimenti rischiamo di avere comunque delle soluzioni poco efficienti.Questa soluzione si contraddistingue in particolare per il fatto che le sue prestazio-ni sono abbastanza costanti, a prescindere dal numero di pagina richiesta. Su pagine di numero basso è più costosa della solu-zione basata su tabella temporanea, ma salendo il numero di pagina le prestazioni rimangono abbastanza uniformi. Come nel caso della tabella temporanea, sia la rete che il client non sono per nulla sovraccari-cati di lavoro.

Paginazione con le CTE di SQL Server 2005

In SQL Server 2005 troviamo alcuni nuovi strumenti come le Common Table Expres-sion (CTE) e la funzione ROW_NUMBER(). Ecco che allora sfruttando entrambi questi strumenti possiamo definire delle query come la seguente:

SPECIALE

Page 19: v2006 05 vbj71

19N. 71 - Settembre/Ottobre 2006 VBJ

T-SQL

WITH CustomersNumbered AS (

SELECT

ROW_NUMBER() OVER (ORDER BY CustomerEMail) AS RowNumber,

idCustomer, CustomerName, CustomerEMail, CustomerBir-

thday, CustomerSex

FROM tabCustomers)

SELECT * FROM CustomersNumbered

WHERE RowNumber BETWEEN 221 AND 240

Dove la parte WITH … AS (...) è appunto la CTE che definisce l’elenco dei clienti ordinati per il campo CustomerEMail, con l’aggiunta del numero di riga, pro-prio in funzione di quella chiave di ordi-namento, come si vede dall’applicazione della funzione ROW_NUMBER() con ordinamento OVER (ORDER BY Custo-merEMail).

La CTE viene poi utilizzata per selezionare le sole righe di interesse della nostra pagi-na.Si tratta di una tecnica con una buona ef-ficienza; come sempre è importante ricor-darsi di indicizzare correttamente le tabel-le per non pagare il prezzo di numerosi I/O in fase di esecuzione delle nostre query.

ConclusioniPenso che l’approccio migliore al problema sia tenere presenti tutte le possibili solu-zioni e, a seconda dei casi, applicare quelle più adatte, in funzione del numero di re-cord, del tipo di filtro, della locazione del client del database, della pagina richiesta e della sua dimensione, ecc. Come abbiamo visto in principio, per questo problema non esiste la soluzione, piuttosto esistono delle soluzioni, da applicare di volta in volta, a seconda dei casi.

SPECIALE

Page 20: v2006 05 vbj71
Page 21: v2006 05 vbj71

21N. 71 - Settembre/Ottobre 2006 VBJ

Master Page,Temi e interfacce in ASP.NET 2.0

di Massimo Bonanni

L’articolo prende in esame le nuove funziona-lità introdotte nella versione 2.0 di ASP.NET riguardanti la coerenza dell’aspetto di una web application, cioè gli strumenti che permettono di rendere le pagine del sito simili tra loro per disposizione degli elementi HTML e per i conte-nuti visivi e grafici.

La realizzazione di un sito web, soprattutto quei siti che devono avere un grande impatto per l’utente finale, non prescinde dall’aspetto grafi-co che deve proporre.Lo sviluppatore lavora, generalmente, di pari passo con il grafico per dare al sito un aspetto coerente ovvero per far in modo che tutte le pa-gine abbiano una “impronta grafica” simile se non addirittura uguale.ASP.NET non stravolge questo metodo di lavo-ro, ma fornisce strumenti e classi che permet-tono di razionalizzare lo sforzo e, soprattutto, di fare in modo che eventuali cambiamenti non ab-biano grande impatto nella manutenzione della web application.

Le pagine MasterIn questo paragrafo esaminia-mo come ASP.NET 2.0 aiuta nel realizzare pagine in cui la disposizione spaziale degli elementi (siano essi immagi-ni, testo, plug-in o quant’altro) è sempre la stessa.Nella versione 1.0 e 1.1 di ASP.NET, un modo per rea-lizzare pagine tutte “uguali”, consisteva nell’affidarsi agli user control, realizzati una volta per tutte in modo da avere l’interfaccia utente de-siderata e distribuiti su tutte le pagine, oppure nel costrui-re una pagina “template” vuo-ta ma con la struttura grafica ben delineata e ricavare tutte le pagine del sito dal “templa-te” ricopiandolo, rinominan-dolo e riempiendolo di oggetti grafici.Quali problematiche, Micro-soft, ha cercato di risolvere o di semplificare introducendo le Master Page?Innanzitutto minimizzare l’im-patto di eventuali cambiamenti

Le nuove funzionalità di ASP.NET 2.0 sulla gestione dell’aspetto delle pagi-ne permettono di ottenere risultati graficamente gradevoli e consentono di uniformare l’aspetto del nostro sito

Massimo Bonanni è laureato in Matematica alla Sapienza di Roma, si occupa di analisi e sviluppo software in ambiente Windows. Per diversi anni si è occupato di applicazioni in ambito telecomunicazioni ed attualmente disegna e sviluppa applicazioni web presso una software house di Roma

WEB

Page 22: v2006 05 vbj71

22 VBJ N. 71 - Settembre/Ottobre 2006

Le pagine Master, quindi, possono essere considerate come una sorta di “metapagi-ne” con struttura del tutto simile alle nor-mali pagine aspx ma estensione .master.A livello pratico, le pagine Master fornisco-no un modello per il rendering delle pagine aspx a loro collegate: nel momento in cui si richiede una pagina, ASP.NET “fonde” la pagina richiesta (detta pagina dei contenu-ti) con la pagina Master in un’unica pagina e ne effettua il rendering.Le pagine Master possono ospitare tutti i controlli web che possono essere inseriti in una pagina aspx normale, ma hanno anche la possibilità di ospitare una o più istanze del controllo ContentPlaceHolder.Il controllo ContentPlaceHolder permette di definire, all’interno di una pagina Ma-ster, un’area riservata ai contenuti che sarà riempita dai controlli della pagina aspx.A livello della pagina dei contenuti, deve es-sere definito un controllo Content per ogni ContentPlaceHolder della pagina Master e i due sono associati in base alla proprietà ContentPlaceHolderID del Content stesso.Durante l’esecuzione, il ContentPlaceHol-der diventa un controllo della collection Controls della pagina aspx, mentre i con-

che si possono avere nel tempo: utilizzare gli user control, come accadeva nelle prece-denti versioni, signi-fica che se qualche oggetto costituente uno dei controlli deve cambiare (an-che solo di posizione o attributi grafici), è necessario compilare di nuovo il codice sor-gente e ridistribuire l’assembly. Inoltre, bisogna stare atten-ti a non cambiare l’interfaccia (cioè i metodi e le proprietà pubbliche) che tali controlli espongono, pena il probabile mal-funzionamento degli oggetti che li utilizza-no. Infine, dovendo creare degli user control si deve scrivere codice e perdere tempo nel debug prima di rilasciarli.Queste problematiche sono risolte quasi del tutto o notevolmente alleviate con l’in-troduzione delle Master Page.L’idea che sta alla base della soluzione pro-posta in ASP.NET 2.0 è quella di creare la pagina che fa da modello una volta per tut-te e ricavare tutte le altre da questa.ASP.NET è basato su un modello ad oggetti e, quindi, per realizzare la soluzione è sufficien-te aggiungere un livello alla “catena” di eredi-tarietà delle pagine aspx (vedi Figura 1).Purtroppo, nella versione 1.1 del fra-mework, interferire con la “catena” di ereditarietà significava, a volte, compro-mettere il progetto.In realtà, come vedremo tra poco, la pa-gina aspx che utilizza una pagina Master non deriva, nel senso classico del termine, dalla pagina Master, ma continua ad essere figlia della Page pur mantenendo traccia nella sua parte HTML del fatto che non vive di vita propria ma in simbiosi con la pagina Master.

WEB

Figura 1 Esempio di ereditarietà tra pagina modello e pagine contenuto

Page 23: v2006 05 vbj71

23N. 71 - Settembre/Ottobre 2006 VBJ

trolli effettivi della pagina stessa, presenti all’interno del Content, sono inseriti nella Controls del ContentPlaceHolder.Per creare una pagina Master all’interno del nostro progetto è sufficiente utilizzare il menu Siti Web, l’opzione Aggiungi Nuovo Elemento e selezionare l’oggetto Pagina master.A seguito di ciò è creato un file con esten-sione .master che non differisce molto da una classica pagina aspx:

<%@ Master Language=”VB” CodeFile=”MasterPage.master.vb”

Inherits=”MasterPage” %>

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0

Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/

xhtml1-transitional.dtd”>

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

<head runat=”server”>

<title>Pagina senza titolo</title>

</head>

<body>

<form id=”form1” runat=”server”>

<div>

<asp:contentplaceholder id=”ContentPlaceHolder1”

runat=”server”>

</asp:contentplaceholder>

</div>

</form>

</body>

</html>

Da notare la direttiva @Master che sosti-tuisce la direttiva @Page e la presenza dei ContentPlaceHolder (uno solamente nell’esempio).La pagina Master non può essere richia-mata da sola (se si prova a richiedere una pagina con estensione .master si ottiene un errore dal server), ma lavora in congiun-zione con una pagina aspx che la utilizza come modello.Per creare una pagina aspx che utilizza la pagina Master è sufficiente creare un nuovo elemento per il sito web (con lo stesso menu utilizzato per la master) scegliendo web form e selezionando il segno di spunta in basso (Figura 2).Nella successiva form proposta si può scegliere quale pagina Master utilizzare (Figura 3).È necessario prestare attenzione perché se non si sceglie la pagina Master in questo

WEB

Figura 2 Aggiunta di una nuova pagina aspx

Page 24: v2006 05 vbj71

24 VBJ N. 71 - Settembre/Ottobre 2006

momento, sarà necessario intervenire sul codice HTML della pagina aspx per asso-ciare in un secondo momento la pagina Master.

<%@ Page Language=”VB” MasterPageFile=”~/

MasterPage.master” AutoEventWireup=”false” CodeFile=”Defa-

ult.aspx.vb” Inherits=”_Default” title=”Untitled Page” %>

<asp:Content ID=”Content1” ContentPlaceHolderID=”Content

PlaceHolder1” Runat=”Server”>

</asp:Content>

Osserviamo che la pagina associata alla Master page è diversa, nella struttura, ri-spetto ad una pagina che non ha Master page associata.

<%@ Page Language=”VB” AutoEventWireup=”false” CodeFile=”

Default2.aspx.vb” Inherits=”Default2” %>

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0

Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/

xhtml1-transitional.dtd”>

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

<head runat=”server”>

<title>Pagina senza titolo</title>

</head>

<body>

<form id=”form1” runat=”server”>

<div>

</div>

</form>

</body>

</html>

Si può notare la pre-senza dell’attributo MasterPageFile del-la direttiva @Page e l’assenza dei tag <HTML>, <HEAD> e <BODY> tipici di una pagina HTML.Questi, infatti, ven-gono forniti alla pagina, dalla fusio-

ne della stessa con la Master page (che, invece, li ha).Si capisce che per “sganciare” una pagina da una pagina Master è necessario rimuo-vere l’attributo MasterPageFile ed inserire i tag <HTML>, <HEAD> e <BODY> (nonché il tag <form>).È possibile specificare l’attributo Ma-sterPageFile nella sezione pages del file di conzione web.config. In questo caso le impostazioni indicate nel web.config verranno automaticamente associate a tutte le pagine che non hanno la direttiva @Page.

<configuration>

.

.

<system.web>

.

.

<pages masterPageFile=”~/MasterPage.master” />

.

.

</system.web>

.

.

</configuration>

Altra caratteristica dell’attributo Master-

Figura 3 Selezione della pagina master

WEB

Page 25: v2006 05 vbj71

25N. 71 - Settembre/Ottobre 2006 VBJ

PageFile della direttiva @Page è che può essere personalizzato in base al browser che si sta utilizzando.Nell’esempio seguente, vengono utilizzate, per una stessa pagina, differenti Master page a seconda del browser che le visualizza:

<%@ Page Language=”VB” ie:masterPageFile=”~/

IEMasterPage.master” netscape:masterPageFile=”~/

NSMasterPage.master” masterPageFile=”~/

BaseMasterPage.master” AutoEventWireup=”false” CodeFile

=”Default.aspx.vb” Inherits=”_Default” title=”Untitled

Page” %>

<asp:Content ID=”Content1” ContentPlaceHolderID=”Content

PlaceHolder1” Runat=”Server”>

<asp:Button ID=”Bottone” runat=”server” Text=”Button” />

<asp:TextBox ID=”TextBox” runat=”server”></asp:

TextBox>

</asp:Content>

I prefissi che si possono anteporre all’attri-buto MasterPageFile sono impostati all’in-terno della sezione BrowserCaps del file di configurazione.

Infine, è possibile fare in modo che la Ma-

ster page di una pagina aspx sia cambiata dinamicamente in base a particolari con-dizioni (ad esempio, se si vuole che ogni utente abbia la possibilità di avere il suo layout grafico). Per fare ciò è sufficiente non inserire l’attributo MasterPageFile nella direttiva @Page ed impostare la proprietà MasterPageFile della pagina nel gestore dell’evento PreInit:

Protected Sub Page_PreInit(ByVal sender As Object,

ByVal e As System.EventArgs) Handles Me.PreInit

Me.MasterPageFile = Profile(“MasterPage”)

End Sub

I TemiAbbiamo visto che le pagine Master con-sentono di dare costanza alla struttura del-le pagine del sito, ma ci sono elementi che devono rimanere inalterati tra le pagine, pur cambiando la loro disposizione spazia-le all’interno delle stesse. Stiamo parlando di font, colori, immagini, loghi e quant’al-tro caratterizza graficamente un sito web.I temi sono stati creati proprio per ri-

Figura 4 Aggiunta di un nuovo elemento di un tema

WEB

Page 26: v2006 05 vbj71

26 VBJ N. 71 - Settembre/Ottobre 2006

solvere questa problematica e possiamo considerarli come un’estensione dei già utilizzati CSS.I temi altro non sono che definizioni di stili e possono, al loro interno, contenere anche dei CSS.Il loro ambito di applicazione può essere a livello di applicazione (tutto il sito), di pagi-na o di controllo server.I temi differiscono dai fogli di stile CSS per le seguenti caratteristiche:

1. possono definire, al loro interno, proprie-tà di un controllo o di una pagina che van-no al di là delle classiche proprietà di stile. Ad esempio in un tema è possibile defini-re gli elementi grafici di un TreeView;

2. possono contenere anche elementi grafi-ci (immagini, icone, etc., etc.);

3. si può decidere se le proprietà e gli stili definiti in un tema sono sovrapposti o meno alle proprietà eventualmente im-postate a design-time;

4. è possibile applicare un solo tema per pagina.

Ogni tema è caratterizzato da un nome (che deve essere univoco) e può essere composto da fogli di stile CSS, da interfac-ce (skin) e da immagini.Le interfacce (o skin) sono dei file di testo di cui vedremo in dettaglio le peculiarità nel prossimo paragrafo.In pratica il CSS fornisce le proprietà client-side della pagina, mentre lo skin, come vedremo, le proprietà server-side.Per definire un tema, è necessario creare la cartella App_Themes (menu Sito Web, Ag-giungi Cartella ASP.NET, Tema) ed un tema al suo interno (che in realtà è anch’esso una cartella).A questo punto è possibile inserire un elemento costituente del tema (CSS, skin o altro) tramite il menu SitoWeb, Aggiungi nuovo elemento (Figura 4).Vediamo ora, una volta realizzato un tema, come è possibile applicarlo al sito o ad una singola pagina.

Impostare il tema per l’intero sito signifi-ca che tutti gli stili definiti nel tema sono applicati a tutti i controlli di ogni pagina, a meno che non si esegua l’override del tema per una singola pagina.Impostare il tema per una singola pagina comporta, invece, l’applicazione di tutti gli stili del tema a tutti i controlli della pagina.Per impostazione predefinita, le proprie-tà e le impostazioni definite in un tema, vanno a sovrascrivere le proprietà, even-tualmente, impostate sui controlli a design time. È possibile impostare un tema come tema del foglio di stile, il che comporta che le impostazioni del tema verranno applica-te alle proprietà dei controlli che non sono state definite a design-time.Per impostare un tema in un sito è suffi-ciente intervenire nel file web.config ed inserire l’attributo theme del tag pages:

<configuration>

.

.

<system.web>

.

.

<pages Theme=”MioTema” />

.

.

</system.web>

.

.

</configuration>

In questo modo tutte le pagine del sito avranno il tema MioTema.Per applicare il tema come tema del foglio di stile si utilizza l’attributo StyleSheetThe-me anziché l’attributo Theme:

<configuration>

.

.

<system.web>

.

.

WEB

Page 27: v2006 05 vbj71

27N. 71 - Settembre/Ottobre 2006 VBJ

<pages StyleSheetTheme=”MioTema” />

.

.

</system.web>

.

.

</configuration>

Se si desidera che il tema sia applicato solo ad un sottoinsieme delle pagine del sito si può procedere raggruppando le pa-gine al di sotto di una cartella e mettendo all’interno di essa un web.config con le impostazioni sul tema oppure creare un elemento <location> nel web.config e spe-cificare la cartella:

<configuration>

.

<location path=”~/Sezione1”>

<system.web>

<pages Theme=”MioTema1” />

</system.web>

</location>

<location path=”~/Sezione2”>

<system.web>

<pages Theme=”MioTema2” />

</system.web>

</location>

.

</configuration>

Per applicare un tema ad una singola pagi-na, invece, si utilizzano gli attributi Theme o StyleSheetTheme della direttiva @Page.Nel caso in cui il tema contenga delle inter-facce, queste vengono applicate a tutte le istanze dei controlli delle pagine del sito (o della pagina se si tratta di un tema su una pagina singola).Per disattivare l’utilizzo di un tema per una pagina o per un controllo si può pro-cedere in due modi: o si definisce il tema come tema del foglio di stile e si impostano le proprietà della pagina o del controllo oppure si disabilita l’utilizzo del tema valorizzando l’attributo EnableTheming della direttiva @Page (@Master se si tratta

di una pagina Master) o la proprietà Ena-bleTheming del controllo.Per applicare un tema a livello di codice si procede in maniera simile a quanto visto per le Master page: nel caso di una pagina aspx, si deve impostare la proprietà Theme dell’oggetto Page nel gestore dell’evento PreInit. Ad esempio, supponiamo che il nome del tema da impostare sia contenuto nella variabile di sessione Tema, avremo:

Public Sub Page_PreInit(ByVal Sender As Object, ByVal e

As EventArgs)

Dim nomeTema As String

nomeTema = Session(“Tema”)

If not nomeTema is Nothing Then

Page.Theme = nomeTema

End If

End Sub

Per quanto riguarda un tema del foglio di stile, invece, è necessario riscrivere la proprietà StyleSheetTheme della pagi-na. Nell’esempio precedente avremo:

Public Overrides Property StyleSheetThema() As String

Get

Return Session(“Tema”)

End Get

Set(ByVal value As String)

End Set

End Property

I temi possono includere anche elementi grafici o altre risorse (script, audio, applet e quant’altro) che generalmente si trovano nella stessa cartella dei file di interfaccia o in una sottocartella del tema.In un tema possono essere impostate tutte quelle proprietà delle pagine e dei controlli che sono relative all’aspetto o al contenuto statico ma non è possibile im-postare quelle proprietà che specificano il comportamento del controllo, come ad esempio il CommandName per un bottone di una DataGrid.Le proprietà impostabili da tema sono so-

WEB

Page 28: v2006 05 vbj71

28 VBJ N. 71 - Settembre/Ottobre 2006

lamente quelle che hanno l’attributo The-meableAttribute impostato su True.

Le interfacceIl concetto di interfaccia, brevemente ac-cennato nel precedente paragrafo, unito a quello delle Master page e dei temi, per-mette di completare la gestione dell’aspet-to grafico di un sito.Un’interfaccia è un modo per impostare le proprietà dei controlli lato server senza do-ver mettere mano al codice delle pagine o delle classi che sono nel code behind.I file di interfaccia sono file di testo con estensione .skin al cui interno, in maniera molto simile al codice presente nelle pagi-ne aspx, vengono riportate le proprietà ed i valori da impostare dei controlli del sito.Possiamo definire le interfacce come dei CSS lato server.Per esempio supponiamo di avere il se-guente file di interfaccia:

<asp:label runat=”server”

backcolor=”blue”

forecolor=”white”

font-name=”Arial”/>

Questo fa si che tutti i controlli label delle pagine che hanno associato il tema che contiene l’interfaccia, avranno il backcolor, il forecolor e il font impostato con i valori definiti nel file.In pratica è come se, da codice, si avesse:

Label1.BackColor = Drawing.Color.Blue

Label1.ForeColor = Drawing.Color.White

Label1.Font.Name = “Arial”

È possibile associare un identificativo alla definizione di interfaccia valorizzando l’at-tributo SkinID:

<asp:label runat=”server” SkinID=”labelSpeciale”

backcolor=”blue”

forecolor=”white”

font-name=”Arial”/>

In questo modo si può applicare l’in-terfaccia in maniera selettiva (e non indistintamente a tutti i controlli) impo-stando la proprietà SkinID delle istanze del controllo a cui si vuole associare l’in-terfaccia.Per impostare da codice l’interfaccia di un controllo è necessario valorizzare la proprietà SkinID dello stesso nel gestore dell’evento PreInit della pagina che lo ospita.

ConclusioniProbabilmente strumenti come Master page, temi ed interfacce non sono in-dispensabili per la realizzazione di siti coerenti (visto che fino ad ora se ne è fatto a meno), ma permettono di gesti-re, in maniera quasi indolore, eventuali cambiamenti grafici che, inevitabilmente, hanno i siti di un certo livello. Grazie al-l’utilizzo sensato ed oculato di queste tre nuove caratteristiche del framework si può anche riuscire a dare una sorta di per-sonalizzazione all’utente (impostando di-namicamente una o tutte e tre) che rende l’interazione sicuramente più coinvolgen-te. Ben venga, quindi, l’utilizzo di queste nuove funzionalità, anche se inizialmente possono sembrare inutilmente complicate e prolisse.

Bibliografia e Riferimenti[1] Dino Esposito – “ASP.NET 2.0 Program-mazione avanzata”, Mondadori Informati-ca, 2006[2] Dino Esposito – “Introducing Microsoft ASP.NET 2.0”, Microsoft Press, 2005[3] George Shepherd – “ASP.NET 2.0 passo per passo”, Mondadori Informatica, 2006[4] http://www.aspitalia.com[5] http://www.weekit.it[6] http://www.dotnethell.it[7] http://www.microsoft.it

WEB

Page 29: v2006 05 vbj71
Page 30: v2006 05 vbj71

30 VBJ N. 71 - Settembre/Ottobre 2006

InteroperabilitàCOM e .NET

di Maurizio Mammuccini

In questa conclusiva seconda puntata viene esposto lo strato d’interoperabilità COM/.NET che permette l’utilizzo di com-

ponenti assembly .NET da parte di client COM, così da concludere quanto esposto nella prima puntata ([11]). A mio avviso questa è una parte abbastanza poco trattata nella letteratura del settore in quanto si pensa di non dover mai manutenere applicativi COM impiegando componenti binari realizzati aderendo a standard industriali di generazione successiva; o perlomeno molti non lo ritengono conveniente. Invece credo che l’aggiunta di componentistica .NET in applicativi COM sia un ottimo mezzo per procedere incrementalmente e gradualmente ad una reingegnerizzazione di procedure COM ormai assestate che necessitano di essere portate sulla piattaforma .NET.Nella mia attività di formatore mi sono accorto che diverse aziende, a causa di motivi di vario tipo, tendono a non riscrivere le loro vecchie ap-plicazioni COM in .NET o comunque tendono a ritardare i tempi di una tale riscrittura.

Comunque queste aziende sono attratte dalla potenza straordinaria del .NET Fra-mework e gradirebbero poter aggiungere già alle loro appli-cazioni un qualche manufatto funzionale scritto in .NET, prima di una completa ripro-gettazione e riscrittura delle medesime.Ebbene in questo articolo esporrò anche come sia pos-sibile realizzare ciò, ossia come si possano manutenere in .NET vecchi applicativi COM, orientando l’esposizio-ne soprattutto al confronto del modello di eventi .NET in COM (che rimane l’argomen-to centrale dell’articolo). Al termine dell’articolo inoltre elencherò delle linee guida, ossia delle considerazioni finali sulla interoperabilità COM e .NET che spero possa-no esser d’aiuto a chi si trova a manutenere vecchi appli-cativi COM e sta pensando ad una loro migrazione verso .NET.

Comprendere e confrontare i modelli di eventi in .NET ed in COM non solo può aiutarci a specializzare la nostra conoscenza del fra-mework .NET stesso ma può essere utile per un miglior riutilizzo event-driven, in applicazioni.NET, di software binario COM già

Seconda puntata

ENTERPRISE

Maurizio Mammuccini ha esperienza decennale nella pro-gettazione e sviluppo di software. Dedica particolare atten-zione alle tecnologie di calcolo distribuito. Utilizza sin dalle primissime versioni Visual Studio di Microsoft. Attualmente è formatore per PCSNet Umbria SRL a Perugia e consulente per aziende del settore informatico. È MCSD for VS6 - MCDBA for Sql Server 2000 - MCAD for .NET - MCSD for .NET ed MCT. Risiede in Umbria.

COMNET2

Page 31: v2006 05 vbj71

31N. 71 - Settembre/Ottobre 2006 VBJ

Approfondimenti sul CCWVediamo un po’ più in profondità l’organiz-zazione interna del CCW ed a tal proposito invito il lettore a rivedere l’esposizione di COM in [9] o l’introduzione a COM in [11].Innanzitutto bisogna osservare che il CCW è allocato (costruito) runtime nell’heap non gestito e quindi non è soggetto a garbage collection, ecco dunque spiegato perché il CCW gestisca un contatore di riferimenti alla maniera di COM.Il CCW dovendo agire proprio come un ge-nuino componente COM espone un’inter-faccia IUnknown ed un’interfaccia IDispa-tch. A tal proposito si tenga presente che il CCW implementa sempre le interfacce COM elencate nella Tabella 1.Il CCW, per i client COM di un assembly .NET, è in grado di operare come un com-ponente COM classico, proprio perché im-plementa tali interfacce.Inoltre, operando come un componente COM, mette a disposizione dei client il clas-sico meccanismo di puntamento alle inter-facce COM, necessario al funzionamento dei client che vogliono invocare le funzionalità dell’assembly .NET passando per il CCW.Prima di andare avanti, vorrei qui ricor-dare un fatto notevole circa gli assembly .NET. Gli assembly .NET sono il risultato della compilazione in MSIL (Microsoft Intermediate Language) di tipi .NET (es. classi, interfacce, … )Dentro l’assembly compilato viene scritta una sezione chiamata metadati, alle volte

CCW – COM Callable WrapperIn [11] abbiamo visto come l’ar-chitettura d’interoperabilità COM/.NET renda possibile l’esposizione di componenti COM a potenziali utilizzatori .NET ricorrendo ai po-tentissimi RCW (Runtime Callable Wrapper).L’RCW di fatto incapsula il componente COM esponendone i servizi via .NET.In modo simmetrico e con altret-tanta potenza ma con evidenti dif-ferenze è possibile incapsulare un componente assembly .NET ed esporlo a client COM ricorrendo ai CCW (COM Cal-lable Wrapper).Ribadiamo per i CCW quanto esposto in [11] per gli RCW, ma in modo simmetrico. Questi oggetti CCW svolgono un servizio basilare in tutta l’architettura d’interope-rabilità effettuando il marshaling (smi-stamento) degli argomenti trasferiti nelle chiamate a metodo tra il codice non gestito e quello gestito, verso l’oggetto .NET di cui effettuano il wrapping.Dunque i CCW sono oggetti che hanno la capacità di varcare i confini tra il codice non gestito e quello gestito, preoccupan-dosi di tutti i meccanismi di basso livello come appunto la trasformazione dei tipi dato (Figura 1); ciò è dovuto al fatto che COM è stato realizzato prima di .NET ed il codice COM non viene supportato nativa-mente dall’infrastruttura .NET.Il CCW inoltre implementa tutta una serie di operazioni di basso livello tipiche di un componente COM, come ad esempio il conteggio dei riferimenti per gestirsi il life-time in memoria. Allorquando, infatti, il conteggio dei riferimenti al CCW ha rag-giunto lo zero, allora il CCW rilascia una referenza interna all’istanza dell’assembly .NET e viene deallocato.Insomma dal lato del codice non gestito, il CCW rende visibile l’assembly .NET come un comune componente COM con tutte le funzionalità tipiche dei compo-nenti COM.

ENTERPRISE

Figura 1 Il CCW rende visibile l’assembly .NET come un comune componente COM, con tutte le funzio-nalità tipiche di tali componenti

Page 32: v2006 05 vbj71

32 VBJ N. 71 - Settembre/Ottobre 2006

paragonata alle librerie dei tipi COM (tlb), che intende descrivere i tipi compilati nel-l’assembly.Di fatto questa assimilazione della sezione metadati ad una libreria dei tipi è un po’ fuorviante, essendo le sezioni metadati di assembly .NET molto più ricche delle type library.Dentro una sezione metadati infatti trovia-mo:

• la descrizione dell’assembly (nome, versio-ne, cultura, dipendenza dell’assembly da altri assembly…)

• la descrizione dei tipi (interfacce, classi… )• attributi personalizzati (forniti dall’utente,

forniti dal framework… )

Il grande vantaggio dei metadati è che permettono all’assembly una propria au-tonomia di descrizione e di funzionamento che lo svincola da altri tipi di supporto sia a runtime che a tempo di programmazione.Dal punto di vista del nostro argomento i

metadati nell’assembly .NET sono utilis-simi in quanto sono alla base del mecca-nismo che porta alla costruzione del CCW per l’assembly. Questo meccanismo passa primariamente per la generazione di una libreria dei tipi (tlb) che si rende neces-saria in quanto i client COM non possono accedere direttamente alle informazioni sui tipi fornite dagli assembly.Concludiamo queste osservazioni d’ap-profondimento sul CCW evidenziando un comportamento strutturale molto impor-tante. Il CCW è prodotto in modo unico per l’assembly .NET wrappato indipenden-temente dal numero dei client COM che accedono alle funzionalità dell’assembly (Figura 3).

Regole e norme all’interoperabilità di COM

Cercando di realizzare un assembly .NET per un suo utilizzo in COM bisogna tener conto di alcune regole ed alcune norme che riassumiamo per brevità qui di seguito. Ciò

Tabella 1 Interfacce COM sempre implementate da un CCW

Interfacce COM sempre implementate da un CCW

IUnknownFornisce l’implementazione standard dell’interfaccia IUnknown con cui il client COM gestisce la durata del CCW e provvede all’assegna-zione forzata.

IDispatch Fornisce un meccanismo per l’associazione tardiva al tipo.

IProvideClassInfoConsente ai client COM di ottenere l’accesso all’interfaccia ITypeInfo implementata da una classe gestita.

ISupportErrorInfo

Consente a un client COM di determinare se l’oggetto gestito supporta l’interfaccia IErrorInfo. Se sì, consente al client di ottenere un puntatore all’ultimo oggetto di eccezione. Tutti i tipi gestiti sup-portano l’interfaccia IErrorInfo.

IErrorInfoFornisce una descrizione testuale dell’errore, la relativa origine, un file della Guida, un contesto della Guida e il GUID dell’interfaccia che ha definito l’errore (per le classi .NET è sempre GUID_NULL).

ITypeInfoFornisce per le classi le stesse informazioni sul tipo che fornisce Tlbexp.exe.

ENTERPRISE

Page 33: v2006 05 vbj71

33N. 71 - Settembre/Ottobre 2006 VBJ

al fine di ottenere il mas-simo vantaggio dall’inte-roperabilità di COM.

1. Le classi scritte in un assembly .NET debbono avere un costruttore di default (senza parame-tri).Infatti COM da parte sua non dispone del concetto di costruttore, quindi quando il wrap-per CCW istanzia per un client COM una classe .NET, l’unico costruttore che può invocare è quello di default, ossia senza parametri.

2. Sono visibili a COM solo i tipi pubblici scritti nell’assembly .NET.Solo i tipi pubblici di un assembly ven-gono registrati ed esportati nella libreria dei tipi. Di conseguenza saranno visibili in COM solo i tipi pubblici.

3. Metodi, proprietà, campi ed eventi devo-no avere ambito di visibilità pubblico.

È necessario che i membri di un tipo pub-blico .NET, se sono destinati ad essere vi-sibili a COM, siano anch’essi pubblici.Di default tutti i tipi pubblici e tutti i membri pubblici di un tipo pubblico sono visibili a COM. Quest’ultima situa-zione può essere modificata utilizzando l’attributo ComVisibleAttribute che si trova nel namespace System.Runtime.InteropServices. Infatti tramite l’attributo ComVisibleAttribute è possibile stabilire l’accesso o meno a COM di un tipo gestito o di un membro specifico entro un tipo gestito o di tutti i tipi all’interno di un assembly .NET. Nel successivo pezzo di codice (in C# e VB.NET) ad esempio si vieta la visibilità a COM di un intero assembly .NET, il cui codice deve essere collocato nel relativo file AssemblyInfo:

C#// esempio di utilizzo dell’attributo ComVisible per un

assembly

using System.Runtime.InteropServices;

[assembly: ComVisible(false)]

VB.NET‘ esempio di utilizzo dell’attributo ComVisible per un

assembly

Imports System.Runtime.InteropServices

<Assembly: ComVisible(True)>

Mentre nel successivo pezzo di codice ad esempio si vieta la visibilità a COM di un metodo di una classe .NET, mentre si per-mette la visibilità dell’intera classe (sempre però con l’esclusione del metodo nascosto); il codice deve essere collocato nel relativo file di definizione della classe:

C#// esempio di utilizzo dell’attributo ComVisible per una

classe

[ComVisible(True)]

class ClassForInteroperability

Public Sub New()

‘costruttore di default, deve essere presente

End Sub

<ComVisible(False)> _

Figura 2 Univocità del CCW rispetto ai client COM

ENTERPRISE

Page 34: v2006 05 vbj71

34 VBJ N. 71 - Settembre/Ottobre 2006

Public Function HiddenMethod() As String

Return “”

End Function

Public Function MyOtherMethod() As String

‘questo metodo è visibile per default a COM

Return “Ciao,Mondo!”

End Function

End Class

VB.NET‘ esempio di utilizzo dell’attributo ComVisible per una

classe

<ComVisible(True)> _

Class ClassForInteroperability

Public Sub New()

‘costruttore di default, deve essere presente

End Sub

<ComVisible(False)> _

Public Function HiddenMethod() As String

Return “”

End Function

Public Function MyOtherMethod() As String

‘questo metodo è visibile per default a COM

Return “Ciao,Mondo!”

End Function

End Class

In questi esempi di codice abbiamo visto l’applicazione di un fondamentale attribu-to per l’interoperabilità di COM ma ve ne sono altri di notevole importanza che al momento nel nostro articolo non trattia-mo. Invito comunque l’attento lettore ad approfondirne la conoscenza, poiché l’uti-lizzo di attributi nella fase di realizzazione del manufatto assembly .NET permette di intervenire in modo determinante sul mec-canismo di conversione eseguito dalle API e dagli strumenti di interoperabilità COM.

4. Nessun membro nella classe .NET può essere statico.

Questo è un punto molto delicato. Si ri-cordi ([9] od [11]) che in COM l’accesso al codice binario di un componente passa per la valorizzazione di un indirizzo di un’interfaccia esposta da questi. Il CCW che a tutti gli effetti funge da componen-te COM relativamente a client COM di un componente gestito, non ha quindi di suo un meccanismo che permetta ai client di distinguere tra una classe ed una sua istanza. Dunque non c’è suppor-to al concetto di membro statico da parte dei CCW.

5. È buona norma che le classi gestite per l’interoperabilità implementino le inter-facce in maniera esplicita.Mi viene da dire che ciò dovrebbe co-munque essere sempre vero in una sana ottica di progettazione e sviluppo OOP (Object-Oriented), ma in funzione del-l’interoperabilità con COM ciò assume maggior evidenza.Anche se l’interoperabilità COM dispone di un suo meccanismo per generare in modo automatico un’interfaccia conte-nente tutti i membri della classe e i mem-bri della relativa classe base, è preferibile fornire interfacce esplicite. L’interfaccia generata automaticamente è definita in-terfaccia della classe (class interface).

Esposizione di assembly .NETall’interoperabilità di COM

Ci preoccuperemo in questa sezione di come si possano esporre assembly .NET al-l’interoperabilità di COM, tenendo a mente quanto detto nelle pagine precedenti. Nel paragrafo precedente abbiamo dato norme e regole di cui tener conto quando si pro-getta un assembly per l’interoperabilità, in funzione di un suo impiego in applicativi COM. In questa sezione dell’articolo in-vece ci occupiamo di come fattivamente scrivere il codice di tipi gestiti per COM. Ci accorgeremo che .NET fornisce un discre-to numero di attributi di programmazione, alcuni dei quali debbono essere conosciuti.

ENTERPRISE

Page 35: v2006 05 vbj71

35N. 71 - Settembre/Ottobre 2006 VBJ

I meccanismi di esposizione fisica di un as-sembly gestito a COM sono numerosi. Per esporre un assembly a COM possiamo:

• sfruttare l’IDE di Visual Studio.NET• eseguire l’operazione manualmente

Tutti i meccanismi di esposizione a COM di un assembly gestito comunque passano per la produzione di una libreria binaria dei tipi, una TLB, ciò per ovvie necessità di COM ([9] od [11]).Nell’IDE di Visual Studio.NET il menu Progetto contiene la voce Proprietà di Nome_Progetto, al click su questa voce compare la finestra che riassume visual-mente tutte le proprietà impostate per Nome_Progetto. Se vogliamo che l’IDE alla produzione dell’assembly DLL produca la TLB con la traduzione COM dei tipi gestiti e la registri nel registro di sistema, assieme ad altre utili informazioni sull’assembly gestito per COM, dovremo impostare a true il flag Registra per interoperabilità COM presente alla voce Generazione in Proprietà di Configurazione nella fine-stra delle proprietà. Comunque indipen-dentemente dalla strada percorsa per esporre a COM l’assembly gestito, è bene produrre una chiave univoca con cui fir-mare l’assembly; a tal scopo si utilizzi l’utility sn.exe fornita gentilmente dalla Microsoft col framework .NET. Dopo aver impostato a true il flag Registra per inte-roperabilità COM possiamo utilizzare la libreria dei tipi risultante dalla produzio-ne del client COM del nostro assembly gestito.Si faccia ben attenzione che sebbene .NET Framework non prediliga passare per il Re-gistro di sistema, la cosa diventa necessa-ria quando si lavora con l’interoperabilità di COM, in quanto quest’ultimo sfrutta il Registro.L’esportazione manuale della libreria dei tipi relativa all’assembly gestito passa per due utilità fornite col framework .NET:

1. TlbExp.exe2. RegAsm.exe

TlbExp.exe è l’utilità di esportazione della libreria dei tipi relativa all’assembly gesti-to e genera una classica libreria di tipi al cui interno sono descritti i tipi definiti in un assembly .NET.La sintassi canonica utilizzata di solito per produrre la TLB dall’assembly ge-stito è:

tlbexp [path]/nome_assembly /out: [path]/nome_tlb

dove nome_assembly è il nome dell’assem-bly gestito comprensivo della sua estensio-ne dll e nome_tlb è il nome della libreria dei tipi comprensiva della sua estensione tlb.RegAsm.exe è l’utility di registrazione degli assembly gestiti nel Registro di sistema. Legge la sezione metadata al-l’interno di un assembly e aggiunge al Registro di sistema le voci necessarie per consentire ai client COM di istan-ziare classi di .NET Framework in modo trasparente. Quando una classe gestita è stata registrata nel Registro, qualsiasi client COM può utilizzarla come se si trattasse di una comune classe COM. La classe deve essere registrata una sola volta, al momento dell’installazione del-l’assembly nella macchina target. Si fac-cia attenzione che non è possibile istan-ziare da COM classi d’assembly finché tali classi non siano state effettivamente registrate.La sintassi canonica utilizzata di solito per registrare un assembly gestito è:

regasm [path]/nome_assembly

od

regasm [path]/nome_assembly /regfile: [path]/nome_

assembly.reg

ENTERPRISE

Page 36: v2006 05 vbj71

36 VBJ N. 71 - Settembre/Ottobre 2006

dove nome_assembly è il nome dell’assembly gestito comprensivo della sua estensione dll ed nome_assembly.reg è il file contenente tutte le voci di registro necessarie al sistema, comprensiva della sua estensione tlb.Volendo che i nostri client COM possano eseguire codice event-driven nell’accedere a classi gestite, relativamente a notifiche emesse da queste ultime, dobbiamo racco-gliere gli eventi entro un’opportuna inter-faccia sink d’eventi (event sink interface) in codice gestito.

C#// esempio di codice

[ComVisible(true),GuidAttribute(“82e42c55-fdd7-468d-a3cf-

363d0d067588”),

InterfaceTypeAttribute(ComInterfaceType.

InterfaceIsIDispatch)]

public interface IOperazioni

{

//lista d’eventi

void ChangeValueEvent(bool b);

}

VB.NET‘ esempio di codice

<ComVisible(true),GuidAttribute(“82e42c55-fdd7-468d-a3cf-

363d0d067588”), _

InterfaceTypeAttribute(ComInterfaceType.InterfaceIs

IDispatch)> _

Public Interface IOperazioni

‘lista d’eventi

Sub ChangeValueEvent(b As Boolean)

End Interface

Le interfacce pubblicano gli eventi noti-ficati dalla sorgente gestita e che il client dovrà, se vuole, gestire.Come vediamo vengono utilizzati due attributi fondamentali: GuidAttribute e InterfaceTypeAttribute. GuidAttribute permette l’assegnazione di un UUID d’interfaccia all’interfaccia IO-perazioni quando questa viene esportata nella libreria dei tipi, così come richiede COM.La sintassi dell’attributo di programmazio-ne GuidAttribute è:

C#// esempio di codice

[GuidAttribute(“82e42c55-fdd7-468d-a3cf-363d0d067588]

VB.NET‘ esempio di codice

< GuidAttribute(“82e42c55-fdd7-468d-a3cf-363d0d067588”)>

Ricorrendo all’utility UUIDGEN.exe fornita con l’SDK di Microsoft Visual C++ 6.0 possiamo ricavare i GUID d’in-terfaccia da assegnare come argomento

Tabella 2

ComInterfaceType

InterfaceIsDualIndica che l’interfaccia esposta a COM è un’interfaccia duale, che consente sia l’associazione anticipata sia l’associazione tardiva. In-terfaceIsDual è il valore di default.

InterfaceIsDispatchIndica che l’’interfaccia esposta a COM è un’ interfaccia dispatch che consente solo l’associazione tardiva.

InterfaceIsIUnknownIndica che l’interfaccia esposta a COM è un’ interfaccia derivata dal-la IUnknown che consente solo l’associazione anticipata.

ENTERPRISE

Page 37: v2006 05 vbj71

37N. 71 - Settembre/Ottobre 2006 VBJ

C++ 6.0 possiamo ricavare i GUID d’in-terfaccia da assegnare come argomento all’attributo GuidAttribute. L’attributo InterfaceTypeAttribute serve a specificare a COM se, l’interfaccia esposta a COM è:

• duale• dispatch• solo IUnknown

Si può specificare ciò a COM ricorrendo all’enumerazione ComInterfaceType (Ta-bella 2). È importante che a livello d’assembly siano dichiarate le sintassi dei delegati d’evento uguali a quelle dei metodi d’evento listati nell’interfaccia sink.Viene definita la classe gestita ed al suo interno vengono dichiarati gli eventi da notificare ai client servendosi dei delegati dichiarati.La classe è dichiarata con un attributo che fa riferimento all’interfaccia sink d’eventi che il client COM dovrà imple-mentare in uno specifico oggetto sink d’eventi ([11]). Se lavoriamo con client COM Visual Basic 6 questo oggetto è realizzato dal compilatore previa dichia-razione con WithEvents del riferimento all’istanza della classe gestita di cui verrà creato runtime il CCW.

C#// esempio di codice

[ComVisible(true),ComSourceInterfaces(“SAMPLELib.I

Operazioni”)]

public class Operazioni

{

// …

}

VB.NET

‘ esempio di codice

<ComVisible(true),ComSourceInterfaces(“SAMPLELib.

IOperazioni”)> _

Public Class Operazioni

‘…

End Class

L’attributo ComSourceInterfaces lista un elenco di interfacce esposte come origini di eventi COM per la classe gestita. L’uti-lizzo più frequente di questo attributo prevede l’elenco delle interfacce sorgenti d’evento entro stringhe separate dalla virgola.Il client COM a questo punto non fa altro che referenziare la libreria dei tipi espor-tata e registrata ed utilizzarne i tipi nel proprio codice. Il client non avrà perce-zione di passare tramite un proxy CCW quando effettua le chiamate al metodo della classe gestita o nel ricevere da que-sta delle notifiche d’evento, che volendo può gestire.

ConclusioniRitengo che questa seconda puntata abbia esposto un aspetto dell’interoperabilità COM/.NET abbastanza sentito da chi at-tualmente sta reingegnerizzando vecchie procedure COM tuttora efficienti, avendo presente la compatibilità con il Framework .NET.Lo scopo è quello di realizzare classi ge-stite in integrazione e manutenzione al vecchio codice COM, non producendo più codice COM (in Visual Basic 6, in Visual C++ 6) ma scrivendolo direttamente in un linguaggio .NET compatibile. Mi spie-go meglio. Se la manutenzione della vec-chia applicazione COM richiede l’aggiun-ta di nuove funzionalità, queste devono essere scritte in binario .NET anziché nelle vecchie DLL COM. I client COM secondo quanto visto possono ugualmen-te utilizzarle via CCW ed ottenendo così l’indubbio vantaggio che si cominciano ad accumulare nuovi manufatti binari .NET da riutilizzare direttamente tal quali quando l’applicazione verrà rein-

ENTERPRISE

Page 38: v2006 05 vbj71

38 VBJ N. 71 - Settembre/Ottobre 2006

Anche in questa seconda conclusiva pun-tata voglio dire grazie alle opere citate in bibliografia i cui autori mi hanno aiutato a comprendere e poi a mettere in pratica i concetti della moderna programmazio-ne distribuita a componenti, secondo gli standard industriali della Microsoft, invitando l’attento lettore ad approfon-dire su questi libri i concetti discussi nel presente articolo, sperando che oltre al-l’acquisizione di tecniche e metodologie, egli possa percepire l’intrinseca bellezza dei contenuti concettuali.

Bibliografia e Riferimenti[1] Jeffrey Richter – “Microsoft .NET Pro-grammazione avanzata”, Mondadori In-formatica, 2002[2] Julian Templeman e John Paul Muel-ler – “COM programming with Microsoft .NET”, Microsoft Press, 2003[3] Guy Eddon ed Enry Eddon – “Inside Distributed COM”, Mondadori Informati-

ca, 1998[4] George Sheperd e Brad King – “Inside ATL”, Mondadori Informatica, 1999[5]_Jeffrey Richter, Francesco Balena – “Programmazione avanzata con Micro-soft Visual Basic .NET” Mondadori Infor-matica, 2002[6]_http://msdn.microsoft.com/library/default.asp?url=/library/en-us/csref/html/vcrefthedelegatetype.asp[7]_http://msdn.microsoft.com/library/default.asp?url=/library/en-us/csref/html/vcwlkeventstutorial.asp[8]_http://msdn2.microsoft.com/en-us/library/75s611wc.aspx[9]_E. Deana – “IUnknown, CLSID, IDispatch,IID”, Visual Basic Journal n. 29[10] M. Mammuccini – “ .NET: Delegate e mo-dello di eventi”, Visual Basic Journal n. 66[11] M. Mammuccini – “Interoperabilità COM e .NET” (1a puntata), Visual Basic Journal n. 69

ENTERPRISE

Page 39: v2006 05 vbj71
Page 40: v2006 05 vbj71

40 VBJ N. 71 - Settembre/Ottobre 2006

Invocazione di web service da VB6 Un approccio semplificato

di Scott Swigart, Swigart Consulting LLC

I siti web espongono ogni sorta di informazio-ni utili. Con Amazon, si possono visualizzare le classifiche dei testi e effettuare acquisi-

ti; su Google, si possono effettuare ricerche sul World Wide Web; con MapPoint, si possono ricer-care indirizzi e ottenere indicazioni; e attraverso eBay, si può acquistare o vendere, praticamen-te… di tutto (http://www.dotcomscotland.co.uk/weirdsites/ebay/eBay1.htm).Il problema con i siti web è che non espongo-no informazioni in un modo facile da consu-mare per un’applicazione. Ad esempio, si po-trebbe volere che i propri agenti del servizio clienti abbiano un’applicazione che permetta loro di localizzare il punto vendita più vicino, in modo da fornire indicazioni ai clienti che chiamano. Realizzare un’applicazione che setacci a video MapPoint o MapQuest sareb-be difficile, e si potrebbe corrompere in ogni

momento se questi siti web subiscono delle modifiche.La risposta è l’utilizzo dei web service. I web service permettono tipicamente a un’applicazione di effettuare richieste via Web, e piuttosto che ottenere in risposta i dati come documento HTML, i dati vengono restituiti in formato XML. Ciò agevola notevolmente l’applicazione nel consumare le informazio-ni. I web service sono emer-si come il mezzo con cui le applicazioni comunicano fra loro. In alcuni casi, i sistemi legacy backend vengono av-volti da web service per poter esporre facilmente dati e fun-zionalità al resto dell’azienda. In altri casi, i provider Web-based (come quelli elencati prima) introducono un web service per permettere l’ac-cesso da programma ai dati e alle funzionalità che forni-scono correntemente ai Web browser.

Web ServiceCome realizzare un’applicazione VB6 che scarica immagi-ni da satellite di un determinato indirizzo di una strada.

Scott Swigart fornisce consulenza alle aziende su come uti-lizzare al meglio l’attuale tecnologia e prepararsi al domani. A tal riguardo, Scott è un orgoglioso collaboratore del sito VB Fusion, dove offre informazioni e strategie di reale utilizzo per gli sviluppatori VB che vogliono realizzare il maggior numero di funzionalità con il minimo sforzo. Scott è anche un Microsoft MVP, ed è coautore di numerosi libri e articoli, ed è contattabile all’indirizzo email [email protected].

VB6

© 2006 Microsoft Corporation. All rights reserved

Page 41: v2006 05 vbj71

41 N. 71 - Settembre/Ottobre VBJ

Basic .NET può ricavare la sottoimmagine e convertirla in una bitmap con una sola riga di codice. E può anche assemblare facilmente le sottoimmagini per ricavare l’immagine completa. Infatti, il più delle volte si vedrà che il modo migliore per in-vocare un web service da Visual Basic 6 è scrivere un po’ di codice Visual Basic .NET per effettuare l’invocazione, e restituire i risultati in COM standard che Visual Basic 6 può consumare.

I web service di geocodificaIl primo passo è convertire un indirizzo di una strada in coordinate latitudine e lon-gitudine richieste da TerraServer. Ci sono due possibili alternative per farlo. Il modo “migliore” è utilizzare qualcosa di simile al web service MapPoint. Si tratta di un web service altamente affidabile fornito da Microsoft che può convertire rapidamente un indirizzo in una coppia di valori latitu-dine e longitudine (un processo noto come “geocodifica”). MapPoint è concepito come servizio ad alte prestazioni, scalabile e suf-ficientemente affidabile da poter dipende-re da esso per applicazioni mission-critical. Tuttavia, MapPoint ha due svantaggi che

L’applicazioneIn questo articolo, intendo realizzare un’applicazione che scarica delle immagi-ni riprese da satellite di un determinato indirizzo di una strada. So per certo che le foto da satellite sono disponibili per mezzo del web service TerraServer (http://www.terraserver.com). E so anche che si può convertire un indirizzo di una strada in una coppia di coordinate latitudine/longitudine per mezzo del web service MapPoint (http://msdn.microsoft.com/mappoint) e di Geocoder, pertanto so che i componenti di base dell’applicazione sono già disponibili.Per prima cosa, mostrerò l’applicazione completa (Figura 1), e poi passeremo a esaminare come il tutto viene realizzato in Visual Basic 6.

DecisioniEsistono due modi per poter invocare un web service da Visual Basic 6. Si può utilizzare il Web Services Toolkit [1], ma quando si invoca un web service che ri-chiede dati complessi [2] ciò comporta la gestione di un bel po’ di XML grezzo. Inol-tre, l’immagine satellitare verrà restituita da TerraServer come serie di sottoimma-gini che è necessario assemblare. Ciò si-gnifica che la propria applicazione riceverà documenti XML con le sottoimmagini codificate in Base64. L’applicazione do-vrà decodificarle e ricucirle in qualche modo per ottenere l’immagine comple-ta. Da Visual Basic 6, ciò non sarebbe una passeggiata.Con Visual Basic .NET, invece, è mol-to semplice. Visual

VB6

Figura 1 Immagine satellitare di un indirizzo da Visual Basic 6 (disponibile come video all’indirizzo [10])

Page 42: v2006 05 vbj71

42 VBJ N. 71 - Settembre/Ottobre

lo rendono non ideale per un utilizzo spo-radico. Innanzitutto, bisogna registrarsi [3] e ottenere uno user ID e una password di valutazione. Queste informazioni di auten-ticazione vengono utilizzate per effettuare le invocazioni al servizio MapPoint. Questo ID gratuito di valutazione vale per 45 gior-ni. Inoltre, dopo aver effettuato la registra-zione, possono essere necessari un paio di giorni per ricevere il proprio ID. Pertanto, intendo fornirvi una applicazione d’esem-pio che si possa semplicemente scaricare e eseguire, senza alcuna registrazione speciale o alcun setup; perciò, oltre a Map-Point, ho previsto una ulteriore opzione per la geocodifica dell’indirizzo.Anche il sito Web Geocoder.us (http://www.geocoder.us/help) fornisce una fun-zionalità per convertire un indirizzo di

una strada in coor-dinate latitudine/longitudine. Se si invia l’indirizzo come parte della query string, il sito restituirà un documento XML contenente le infor-mazioni latitudine/longitudine. Per iniziare, ho creato una classe mol-to semplice per contenere il risul-tato latitudine/longitudine (Lista-to 1).Questa classe contiene semplice-mente le proprietà per la latitudine e della longitudine. Inoltre, la classe contiene gli attri-buti in modo da ve-nire esposta come oggetto COM che può essere utilizza-

to direttamente da Visual Basic 6.Il sito Geocoder può quindi essere utilizza-to per ricercare un indirizzo e popolare un oggetto LatLongInfo con le informazioni (Listato 2).

La cosa che amo di .NET è che semplifica notevolmente l’interazione con il Web. La classe WebClient [4] permette di “aprire” un URL come se fosse un file. Poiché que-sto “file” è un documento XML, posso uti-lizzare semplicemente un XmlTextReader [5] per ricercare nel risultato gli elementi XML con determinati nomi. Una volta tro-vati, basta prendere i valori e metterli nella classe LatLongInfo. Se il sito web non è in grado di risolvere l’indirizzo, questa fun-zione restituirà Nothing; altrimenti, resti-tuirà una classe LatLongInfo che contiene

VB6

Listato 1 Classe VB .NET per contenere le informazioni latitudine/longitudine

<ComClass(LatLongInfo.ClassId, LatLongInfo.InterfaceId, _LatLongInfo.EventsId)> _Public Class LatLongInfo

#Region “COM GUIDs” Public Const ClassId As String = “4362FF28-FFF7-4BCE-B844-8CF4208536AC” Public Const InterfaceId As String = “4A8FC896-6A9D-4F85-8B55-104CE4211829” Public Const EventsId As String = “B9108846-8A2C-4698-831B-D3BC197168C5”#End Region

Public Sub New() MyBase.New() End Sub

Private _lat As Double Public Property Lat() As Double Get Return _lat End Get Set(ByVal Value As Double) _lat = Value End Set End Property

Private _long As Double Public Property [Long]() As Double Get Return _long End Get Set(ByVal Value As Double) _long = Value End Set End PropertyEnd Class

Page 43: v2006 05 vbj71

43 N. 71 - Settembre/Ottobre VBJ

la latitudine e la longitudine della strada richiesta. Ho anche accennato che si potrebbe utiliz-zare il web service MapPoint per ottenere latitudine/longitudine di un indirizzo. In tal caso il codice è ancor più semplice del-l’utilizzo di Geocoder (Listato 3).Le primissime righe di questa funzione servono semplicemente ad impostare lo user ID e la password in modo che ven-gano inviate al web service MapPoint. Per effettuare un’invocazione al web service MapPoint, è necessario che sia già stato creato un account. Senza un account, vo-lendo utilizzare MapPoint invece di Geo-coder, basta registrarsi all’indirizzo https://mappoint-css.partners.extranet.microsoft.com/MwsSignup/Eval.aspx.Il codice crea poi un oggetto Address Map-Point e lo popola con l’indirizzo fornito dal-l’utente. MapPoint dispone di diverse fonti di dati [6] per il Nord America, l’Europa, e via dicendo, e pertanto FindAddressSpeci-fication.DataSourceName_(/library/en-us/

VB6

mappointsdk/HTML/P_Na-mespace_FindAddressSpeci-fication_ataSourceName.asp) è impostato a MapPoint.NA, ad indicare che verrà effet-tuata una ricerca in Nord America.Infine, avviene l’invocazione a FindAddress [7]. Ciò resti-tuisce un oggetto FindResult (http://msdn.microsoft.com/library/en-us/mappointsdk/H T M L / T _ N a m e s p a c e _FindResult.asp) che contiene le informazioni sulla latitu-dine e longitudine. Queste informazioni vengono poi copiate nella classe custom LatLongInfo e restituite.

Una vista… dall’aldilà Adesso che si conosce la latitudine e la longitudi-ne dell’indirizzo richiesto,

TerraServer può restituire un’immagine satellitare di questa locazione geografica. L’immagine è fornita come insieme di sot-toimmagini che è necessario “ricucire” per ottenere l’immagine complessiva. Il codice per farlo è fornito sul sito Web TerraServer [8]. Pertanto, ho utilizzato questo codice e l’ho convertito in Visual Basic .NET. Il codice inizia calcolando semplicemente la larghezza e l’altezza in pixel dell’immagine desiderata (Listato 4).

Visual Basic .NET contiene alcune funzio-ni di supporto che facilitano la conversione dei twip utilizzati da Visual Basic 6 in pixel standard. Ciò permette all’applicazione Visual Basic 6 di passare l’altezza e la larghezza del controllo Image come twip, e il codice Visual Basic .NET è in grado di calcolare le dimensioni in pixel in modo che possa invocare il servizio TerraServer e ottenere correttamente l’immagine.Successivamente, il codice invoca TerraServer con le dimensioni dell’immagine, e TerraSer-

Listato 2 Utilizzo di Geocoder per ricavare latitudine/longitudine di un indirizzo

Public Function AddressToLatLongGeocoder(ByVal address As String) _ As LatLongInfo Dim wc As New WebClient Dim geocodeStream As Stream = _ wc.OpenRead(“http://geocoder.us/service/rest?address=” _ & address)

Dim xr As New XmlTextReader(geocodeStream)

Try Dim ll As New LatLongInfo While xr.Read() If xr.Name = “geo:lat” Then ll.Lat = CDbl(xr.ReadInnerXml) End If If xr.Name = “geo:long” Then ll.Long = CDbl(xr.ReadInnerXml) End If End While

wc.Dispose() Return ll Catch Return Nothing End Try

End Function

Page 44: v2006 05 vbj71

44 VBJ N. 71 - Settembre/Ottobre

ver restituisce un elenco di ID delle sottoim-magini dell’area che si vuole visualizzare:

Dim ts As New TerraService

Dim abb As AreaBoundingBox = ts.GetAreaFromPt(center, _

theme, scale, mapWidth, mapHeight)

AreaBoundingBox contiene un elenco di tutte le sottoimmagi-ni che sarà necessario scarica-re per poter creare l’immagine completa dell’area richiesta. Man mano che ciascuna sot-toimmagine viene scaricata, verrà disegnata in un oggetto Bitmap del .NET Framework, che infine conterrà l’immagi-ne completa. La classe Bitmap [9] rende sorprendentemente agevole disegnare e interagi-re con la grafica. Il seguente listato permette di creare un oggetto Bitmap per contenere

la foto satellitare:

Dim pf As PixelFormat = PixelFormat.

Format32bppRgb

Dim compositeImage As Bitmap = New

Bitmap(mapWidth, mapHeight, pf)

Dim compositeGraphics As Graphics =

Graphics.FromImage(compositeImage)

A questo punto, ciascuna sot-toimmagine può essere scari-cata e disegnata per formare l’immagine composita (Li-stato 5). Nel listato, ciascuna sottoimmagine viene scarica-ta e disegnata nell’immagine composita nella posizione corretta. Al termine del ciclo, l’intera foto da satellite del-l’area richiesta sarà scaricata, e l’oggetto compositeImage conterrà l’immagine comple-ta. La sola cosa che resta da fare è restituire questa imma-gine in modo che possa esse-

re assegnata a un controllo Visual Basic 6 Image o PictureBox.Devo ammettere che la sola parte di questa applicazione che mi ha preoccupato è stata la restituzione dell’immagine a Visual Basic 6. Ero conscio del fatto che la classe Bitmap

VB6

Listato 3 Geocodifica di un indirizzo utilizzando il Web service Map-Point

Public Function AddressToLatLongMapPoint(ByVal address As String, _ ByVal username As String, ByVal password As String) As

LatLongInfo

Dim fs As New MapPoint.FindServiceSoap fs.Credentials = New System.Net.NetworkCredential(username,

password) fs.PreAuthenticate = True

Dim addressInfo As New MapPoint.Address addressInfo.FormattedAddress = address Dim fas As New MapPoint.FindAddressSpecification fas.InputAddress = addressInfo fas.DataSourceName = “MapPoint.NA”

Dim results As MapPoint.FindResults = fs.FindAddress(fas)

Dim ll As New LatLongInfo If results.Results.Length = 0 Then Return Nothing Else With results.Results(0).FoundLocation.LatLong ll.Lat = .Latitude ll.Long = .Longitude End With End If Return ll End Function

Listato 4 Calcolo delle dimensioni dell’immagine in Visual Basic .NET

Public Function DownloadSatteliteImage(ByVal latLong As LatLongInfo, _ ByVal scale As Integer, _ ByVal widthTwips As Double, _ ByVal heightTwips As Double) As Object

Dim center As New LonLatPt Dim theme As Integer Dim mapWidth As Integer Dim mapHeight As Integer

center.Lon = latLong.Long center.Lat = latLong.Lat theme = 1 mapWidth = Compatibility.VB6.TwipsToPixelsX(widthTwips) mapHeight = Compatibility.VB6.TwipsToPixelsY(heightTwips) ...

Page 45: v2006 05 vbj71

45 N. 71 - Settembre/Ottobre VBJ

VB6

.NET e i controlli Image Visual Basic 6 non fossero diret-tamente compatibili, e ritenevo che la conversione della Bitmap in qualcosa che Visual Basic 6 potesse utilizzare fosse qualcosa di non facile. Ho tra-scorso del tempo a cercare delle rispo-ste con Google, cer-cando invocazioni alle API Win32 o librerie che fossero state già scritte. Ma infine, giusto per essere certo che non stavo controllando nel posto più ovvio, ho dato un’occhiata all’oggetto Microsoft.VisualBasic.Compatibility.VB6 di .NET. Si tratta dello stesso oggetto che ci ha fornito la conversione da twip a pixel. Com’era prevedibile, è dota-to di un metodo ImageToIPictureDisp. La proprietà Picture dei controlli Image e Pic-tureBox è un IPictureDisp, pertanto questo metodo ha consentito la conversione con una riga di codice:

Return Compatibility.VB6.ImageToIPictureDisp

(compositeImage)

Da Visual Basic 6, si può invocare il metodo DownloadSatelliteImage, passare la coppia latitudine/longitudine e la dimensione del con-trollo immagine, e ottenere una foto satellitare delle dimensioni corrette (Listato 6).Si può vedere che basta invocare DownloadSate l -liteImage, pas-sando latitudine/longitudine, la scala (quanto si vuole sia ingrandita l’imma-gine), e l’altezza e la larghezza. Il codice

Visual Basic .NET si occupa dell’invocazione a TerraServer e della composizione dell’im-magine completa (Figura 2). L’immagine viene restituita, e può essere semplicemente assegnata alla proprietà Picture del controllo Image Visual Basic 6.

ConclusioniRealizzare questa applicazione solo con Visual Basic 6 sarebbe stato realmente arduo. Per scaricare una pagina Web, avrei dovuto utiliz-zare un controllo Web browser, e poi estrarre le informazioni dal documento. Si tratterebbe di un suicidio in confronto alle semplici classi che il .NET Framework fornisce per questo compito. Per poter invocare i web service sa-rebbe stato necessario il Web Services Toolkit, lasciandomi l’onere di gestire un bel po’ di XML grezzo. E non saprei come avrei dovuto decodificare le sottoimmagini codificate in

Listato 5 Download di ciascuna sottoimmagine e aggiunta all’immagine composita

Dim xStart As Integer = abb.NorthWest.TileMeta.Id.X Dim yStart As Integer = abb.NorthWest.TileMeta.Id.Y For x As Integer = xStart To abb.NorthEast.TileMeta.Id.X For y As Integer = yStart To abb.SouthWest.TileMeta.Id.Y Step -1 Dim tid As TileId = abb.NorthWest.TileMeta.Id tid.X = x tid.Y = y Dim tileImage As Image = Image.FromStream( _ New MemoryStream(ts.GetTile(tid))) compositeGraphics.DrawImage(tileImage, _ (x - xStart) * tileImage.Width - _ CInt(abb.NorthWest.Offset.XOffset), _ (yStart - y) * tileImage.Height - _ CInt(abb.NorthWest.Offset.YOffset), _ tileImage.Width, tileImage.Height) tileImage.Dispose() Next Next

Listato 6 Invocazione di DownloadSatelliteImage da Visual Basic 6

Dim msw As MapServiceWrapper.SatImageServiceSet msw = New MapServiceWrapper.SatImageServiceDim satImage As ObjectSet satImage = msw.DownloadSatteliteImage(latLong, hscrScale.Value, _ imgSatPhoto.Width, imgSatPhoto.Height)Set imgSatPhoto.Picture = satImage

Page 46: v2006 05 vbj71

46 VBJ N. 71 - Settembre/Ottobre

Base64 o come ricucirle assieme. Tuttavia, estendendo Visual Basic 6 con Visual Basic .NET, il tutto è stato real-mente agevole da realizzare. Mi auguro che l’articolo abbia illustrato chiaramente come si può prendere un’applicazione esi-stente Visual Basic 6, per poi estenderla con Visual Basic .NET per poter ottenere informazioni in realtime dai web service. I web service potrebbero essere ospitati nella propria azienda per esporre i sistemi backend, o possono esistere sul Web: ad esempio, Google, eBay, Amazon o Map-Point. Esistono web service che espongono quotazioni di titoli finanziari, informazioni metereologiche, e quasi qualsiasi altro tipo di dati. E, con la combinazione di Visual Basic 6 e di Visual Basic .NET, sono tutti servizi a propria disposizione.

Riferimenti[1]_http://www.microsoft.com/downloads/details.aspx?FamilyId=4922060F-002A-4F5B-AF74-978F2CD6C798&displaylang=en

[2]_http://msdn.microsoft.com/library/en-us/dnxpwst2/html/odc_CmplxTypes.asp[3]_https://mappoint-css.partners.extranet.microsoft.com/MwsSignup/Eval.aspx[4]_http://msdn.microsoft.com/library/en-us/cpref/html/frlrfSystemNetWebClientClassTopic.asp[5]_http://msdn.microsoft.com/library/en-us/cpref/html/frlrfSystemXmlXmlTextReaderClassTopic.asp[6]_http://msdn.microsoft.com/library/d e f a u l t . a s p ? u r l = / l i b r a r y / e n - u s /mappointsdk/HTML/index.asp[7]_http://msdn.micorosft.com /library/en-us/mappointsdk/HTML/M_Namespace_FindServiceSoap_FindAddress.asp[8] http://terraserver.microsoft.com/about.aspx?n=AboutTerraServiceExampleMap[9]_http://msdn.microsoft.com/library/en-us/cpref/html/frlrfSystemDrawingBitmapClassTopic.asp[10]_http://download.microsoft.com/download/8/0/a/80a8307c-ece6-4f4d-94c9-ceeaae586ca4/VisualBasic6WebServices.wmv)

Figura 2 Immagine scaricata e visualizzata in un’applicazione Visual Basic 6

VB6

Page 47: v2006 05 vbj71
Page 48: v2006 05 vbj71

48 VBJ N. 71 - Settembre/Ottobre 2006

La programmazione di Office tramiteVSTO

di Emanuele Mattei

Microsoft Office è un pacchetto che comprende diverse applicazioni, mol-to usate in ambito aziendale e perso-

nale; quelle di più frequente utilizzo sono Word, Excel, Access e Outlook. Il pacchetto Office offre altri prodotti, quali Power Point, Infopath, FrontPage, Visio e Project. Quando si ha l’esi-genza di utilizzare un determinato applicativo con funzionalità avanzate, è possibile persona-lizzarlo utilizzando il linguaggio Visual Basic for Application (VBA). L’uscita di Visual Studio 2005, in particolare con la versione Visual Stu-dio Tools for Office (VSTO), ha messo in grado di programmare i prodotti Office con la tecnologia .NET, superando quei limiti che VBA (che conti-nua a rimanere) poneva all’utente.

InstallazioneMicrosoft Visual Studio 2005 comprende di-verse versioni, quella dedicata allo sviluppo di applicazioni per Office si chiama Visual Studio Tools for Office e permette di program-

mare per i prodotti Word ed Excel; inoltre tramite alcuni componenti aggiuntivi che si trovano sugli appositi cd, si può abilitare tale ambiente di sviluppo anche per la pro-grammazione di Outlook e Infopath. Prima di procedere all’installazione dell’ambien-te di sviluppo VSTO, bisogna installare le Primary Interop Assemblies (pias), che per-mettono di rendere possibile la programmazione .NET per il pacchetto Office. Tali com-ponenti si possono installare durante l’installazione di Microsoft Office oppure mo-dificandone le impostazioni di installazione: in quest’ul-timo caso bisogna scegliere la voce aggiungi/rimuovi del programma Office, situato nella finestra di installazio-ne applicazioni del pannello di controllo. Nelle opzioni di Office, bisogna eseguire l’installazione completa per alcune voci, tramite il menu

In questo articolo vedremo come creare applicazioni in am-biente Office utilizzando la tecnologia .NET

OFFICE

Emanuele Mattei è sviluppatore presso una società d’infor-matica di Roma. Attualmente collabora con altri webmaster al sito www.shareoffice.it il primo usergroup italiano dedicato alla programmazione di Office, tramite la tecnologia .NET.

VSTO

Page 49: v2006 05 vbj71

49N. 71 - Settembre/Ottobre 2006 VBJ

proprio interesse, si ha la possibilità di scegliere il tipo di progetto, ossia se in ambiente Windows, Mobile ed Office. Selezionato il tipo di progetto, nella parte destra (quella indicante i modelli) verranno riportati i vari progetti che si posso-no creare: Word, Excel ed eventualmente anche per Outlook o Infopath, qualo-ra si sia scelto di installare anche questi componenti. Selezionando il modello “Documento Word” verrà aperta una finestra (Fi-gura 4), che ci chiede se vogliamo creare un nuovo documento o utilizzare uno

esistente; selezioniamo nuovo documento e digitiamo il pulsante Ok. A video po-trebbe essere visualizzato un messaggio, come mostrato nella Figura 5, qualora le impostazioni delle protezioni macro siano ad un livello medio-alto. Come si vede nella Figura 6, l’ambiente di

di scelta rapida dell’elemento seleziona-to. A tal proposito occorre impostare tale scelta alle voci “Supporto per la program-mabilità .NET per Microsoft Form 2.0” e “Supporto programmabilità .NET per Smart Tag” situate alla voce Strumenti di Office, come mostrato in Figura 1. Stessa operazione anche per Word, selezionando la voce “Supporto per la pro-grammabilità .NET.” come mostrato nella Figura 2.

Prima applicazioneDopo aver installato il tutto, si può procedere alla creazione della prima applicazione .NET per Of-fice. Si apra Visual Studio 2005; dopo aver selezio-nato Nuovo Progetto dal menu File, viene aperta una finestra (Figura 3) la quale ci permette di sce-gliere il linguaggio che vogliamo utilizzare; dopo aver selezionato il linguag-gio di programmazione di

OFFICE

Figura 1 Finestra per l’aggiunta delle programmazione (pias) di Office

Figura 2 Finestra per aggiungere la possibilità di programmare gli smart tag

Page 50: v2006 05 vbj71

50 VBJ N. 71 - Settembre/Ottobre 2006

sviluppo è un ibrido tra quello di Visual Studio 2005 ed un documento Word, que-sto per dare la possibilità al programmato-re di avere una visione reale di ciò che sta programmando.Chi programma in ambiente Windows

troverà familiare la programmazione per Office, in quanto molti controlli che si tro-vano in ambiente Windows sono compresi anche in quello Office, situati nella barra degli strumenti. Trasciniamo un pulsante sul foglio, e nel-

l’evento click scriviamo il frammento di codice ripor-tato di seguito

MsgBox(“ciao a tutti”,

MsgBoxStyle.Information, “testo”)

A questo punto, per poter eseguire il progetto baste-rà fare click sul tasto F5 o andare nel menu Debug e selezionare la voce Avvia Debug.

Modifica del riquadro attività

Di seguito viene illustrata la procedura per creare un riquadro attività per-sonalizzato, il quale avrà il compito di inserire nel

OFFICE

Figura 3 Scelta del progetto in Visual Studio 2005

Figura 4 Finestra che indica se creare un nuovo documento o utilizzare uno esistente

Page 51: v2006 05 vbj71

51N. 71 - Settembre/Ottobre 2006 VBJ

documento una data selezionata da un apposito calendario. Il riquadro attività è quel pannello che si trova nella parte de-stra di ogni programma Microsoft Office 2003, nel quale si trovano informazioni aggiuntive o complementari di un deter-minato comando.Per aggiungere un nuovo riquadro atti-vità da codice, selezioniamo la voce di menu Aggiungi nuovo elemento, situato nel menu Progetto; a questo punto verrà aperta una finestra (Figura 7) e in essa selezioniamo il modello con la dicitura “Controllo riquadro azioni”. Verrà ag-giunto al progetto un nuovo controllo, o meglio un user control, in cui si possono inserire altri controlli, per esempio quelli

situati nella barra degli strumenti. Inseriamo un controllo di tipo MonthCa-lendar ed un pulsante; in questo modo, dopo che l’utente avrà selezionato una data tramite il pul-sante inserisci, nel docu-mento Word verrà inserita tale data nel punto in cui

si trova il cursore.

L’oggetto word.selection permette di gesti-re le impostazioni del documento di testo, quali testo, tabelle, formattazioni ed altro ancora; la proprietà text imposta o resti-

OFFICE

Figura 5 Messaggio informativo sulla protezione delle macro

Figura 6 L’ambiente per lo sviluppo di Office

L’oggetto word.selection permette di gestire le impostazioni del documen-to di testo

Page 52: v2006 05 vbj71

52 VBJ N. 71 - Settembre/Ottobre 2006

tuisce il testo richiesto.Nell’evento click del pulsante inseriamo il seguente frammento di codice, il qua-le imposta nel documento Word in cui si trova il cursore, la data selezionata nel calendario

Dim selezione As Word.Selection = Globals.ThisDocument.

Application.Selection

selezione.Text = MonthCalendar1.SelectionEnd

Per aggiungere tale controllo nell’evento startup del documento Word dobbiamo aggiungere alla proprietà ActionsPanel

dell’oggetto Me, il controllo inserito nel progetto.Il codice deve essere simile a quello ripor-tato qui di seguito:

Me.ActionsPane.Controls.Add(New ActionsPaneControl1)

ConclusioniIn questo articolo introduttivo abbiamo visto come in Visual Studio 2005 si pos-sono creare applicazione in ambiente Mi-crosoft Office; tale ambiente di sviluppo ci permette di creare applicazioni con più semplicità e velocità. Nel prossimo artico-lo vedremo come creare uno Smart Tag.Sul sito ftp di Infomedia (ftp.infomedia.it/pub/) trovate il codice sorgente dell’appli-cazione.

Bibliografia[1] Sito della home page della Msdn per lo sviluppo di Visual Studio Tools for Officehttp://msdn.microsoft.com/office/tool/vsto/default.aspx

OFFICE

Figura 7 Finestra per l’aggiunta di un nuovo riquadro attività

In Visual Studio 2005 si possono creare applicazio-ne in ambiente Microsoft

Office

Page 53: v2006 05 vbj71
Page 54: v2006 05 vbj71

Prodotti News

54 VBJ N. 71 - Settembre/Ottobre 2006

3CX Centralino Telefonico per Windows, edizione GRATUITA

3CX, una nuova società che sviluppa IP PBX basati su software, ha rila-sciato la prima versione del proprio prodotto IP PBX, il Centralino Tele-fonico 3CX per Windows, edizione gratuita.Il Centralino Telefonico 3CX libera le aziende dagli elevati costi di acqui-sto e gestione di centralini (o PBX) proprietari. Centralino Telefonico 3CX si basa sullo standard aperto SIP (Session Initial Protocol); di conseguenza, funziona con qualsiasi gateway o telefono basato su SIP. In questo modo, si elimina l’esigenza di telefoni di sistema proprietari ed il know-how d’installazione e gestione specializzate.Centralino Telefonico 3CX per Win-dows è un IP PBX che sostituisce del tutto un centralino proprietario, supporta telefoni software e hard-ware con standard SIP, servizi VOIP e linee telefoniche PSTN. Centralino Telefonico 3CX è molto meno co-stoso di un centralino tradizionale ed è in grado di ridurre i costi delle chiamate in modo marcato, grazie all’utilizzo di provider di servizi VOIP. La sua amministrazione basata su web semplifica la gestione del siste-ma telefonico. Centralino Telefonico 3CX elimina il circuito telefonico di rete e consente agli utenti di “con-dividere l’ufficio” semplicemente rispondendo al telefono.

Caratteristiche principali:

*_Sistema telefonico completo: fornisce la commutazione, lo smi-

stamento e la messa in coda delle chiamate

* Costo di acquisto notevolmente inferiore a quello di un apparec-chio PBX tradizionale

* Scalabilità: numeri diretti e linee telefoniche illimitate. Non sono richiesti moduli di espansione proprietari.

* Configurazione e indicatore di sta-to basati sul web: facile gestione del sistema telefonico.

* Riduzione dei costi delle telefona-

te interurbane e tra uffici. * Niente più costosi telefoni di siste-

ma proprietari: utilizzo di telefoni con standard SIP

* Eliminazione del circuito telefoni-co e semplificazione del trasloco di uffici.

http://www.3cx.it/centralino/product-tour.phpL’edizione gratuita è scaricabile dal sito http://www.3cx.it/ip-pbx/free-edition.html.

Microsoft completa l’ac-quisizione di Softricity

L’acquisizione di Softricity consente ai clienti Microsoft di ridurre i costo-si processi di gestione delle applica-zioni, velocizzare la distribuzione dei sistemi operativi e delle applicazioni e creare una base per un’infrastrut-tura di servizi software. La tecnolo-gia di virtualizzazione di Softricity può contribuire a ridurre in modo significativo la quantità di test di compatibilità delle applicazioni, che vengono gestite centralmente e inviate direttamente al desktop dell’utente in un’immagine isolata e virtualizzata, riducendo al minimo le alterazioni al sistema operativo.Grazie all’integrazione con la funzio-nalità di streaming del software di Softricity, le applicazioni virtualizza-te possono essere inviate in rete in modo dinamico e su richiesta. Que-sto approccio offre l’opportunità di usufruire di un servizio software gestito centralmente, nel quale le applicazioni siano disponibili su ri-chiesta e facilmente aggiornabili.Conclusa l’acquisizione, Softricity è diventata una società interamente posseduta da Microsoft ed ha già iniziato l’integrazione delle proprie tecnologie nei processi di enginee-ring e di distribuzione del software Microsoft. Microsoft, anche in Italia, ha rilasciato la piattaforma di virtualizzazione delle applicazio-ni SoftGrid ad un prezzo ridotto. Vengono offerti due prodotti core: SoftGrid for Desktops e SoftGrid for Terminal Services. Entrambi i prodotti includono la funzionalità

di portale self-service e di accesso basato sul Web di Softricity Zero-Touch. Inoltre, i clienti Microsoft che utilizzano Systems Management Server (SMS) 2003 possono scaricare gratuitamente il connettore SMS di Softricity. Per il supporto gli attuali clienti di Softricity potranno conti-nuare a rivolgersi ai team abituali e partner dei servizi e delle vendite. Microsoft fornirà successivamente ulteriori dettagli sulla distribuzione dei prodotti Softricity che supporta-no Windows Vista e Windows Server “Longhorn”.In Italia Softricity SoftGrid è di-stribuito da Ready Informatica (www.ready.it) che ha iniziato la diffusione nel 2003. Oggi si contano più di 50 clienti e più di 4000 licenze installate sul territorio italiano. Inol-tre sono già presenti 10 integratori certificati, capaci di supportare il cliente dallo studio di fattibilità fino alla messa in opera del progetto. Ready Informatica è anche l’unico training center ufficiale Softricity SoftGrid (www.readyeducation.it).Maggiori informazioni su Softricity SoftGrid sono disponibili sul sito www.softricity.it.

Il 2D di Solid Edge gratis per tutti

UGS, leader mondiale nella fornitura di soluzioni e servizi per la gestione del ciclo di vita del prodotto (PLM), annuncia cheSolid Edge® 2D Drafting, il software per la progettazione 2D (prece-dentemente a listino a più di 1.000 euro) è a disposizione gratuitamente all¹indirizzo www.solidedge.com/free2d. La decisione indica che il mercato considera ormai il software 2D una commodity e sottolinea il valore della modellazione gestita in 3D. Il software 2D è scaricabile gra-tuitamente e non prevede l¹acquisto di licenze, mentre verranno forniti a pagamento eventuali servizi di assi-stenza e aggiornamento automatico del software.Solid Edge è il componente CAD del-la nuova suite UGS Velocity Series_. Solid Edge 2D Drafting fornisce una

Potete inviare i vostri comunicati stampa all’indirizzo:[email protected]

Page 55: v2006 05 vbj71

Prodotti News

55N. 71 - Settembre/Ottobre 2006 VBJ

serie di strumenti collaudati per disegnare. Il pacchetto integra co-mandi di disegno, funzionalità per la generazione di schemi, annotazioni e quotatura, che rispettano auto-maticamente gli standard di disegno meccanico selezionati, fra cui ISO, ANSI, BSI, DIN, JIS e UNI. Inoltre il software mette a disposizione assi-stenti intuitivi (wizard) per la conver

La soluzione HASP di Alad-din supporta Microsoft .NET Framework 2.0 Techne Security, distributore ita-liano dei prodotti Aladdin Know-ledge Systems (NASDAQ: ALDN), annuncia che la società Israeliana, leader nelle soluzioni DRM, strong authentication e di content security, ha presentato il supporto dell’archi-tettura Microsoft .NET Framework

versione 2.0 per il sistema HASP, la soluzione dedicata alla protezione, licenziamento e distribuzione sicura del software.Grazie all’introduzione di questa funzionalità, HASP di Aladdin è in grado di proteggere automatica-mente e con un elevato livello di sicurezza applicazioni basate su .NET Framework 2.0, sfruttando soluzioni tecnologiche innovative come sicu-rezza multi-livello e misure contro il debug ed il reverse engineering. Clienti HASP che sviluppano su piattaforma .NET Framework 2.0 ora possono avvalersi delle avanzate mi-sure anti-hacking che caratterizzano le soluzioni Aladdin. D’ora in avanti gli sviluppatori saranno in grado di proteggere nel giro di pochi minuti applicazioni .NET Framework 2.0, che vengono letteralmente “rac-chiuse” in un ambiente pressocché impenetrabile. Poiché Envelope non

richiede alcuna modifica al codice sor-gente, è la soluzione ideale anche per distributori e rivenditori che vogliono proteggere software. Alcuni dei van-taggi offerti da Envelope:

• Protezione del software dall’uso non autorizzato vincolandolo alla presenza della chiave HASP

• Protezione da reverse engineering grazie alla crittografia dei file

• Protezione dall’analisi del codice con l’introduzione di sofisticate misure anti-debugging

• Utilizzo di diversi livelli di pro-tezione random per impedire l’hacking dell’eseguibile.

Techne Security S.r.l.Via Monte Sabotino, 69 – 41100 Modena ItalyTel: +39 059 415608; Fax: +39 059 415630

Page 56: v2006 05 vbj71

Prodotti News

56 VBJ N. 71 - Settembre/Ottobre 2006

GFI EventsManager scopre cosa sta effettivamente accadendo sulla propria rete

GFI, sviluppatore internazionale leader di software di protezione della rete, sicurezza del contenuto e messaggistica, ha lanciato oggi GFI EventsManager, la sua soluzione diprossima generazione per la ge-stione e il reporting centralizzati dei log di eventi. L’ultima release di GFI fornisce un’idea di quanto accade nella struttura informatica e garantisce il massimo tempo di operatività della rete: funge da si-stema di avvertimento precoce per tutti i potenziali errori hardware e software, al contempo, controllan-do e avvisando l’utente in merito a possibili violazioni di sicurezza. GFI EventsManager è stato inoltre svi-luppato per soddisfare le crescenti richieste di conformità deilog di eventi a leggi e normative.GFI EventsManager è una soluzio-ne di gestione dei log di eventi orientata ai risultati, che si integra in qualsiasi infrastruttura informa-tica esistente. Raccoglie in modo automatico i dati degli eventi da tutti i componenti della rete, li standardizza in un database centrale e fornisce rapporti utili sulle conclu-sioni raggiunte. Grazie alla continua attività di monitoraggio e avvisi, GFI EventsManager conferisce all’am-ministratore maggiore potere di prevenzione dei disastri della rete, attraverso lanotifica di attività illecite o di possi-bili errori hardware e software rela-tivi alla loro rete, grazie a informa-zioni quali: i software che vengono installati o disinstallati, lo stato di salute di Microsoft Exchange ed altri server, gli utenti che accedono a file contenenti dati sensibili, le attività di login e molto altro.Gestori informatici con maggiore esperienza sanno che i dati conte-nuti nei log di eventi rappresentano la loro risorsa più preziosa quando si tratta di esaminare errori di sistema e violazioni di sicurezza. Le aziende

sono adesso anche legalmente vin-colate a conservare ed esaminare attivamente i loro log di eventi nell’ambito della loro gestione or-dinaria. La conservazione di archivi protetti di eventi nel loro formato originario sirivela essenziale quando si devono fornire le prove di conformità a leggi e normative.

<http://www.gfi-italia.com/http://www.gfi-italia.com/.

Symantec presenta Nor-ton Confidential, la prima soluzione per la sicurezza delle transazioni online Symantec Corp. ha annunciato la disponibilità di Norton Confiden-tial, la prima soluzione completa per la sicurezza delle transazioni online. Norton Confidential fornisce all’utente un livello di protezione altissimo contro gli strumenti più pericolosi utilizzati dagli hacker: siti di phishing fraudolenti e crimeware eavesdropping, capaci cioè sottrar-re i dati digitati o presenti sulla schermata quando si effettua una transazione online. Per una sicurezza ancora più efficace delle transazioni online, Norton Confidential intensi-fica la protezione nei momenti di maggiore rischio, ovvero quando l’utente inizia a inserire i propri dati personali sensibili, come password e numeri di conto, fornendo inoltre chiari indicatori visivi che permet-tono all’utente di sapere quando può compiere transazioni online in maniera sicura.Secondo quanto emerso da uno studio di Harris Interactive commis-sionato da Symantec in ottobre 2005, il 71% degli utenti dichiara di sentirsi “a disagio” nel fornire dati personali online, mentre il 53% afferma di esse-re “molto preoccupato” per il furto d’identità online. Vi sono quindi ot-timi motivi per prendere precauzioni quando si tratta di sicurezza online. Il crimeware, una serie di strumenti di malware mirati al furto di dati e d’identità, costituisce una minaccia

sempre più grave per gli utenti che effettuano transazioni in rete. Secon-do la decima edizione dell’Internet Security Threat Report, analisi seme-strale condotta da Symantec sulla si-curezza in rete, nei primi sei mesi del 2006, 30 dei 50 principali campioni di codici maligni erano in grado di esporre i dati riservati dell’utente.Norton Confidential è l’unico prodotto per la sicurezza delle transazioni online che racchiude in un’unica soluzione tecnologie antiphishing e anticrimeware. Nor-ton Confidential non solo avvisa gli utenti impedendo loro di visitare i siti di phishing ma, grazie alla tec-nologia anticrimeware, è anche in grado d’impedire gli attacchi dei software di eavesdropping.Le principali funzionalità di Norton Confidential comprendono:

• Protezione dal phishing – Avvisa o impedisce all’utente di visitare siti di phishing noti o sospetti.

• Autenticazione dei siti – Confer-ma l’autenticità dei più famosi siti di shopping, banking o altro che richiedono l’inserimento di dati finanziari o di altri dati personali.

• Protezione del crimeware – Pro-tegge l’utente dal crimeware noto o sconosciuto nei momenti di maggiore rischio, ovvero prima di effettuare una transazione online.

• Sicurezza delle password – Pro-tegge e gestisce i dati di login e le password.

• Blocco delle password – Blocca le credenziali di login impedendo l’accesso ai siti non autorizzati senza l’approvazione dell’utente.

Norton Confidential sarà disponi-bile al pubblico da novembre 2006 presso lo store online di Symantec www.symantecstore.com e rivendi-tori e distributori online. Il prezzo al pubblico consigliato di Norton Con-fidential è di circa 50 euro, che com-prendono un anno di abbonamento al servizio, gli update alla sicurezza grazie a Symantec LiveUpdate e le nuove funzionalità del prodotto non appena disponibili.

Page 57: v2006 05 vbj71
Page 58: v2006 05 vbj71

Prodotti News

58 VBJ N. 71 - Settembre/Ottobre 2006

Adaptec Snap Server 410 semplifica lo storage con-diviso

Adaptec, fornitore globale di so-luzioni storage, ha lanciato Snap Server 410, il prodotto che com-pleta la famiglia di soluzioni NAS (network attached storage) indiriz-zate alle piccole e medie imprese. Il prodotto è disponibile in 3 di-verse configurazioni – con capacità da 640GB, 1TB e 2TB – e sfrutta il potente sistema operativo Guar-dianOS, lo stesso utilizzato per la linea di Snap Server di fascia midrange. Semplice da installare e manutene-re, Snap Server 410 è stato ideato per essere utilizzato in ambienti che non dispongono di risorse tec-niche. La famiglia di Snap Server di Adaptec, che oltre al prodotto presentato oggi comprende gli Snap Server 110, 210, 520, 550 e i JBOD S50, rappresenta la prima linea di soluzioni NAS per le PMI in grado di offrire unified block (tramite iSCSI) e supporto file nel-lo stesso dispositivo. Snap Server 410 offre funzionalità avanzate, comprese applicazioni opzionali di classe enterprise per la replica dei dati, il backup disk-to-disk e il disaster recovery. Snap Server 410 è offerto in con-figurazione rack con quattro disk drive e interfacce di rete da due gigabit. Oltre a RAID 1 e 0, Snap Server 410 supporta anche RAID 5.

• Piattaforma storage flessibile e multi-purpose – Questi sistemi sono le prime soluzioni network storage di questa fascia di prez-zo a offrire servizi unified file & block (tramite iSCSI), nonché supporto multi-protocollo per NFS, AFP e CIFS. Le aziende pos-sono pertanto ridurre la spesa IT globale grazie alla possibilità di archiviare sia file sia dati struttu-rati nello stesso sistema.

• Semplicità di utilizzo - Guardia-nOS offre un’interfaccia grafica

intuitiva che rende gli Snap Ser-ver 110, 210 e 410 semplici da installare, configurare e manu-tenere. Filiali e uffici remoti che non dispongono di personale tecnico possono implementare e gestire autonomamente questi server, assicurando che i dati siano protetti a prescindere da dove risiedano.

• Protezione e gestione dati avan-zate e personalizzate – In base ai budget IT e alle esigenze di storage, le aziende possono sce-gliere lo specifico software op-zionale di cui hanno bisogno per trasferire, gestire e proteggere i dati aziendali. Il software di-sponibile comprende accesso ai dati block-level (tramite iSCSI), antivirus CA eTrust e il software di backup NetVault e di BakBone per l’archiviazione disk-to-disk o disk-to-disk-to-tape (D2D & D2D2T).

Snap Server 410 da 640GB è già disponibile a un prezzo suggerito di 1749 euro, IVA esclusa. Le con-figurazione da 1TB e 2TB, disponi-bili a partire dalla fine dell’anno, saranno offerte a un prezzo rispet-tivamente di 2189 e 3069 euro, IVA esclusa.

Per maggiori informazioni: www.snapserver.com

TANDBERG e la videocon-ferenza su PC

Immagina di essere seduto in un caffè o in un aeroporto e, con un semplice click, collaborare in video dal tuo laptop con un collega dal-l’altra parte del mondo. Immagina ora di essere l’IT administrator che ha appena collegato l’intera azien-da con un video PC senza toccare il computer di nessun dipendente. A conferma del proprio impegno nell’innovazione, TANDBERG® annuncia Movi, la prima soluzione del suo genere che rende tutto questo possibile. Permette infatti

di beneficiare della comunicazio-ne visiva basata su PC ovunque e in qualunque momento senza prendere un appuntamento con il dipartimento informatico.Movi è un’applicazione video ser-ver-based per il mercato enterpri-se che ridefinisce la facilità d’uso. Con una sola semplice operazione gli utenti possono lanciare video-chiamate in tre modi: ciccando su un invito a un meeting, su un link permanente sull’intranet aziendale oppure su un indirizzo della rubri-ca Movi. Tutto ciò che serve è una webcam, un microfono, speaker e un PC con connessione Internet. Movi fa tutto il resto, mettendo in comunicazione gli utenti in video nella finestra Movi.La soluzione Movi permette ai di-pendenti di comunicare in maniera visiva con i propri colleghi per au-mentare la produttività - ovunque essi si trovino. Il personale non deve più affidarsi unicamente al telefono per riunioni importanti o sentirsi ‘isolato’ se lavora da casa o dall’estero. La collaborazione face-to-face avviene direttamen-te dal PC, facilitando il processo decisionale, sfruttando l’expertise aziendale e unendo le organizza-zioni. Video a portata di un click - uno strumento indispensabile per la produttività.Movi è il primo prodotto video PC che offre l’installazione con un solo tocco e i dipartimenti IT possono gestirlo centralmente via Web. Poiché non richiede l’installa-zione in locale di software, aggior-namenti, diagnostica e misurazione è molto più semplice di altri stru-menti video PC.Movi è attualmente in fase di test presso numerosi clienti TANDBERG e sarà disponibile nel secondo trimestre del 2007. Per ulteriori informazioni visitate il Launch Pad, il nuovo sito interattivo che per-mette ai visitatori di esplorare e fornire pareri su Movi all’indirizzo www.tandberglaunchpad.com.

Page 59: v2006 05 vbj71
Page 60: v2006 05 vbj71

60

.NET TOOLS

VBJ N. 71 - Settembre/Ottobre 2006

PHP Obfuscator di Raffaele Di Natale

Un tool open source in C# per offuscare il codice sviluppato in Php

La diffusione delle applicazioni web ha senz’altro agevolato il compito di distribuzione delle applicazioni stesse, ma, al contempo, ha favorito azioni di sciacallaggio nei confronti di interi blocchi di codice in linguaggi script. Nel-l’intento di aggirare il problema molte aziende provano ad offuscare opportunamente il codi-ce distribuito, soprattutto in casi particolari, quale per esempio quello di una demo.Dato un programma A ed un programma B svi-luppati in un generico linguaggio, si dice che B è ottenuto per offuscamento di A se e solo se il comportamento di A è identico a quello di B ed inoltre il codice sorgente di B risulta particolarmente difficile da leggere e da analizzare.

Offuscare o non offuscare?L’offuscamento del codice è l’obiettivo finale, ma la strada può talvolta essere così tortuosa che il gioco potrebbe anche non valere la candela. Innanzitutto, biso-gna dire che l’offuscamento del codice effettuato in maniera inesatta non solo potrebbe produrre un’applicazione non funzionante, ma, cosa ben più grave, potrebbe generare un’applicazione ap-parentemente funzionante. Un secondo problema è rappresentato dal modo in cui si opera per offuscare il codice: molti tool di offuscamento prevedono spesso delle precondizioni tali da richiedere una modifica del codice originario al fine di garantirne la corretta codifica. A questo

punto oltre a domandarsi se sia davvero van-taggiosa una simile attività di offuscamento è necessario utilizzare il tool più vantaggioso.

Limitazioni nell’offuscamentoTutti i tool di offuscamento definiscono regole più o meno rigide per portare a termine cor-rettamente il proprio compito. Bisogna ricono-scere che PHP Obfuscator non solo non eccede in tali richieste, ma l’unica vera limitazione appare più che legittima. Infatti, il processo di offuscamento ignora tutte le variabili definite nel body della pagina HTML. Per garantire un corretto offuscamento, le strade da seguire sono principalmente due: non utilizzare tali variabili all’interno dello blocco di codice PHP o, in alternativa, includerle nell’elenco delle variabili da non sottoporre ad offuscamento.

Figura 1 Componenti di base del tool

Page 61: v2006 05 vbj71

61

.NET TOOLS

N. 71 - Settembre/Ottobre VBJ

L’applicazionePHP Obfuscator è un tool interamente svilup-pato in C#: l’applicazione ed il codice sorgente possono essere scaricati dal sito [1]. Si compo-ne di tre elementi fondamentali:

• La GUI;• Il tool a linea di comando;• La classe Obfuscator.

Come si evince dalla Figura 1, la GUI può inte-ragire con il tool a linea di comando per mezzo di un file di progetto in XML, con estensione .obxml. La classe Obfuscator è alla base sia della GUI, sia del tool a linea di comando. Di seguito è fornito un esempio del file di proget-to in cui è facile riconoscere le variabili che sono escluse dal processo di offuscamento. Per modificare tale elenco è possibile agire diret-tamente su tale file o usufruire dell’apposita funzionalità della GUI.

<?xml version=”1.0”?>

<ObfuscationConfig xmlns:xsi=”http://www.w3.org/2001/XMLSchema-

instance” xmlns:xsd=”http://www.w3.org/2001/XMLSchema”>

<FilesToObfuscate>

<string>C:\Temp\Index.php</string>

</FilesToObfuscate>

<ExcludeVariables>

<string>$password</string>

<string>$database</string>

<string>$username</string>

<string>$server</string>

<string>$_SERVER</string>

<string>$HTTP_SERVER_VARS</string>

<string>$_ENV</string>

<string>$_COOKIE</string>

<string>$_GET</string>

<string>$_POST</string>

<string>$_FILES</string>

<string>$_REQUEST</string>

<string>$_SESSION</string>

<string>$GLOBALS</string>

<string>$this</string>

<string>$php_errormsg</string>

</ExcludeVariables>

<ExcludeFunctions />

<RemoveWhitespace>true</RemoveWhitespace>

<RenameVariables>true</RenameVariables>

<RenameFunctions>true</RenameFunctions>

<TargetDir>C:\Obfuscated</TargetDir>

<SourceDir>C:\Temp</SourceDir>

</ObfuscationConfig>

Tra gli elementi del progetto sono presenti anche SourceDir e TargetDir, che rappresenta-no rispettivamente la directory a partire dalla quale sono processati i file PHP e la cartella di destinazione all’interno della quale saran-no copiati tutti i file offuscati. La cartella di destinazione viene eliminata e ricreata ogni volta che si esegue l’offuscamento. Inoltre la struttura della cartella finale è il clone di quel-la d’orgine garantendo, in tal modo, un codice offuscato, ma pronto all’uso senza la necessità di ulteriori interventi sul codice stesso.

MD5 in PHP ObfuscatorMD5 è un algoritmo crittografico che, dato un messaggio di arbitraria lunghezza, genera un’impronta di 128 bit. PHP Obfuscator uti-lizza tale algoritmo per codificare. Questo ac-corgimento oltre a generare nomi di variabili e di funzioni praticamente illeggibili ad occhio nudo, rende praticamente impossibile risalire al nome iniziale delle variabili e comprender-ne quindi il significato all’interno dello script. Per maggiori dettagli visitare [2].

Le fasi dell’offuscamentoPHP Obfuscator effettua l’offuscamento agen-do su variabili, funzioni e spazi vuoti, insieme o singolarmente, al fine di ottenere il livello di offuscamento desiderato. Tramite la GUI è possibile infatti settare quale o quali dei tre

PHP Obfuscator usa l’algo-ritmo MD5 per offuscare variabili e funzioni

Page 62: v2006 05 vbj71

62

.NET TOOLS

VBJ N. 71 - Settembre/Ottobre 2006

precedenti aspetti prendere in considerazio-ne durante l’offuscamento. In virtù del fatto che l’obiettivo rimane sempre quello di avere un’applicazione offuscata equivalente a quella originaria, si consiglia di effettuare l’offusca-mento per gradi, testando di volta in volta il risultato finale. Si potrebbe cominciare dalla rimozione degli spazi vuoti, per poi passare al-l’offuscamento delle variabili ed infine a quel-lo delle funzioni. Il processo di offuscamento avviene in due fasi principali: nella prima sono rinominate le variabili, rimossi i commenti e gli spazi bianchi; nella seconda fase sono rino-minate le classi e le funzioni proprie dell’appli-cazione.

Un esempioUn semplice esempio di offuscamento può es-sere ottenuto applicando PHP Obfuscator ad un file contenente il seguente codice PHP:

<?php

if($functions==”something”)

{

print(“<p><h3>Hello VBJ!</h3></p>”);

}

print_footer();

?>

Il risultato, che un qualsiasi editor visualizze-rebbe in un’unica linea sarebbe:

<?php

if($R83E53B3209D4446AACD5F8A9B11F3A21==”something”)

{

print(“<p><h3>Hello VBJ!</h3></p>”);

}

F7E969322D1342FC7546AB99B9E690339();

?>

Come si può facilmente notare, sia il nome della variabile, sia il nome della funzione sono stati modificati nelle corrispondenti impronte generate dall’algoritmo MD5.

ConclusioniMolteplici e complesse sono le strade che por-tano all’offuscamento del codice. In questo ar-ticolo è stato proposta una possibile soluzione che, mediante semplici accorgimenti e piccole restrizioni, permette all’utente di codificare agevolmente il proprio codice PHP. Non è det-to che sia la soluzione migliore, ma sicuramen-te non richiede uno stravolgimento del codice e comunque consente di aggirare gli ostacoli che potrebbero presentarsi.

Bibliografia e Riferimenti[1]_http://www.codeproject.com/csharp/php_obfuscator.asp[ 2 ] _ h t t p : / / w w w. a m a g r i . i t / C r i t t o l o g i a /Crittografia/Algoritmi_crittografici/MD5/analisi_algoritmo.htm

ProdottoPHP Obfuscator

Url di riferimento http://www.codeproject.com/csharp/php_obfuscator.asp

Stato Releasev. 0.1.0.0

Semplicità d’uso ªªªªªSi tratta di un tool semplice e molto intuitivo. Dopo qualche test si è in grado di generare una completa applicazione PHP offuscata.

Utilità ªªªªªIn tutti i casi in cui l’offuscamento del codice si rende necessario per proteggere il proprio lavoro, questa tipologia di tool risulta fondamentale, soprattutto, come in questo caso, in cui non è ne-cessario stravolgere il proprio lavoro.

Qualità prodotto ªªªª² In applicazioni semplici e che rispondono esattamente alle richie-ste del tool, l’offuscamento avviene senza grossi problemi. In ap-plicazioni più complesse gli è capitato di bloccarsi.

Qualità documentazione ªªªª²Pur non essendo disponibile alcun help in linea, la documentazio-ne allegata al progetto (in lingua inglese) spiega perfettamente non solo i punti di forza del tool, ma anche le limitazioni, anticipando in tal modo eventuali problemi.

Le variabili definite nel body della pagina html

sono ignorate nel processo di offuscamento

Page 63: v2006 05 vbj71

63

.NET TOOLS

N. 71 - Settembre/Ottobre VBJ

modo viene creato un file XML per ogni file del progetto; questi file vengono poi dati “in pasto” a determinate applicazioni che creano la docu-mentazione con l’ausilio di un compilatore di file HTML Help. Fino a .NET 1.1 il tool più utilizzato è stato NDoc, che purtroppo ha chiuso i battenti e quindi non supporta la versione 2.0 con tutte le sue sfaccettature (prima tra tutte i Generics). Per colmare questo gap la Microsoft ha messo a disposizione degli sviluppatori lo strumento gra-tuito oggetto della recensione di questo articolo: al momento della scrittura è a nostra disposizio-ne la CTP 2 ed è un tool completamente a riga di comando; esistono tuttavia delle applicazioni gratuite che forniscono il front-end del motore dell’applicazione. Come funziona Sandcastle? In primo luogo è necessario compilare il nostro file .cs o .vb (per comodità, da ora in poi conside-riamo solo la parte C#) per estrarre i commenti XML (ciò si effettua con l’opzione /doc del com-pilatore C#) . A questo punto abbiamo creato due “oggetti”: un assembly compilato e un file XML contenente i commenti estratti dai sorgenti. In

SandcastleLa documentazione professionale

di Fabio Perrone

Il nuovo strumento Microsoft per documentare il codice

La documentazione del codice è fondamentale. Punto. Anche se agli “smanettoni” la parola documentare fa rizzare i capelli, in un progetto software professionale è uno step necessario per poter riutilizzare il proprio codice e, soprattutto, per capire effettivamente tutte le sfaccettature di un’applicazione complessa. La documenta-zione può essere utente o tecnica, e in questa recensione ci soffermeremo sulla creazione di quest’ultima. Con l’avvento di .NET creare do-cumentazione tecnica è divenuto molto più sem-plice grazie alla presenza dei commenti XML (presenti sin dalla versione 1.0 per il C#, dalla 2.0 per VB.NET) incorporati all’interno del codice e realizzabili con l’aiuto dell’Intellisense. In questo

Figura 2 Sandcastle

Page 64: v2006 05 vbj71

64

.NET TOOLS

VBJ N. 71 - Settembre/Ottobre 2006

seguito, si utilizza MRefBuilder che usa reflec-tion per ispezionare gli assembly compilati e re-stituisce un nuovo file di output (reflection.org), a cui deve essere applicata una trasformazione XML grazie all’eseguibile XslTransform che tra-sforma l’output di MRefBuilder in un file di do-cumentazione reflection.xml, che contiene tutti i dati ma non la presentazione dei dati stessi. A questo punto si esegue l’applicazione BuildAs-sembler che presenta la documentazione presa dal reflection.xml e mette insieme i commenti raggruppandoli secondo argomenti HTML. L’ou-tput di BuildAssembler può essere consumato dai compilatori Microsoft di HTML Help per crea-re un file di TOC (Table of Contents) e gli indici.Come abbiamo visto, la procedura è abbastan-za macchinosa, specie per chi non ha molta familiarità con i tool a riga di comando. Tra le tante applicazioni open source che permettono di creare documentazione in modo visuale, vale la pena menzionare Sandcastle Help File Builder, un’applicazione scaricabile gratuita-mente dal sito di CodeProject. La semplice interfaccia grafica (volutamente ispirata a NDoc) permette in primo luogo di sce-gliere quali assembly includere nel progetto di compilazione ed eventualmente quali esclude-re. Una grande property grid permette di modi-ficare le impostazioni del progetto: vediamone alcune. Le prime impostazioni da modificare riguardano la posizione del compilatore HTML help 1.x, del compilatore HTML help 2.x, del percorso dove deve essere salvato il file di help compilato e del percorso di Sandcastle. Sotto la categoria “Build” è possibile imposta-re la versione del Framework e il formato del file di Help. Nella categoria “Help File” sono presenti alcune proprietà che renderanno la nostra documenta-zione in tutto e per tutto uguale a quella Micro-soft: CopyrightHref e CopyrightText permettono di impostare un link ad eventuali scritte sul copyright dei contenuti, IncludeFavorites inclu-de un tab “Preferiti” nel file di help compilato, Preliminary imposta la classica scritta “[This is preliminary documentation and is subject to change]”, SdkLinkType permette di scegliere dove devono essere impostati gli eventuali link.

A differenza della procedura a riga di coman-do, per creare un file di documentazione è sufficiente inviare il comando “Build Project” del menu “Documentation”: automaticamente verranno eseguiti tutti gli step necessari e il ri-sultato sarà presente nella directory di output specificata nelle opzioni. Il risultato di questa elaborazione è un file di help del tutto somigliante a quelli cui noi pro-grammatori in ambiente .NET siamo abituati, cioè con lo stesso layout della documentazione MSDN. Insieme, questi due tool forniscono un mezzo invalutabile per creare una documentazione professionale e altamente affidabile. Poiché Sancastle è ancora in versione CTP, non è da escludere che verranno effettuate piccole mo-difiche al motore, che inevitabilmente dovran-no essere riflesse anche sul Sandcastle Help File Builder. Nonostante una leggera difficoltà iniziale, è assolutamente certo che questo tool ripagherà di gran lunga le ore spese per padro-neggiarlo al meglio.

ProdottoSandcastle CTP + Sandcastle Help File Builder 1.2.0.0

Url di riferimento http://www.microsoft.com/downloads/details.aspx?familyid=E82EA71D-DA89-42EE-A715-696E3A4873B2&displaylang=en (Sandcastle)http://www.codeproject.com/useritems/SandcastleBuilder.asp (Sandcastle HFB)

Stato ReleaseCTP

Semplicità d’uso ªªª²²Come tutte le applicazioni a riga di comando, la semplicità d’uso diminuisce; diventa buona se si utilizza Sandcastle HFBo.

Utilità ªªªªªFinalmente a disposizione di qualsiasi programmatore uno stru-mento professionale per creare la documentazione.

Qualità prodotto ªªªª² Entrambi affidabili, nei test sul prodotto eseguiti non abbiamo ri-scontrato particolari problemi, solo qualche piccolo bug che ver-rà risolto nella versione definitivai.

Qualità documentazione ªªª²²La documentazione di Sandcastle è abbastanza scarsa, si consi-glia una buona dose di pazienza e molte prove; la documenta-zione di Sandcastle HFB è decisamente buona (in lingua inglese, come il programma)

Page 65: v2006 05 vbj71
Page 66: v2006 05 vbj71
Page 67: v2006 05 vbj71
Page 68: v2006 05 vbj71