Sei sulla pagina 1di 68

online.infomedia.

it
n. 60 - novembre/dicembre 2004
bimestrale - anno decimo

Direttore Responsabile
Marialetizia Mari (mmari@infomedia.it)
Direttore Esecutivo
ED I T O R I A L E
Francesco Balena (fbalena@infomedia.it)
Technical Editor
Alberto Falossi (afalossi@infomedia.it)
Managing Editor
Renzo Boni (rboni@infomedia.it)
Le community
Collaboratori
Marco Bellinaso, Daniele Bochicchio,
Lorenzo Braidi, Gianluca Cannalire,
e CodeZone
Dino Esposito, Massimiliano Mariconda,
Davide Mauri, Paolo Pialorsi,
Ingo Rammer, Marco Russo,
Fabio Scagliola, Lorenzo Vandoni
S crivo questa pagina al ritorno dall’evento Connect a
Barcellona, dove Microsoft ha invitato gli animatori delle
principali community e siti Web dedicati alle tecnologie
e ai linguaggi di programmazione .NET. Sono stati due giorni
molto intensi e molto interessanti, soprattutto per la possibilità di
confrontarsi sulla nuova iniziativa sulle community che Microsoft
sta portando avanti da qualche tempo.
Immagino che qualcuno di voi abbia già sentito parlare di Co-
deZone, per gli altri ecco un piccolo riassunto. Si tratta di una
Direzione
Natale Fino (nfino@infomedia.it) specie di portale+motore di ricerca che i programmatori .NET
potranno usare per arrivare facilmente agli articoli più interessanti su queste tecnologie,
Marketing & Advertising tra quelli prodotti appunto dai numerosi siti Web e community sparsi per il mondo. La cosa
Segreteria: 0587/736460
marketing@infomedia.it interessante è che ci saranno tanti portali CodeZone, uno per ciascuna area geografica o
lingua. Potete trovare maggiori informazioni a http://www.codezone.info e potete persino
Amministrazione
abbonarvi ad una rivista abbastanza ben fatta (gratuita, ma in inglese).
Sara Mattei
(amministrazione@infomedia.it) L’iniziativa è molto interessante e quasi certamente destinata al successo. Perché quasi?
Non certo perché a Microsoft mancano i mezzi per imporre CodeZone al mondo degli
Grafica
Manola Greco (mgreco@infomedia.it) sviluppatori. Il motivo che ho per dubitare (ma solo un pochino...) ha un nome ben pre-
ciso: Google. Ce la farà CodeZone ad imporre la sua specificità e guadagnare le simpatie
Technical Book
degli sviluppatori che da anni oramai si affidano alla completezza di Google? Nessuno lo
Lisa Vanni (book@infomedia.it)
può sapere, ma sarà interessante vedere cosa succederà. Di certo è la prima volta che la
Segreteria più grande software house del mondo deve combattere un osso così duro, e il fatto che la
Enrica Nassi
(info@infomedia.it) Borsa continui a premiare Google non può che alzare il livello della contesa.

Termino questa pagina con una piccola novità (per voi) ma grande (per il sottoscritto).
Stampa Quando leggerete questo editoriale sarà già attivo www.dotNet2TheMax.it, la versione
TIPOLITOGRAFIA PETRUZZI italiana del sito VB2TheMax, che ho fondato nel ’99 e a cui hanno collaborato alcuni tra i
Citta’ di Castello (PG)
migliori autori ed esperti italiani e non solo (ecco spiegata la mia partecipazione all’evento
Connect). Sul nuovo sito troverete tantissimi tip e articoli e stiamo anche preparando una
Ufficio Abbonamenti
Tel. 0587/736460 - Fax 0587/732232
sezione speciale dedicata ai programmatori VB6 che vogliono migrare a VB.NET.
e-mail: abbonamenti@infomedia.it
www.infomedia.it Arrivederci sulla rete.
Gruppo Editoriale Infomedia srl
Via Valdera P., 116 - 56038 Ponsacco (PI) Italia
Tel. 0587/736460 - Fax 0587/732232
red_vbj@infomedia.it
Sito Web www.infomedia.it
Francesco Balena
fbalena@codearchitects.com

Manoscritti e foto originali anche se non pubblicati,


non si restituiscono. È vietata la riproduzione
anche parziale di testi e immagini.

Si prega di inviare i comunicati stampa e gli inviti stampa per


la redazione all’indirizzo: comunicatistampa@infomedia.it
Visual Basic Journal è una rivista di
Gruppo Editoriale Infomedia S.r.l. Via Valdera P, 116 Ponsacco - Pisa.
Registrazione presso il Tribunale di Pisa n. 20/1999
N. 60 - Novembre/Dicembre 2004 VBJ 3
SOMMARIO
NOVEMBRE/DICEMBRE

N.60
SPECIALE

Vulnerabilità del codice 7


Analisi dei casi più comuni di vulnerabilità delle applicazioni software.
di Paolo Pialorsi

La sicurezza del codice managed 13


Vediamo alcune delle principali caratteristiche del Framework .NET rivolte alla sicurezza del codice e
delle applicazioni.
di Paolo Pialorsi

Applicazioni sicure con IIS 6 e ASP .NET 20


L’accoppiata IIS 6 e ASP.NET garantisce la possibilità di creare e far funzionare in maniera sicura appli-
cazioni web con pochi e semplici sforzi. Anche se entrambi i sistemi sono già sicuri appena installati, è
necessario un ulteriore tocco per garantire alle nostre applicazioni un elevato livello di sicurezza.
di Daniele Bochicchio

Sviluppare senza essere amministratori 25


Sviluppare applicazioni senza essere amministratori è importante per la sicurezza e per scrivere appli-
cazioni eseguibili con il minimo dei privilegi necessari. Vediamo cosa c’è da sapere su Windows e Visual
Studio .NET e quali tool sono utili per affrontare questo scenario.
di Marco Russo

BEGINNER
Programmare Excel da Visual Basic .NET 31
Analisi di tre soluzioni per trasferire dati a Excel usando Visual Basic .NET e le classi del .NET framework
di Fabio Scagliola
ENTERPRISE
Servizi NT con VB .NET (seconda parte) 38
Caso reale di realizzazione e implementazione di servizi Windows con .NET
di Gianluca Cannalire

WEB
Grafici dinamici in ASP .NET 45
Vale la pena di sprecare tempo per creare grafici da zero? Molto meglio utilizzare una libreria altamente personalizzata.
Vediamo tutti i pregi di .netCHARTING
di Dino Esposito

4 VBJ N. 60 - Novembre/Dicembre 2004


RUBRICHE

Editoriale 3
Posta 54
a cura di Alberto Falossi

Recensione libri 61
.NET Tools 62
a cura di Davide Mauri

ARCHITECT'S CORNER
Applicazioni scalabili in pratica 50
“Two is meglio che one” diceva una nota pubblicità. In questa puntata daremo dei consigli pratici per progettare e imple-
mentare un’applicazione scalabile.
di Ingo Rammer

SOFTWARE ENGINEERING
L'accesso ai dati nei linguaggi object-oriented 56
Tutti i linguaggi object-oriented devono fare i conti con la necessità di gestire dati in formato relazionale
di Lorenzo Vandoni
DIFENDERSI DAGLI HACKER

Vulnerabilità del codice


Analisi dei casi più comuni di vulnerabilità delle applicazioni software.

di Paolo Pialorsi

Q
uando si parla di sicurezza delle applicazioni e del La variabile buf può contenere al mas-
codice ci si riferisce al fatto che le applicazioni de- simo 10 byte. Del codice invocherà foo,
vono essere progettate e realizzate considerando che riceverà in ingresso un puntatore a
e prevenendo i casi più diffusi di attacco. Questo articolo caratteri chiamato input, che copiamo
ha l’obiettivo di fornire una panoramica dei principali e più con la funzione strcpy dentro alla varia-
diffusi casi di vulnerabilità, insieme ai consigli per evitare di bile buf. Cosa accade se input è di di-
sviluppare applicazioni che siano in tal senso attaccabili. mensione maggiore di 10 byte? La fun-
zione strcpy non svolge alcun control-
Buffer Overrun lo sulla dimensione di input e di buf, il
È sicuramente il più famoso tipo di attacco e non poteva- nostro codice nemmeno. L’eccedenza
mo non parlarne in un articolo come questo. Riguarda tipi- sarà copiata in memoria oltre lo spazio
camente le applicazioni sviluppate con linguaggi che con- allocato nello stack di foo per la varia-
sentono la gestione diretta delle aree di memoria come C bile buf. Per come funziona l’esecuzio-
e C++. È mediamente difficile da realizzare nei confronti di ne del codice in memoria, nella parte
applicazioni sviluppate in Visual Basic o in ambienti di ese- finale dello stack allocato per l’esecu-
cuzione con memoria gestita (come .NET e Java) anche se zione di foo, cioè dopo buf, avremo l’in-
in taluni casi, quando queste applicazioni si appoggiano a dirizzo di ritorno della procedura. Se il
librerie esterne scritte per esempio in C/C++, è comunque contenuto di input è sufficientemente
possibile essere vulnerabili. Si basa sul fatto che l’accesso lungo potrà sovrascrivere questo indi-
diretto e non controllato alla memoria può consentire a un rizzo di ritorno, cambiando l’esecuzio-
hacker di sovrascriverne delle aree. Esistono diverse tipolo- ne dell’applicazione. Un trucco come
gie di buffer overrun, una delle più diffuse e che prenderemo questo, eseguito ai danni di un servizio
come esempio è quella sulle variabili di stack (Figura 1). Nei del sistema operativo, che tipicamente
linguaggi come il C le variabili stringa non sono altro che se- è eseguito con un buon livello di privi-
quenze di byte in memoria, terminate dal carattere ASCII 0. legi, consente di eseguire del codice
Pensiamo a una procedura definita come la seguente: molto pericoloso. I più famosi attac-
chi ai sistemi Windows hanno spesso
C sfruttato dei buffer overrun di IIS o di
void foo(const char* input) altri servizi molto diffusi, per cambia-
{ re l’esecuzione del codice ed esegui-
char buf[10]; re delle escalation di privilegi.
strcpy(buf, input); La soluzione a questo problema
} è controllare sempre la dimensione
dei buffer prima di usarli, in particola-
re con funzioni a rischio (strcpy, strn-
cpy, CopyMemory, MultiByteToWide-
Char). Con l’ultima versione di compi-
latore C++ di Microsoft si può utilizza-
Paolo Pialorsi è un consulente e autore specializzato nello
re l’opzione /GS che aiuta a individua-
sviluppo di Web Service e soluzioni Web con il Framework
.NET di Microsoft. Lavora nell’omonima società Pialorsi re i buffer overrun (anche se di per sé
Sistemi S.r.l. e fa parte del gruppo DevLeap. Può essere non è una protezione sicura al 100%).
contattato via email: paolo@devleap.it. Inoltre possiamo utilizzare delle funzio-

N. 60 - Novembre/Dicembre 2004 VBJ 7


DIFENDERSI DAGLI HACKER

Questo codice, oltre che poco elegante, è anche decisa-


mente insicuro! Finché sul nostro sito navigano utenti nor-
mali è tutto ok. Io cerco “birra rossa” e la query risultante
sarà “ SELECT * FROM Prodotti WHERE Descrizione = ‘bir-
ra rossa’ ”. Ma cosa accade se la ricerca viene utilizzata da
un hacker, che magari ne capisce un po’ di codice SQL?
Potrebbe cercare “qualcosa’ OR ‘1’ = ‘1” che inserito nel
nostro codice produrrebbe la seguente query:

SQL
SELECT * FROM Prodotti WHERE Descrizione = ‘qualcosa’ OR ‘1’
= ‘1’

Il risultato sarebbe la lista di tutti i prodotti del nostro


Figura 1 Schema di un buffer overrun su stack sito Web di commercio elettronico, perchè ‘1’ = ‘1’ è una
condizione sempre vera. Poco male, direte, tanto se quei
prodotti li vendo l’hacker non scopre nulla di nuovo. In
questo caso è proprio così, ma pensiamo a un caso di-
ni per le stringhe “sicure”, disponibili nel file di inclusione verso: una pagina di login che utilizza i campi txtUserID e
strsafe.h. Infine, conviene sempre controllare tutti gli indici txtPassword per autenticare un utente. Provo a ipotizzare
delle matrici prima di usarle, così come le lunghezze mas- del codice che mi capita di vedere abbastanza spesso:
sime dei path di file e cartelle. Se poi è possibile, conviene
passare a codice interamente gestito (.NET). VBScript
<%
SQL Injection Dim sQuery ‘As String
Con questa espressione ci si riferisce agli attacchi rivol- sQuery = “SELECT * FROM Utenti WHERE UserID = ‘”
ti a database, tipicamente esposti da applicazioni Web, + Request(“txtUserID”) + “’ AND Password = ‘” +
portati a termine sfruttando un errato o insufficiente con- Request(“txtPassword”) + “’”
trollo dell’input dell’utente da parte di noi programmato- ‘ Ottengo I dati all’interno di un ADODB.Recordset
ri. Si tratta per altro di una delle vulnerabilità ancora oggi If Not rs.EOF Then
più diffuse e utilizzate per violare la sicurezza di un ser- ‘ Se ho almeno un record significa che l’utente esiste
ver e delle reti alle loro spalle. End If
È doveroso dire che attacchi di questo tipo hanno qua- %>
le unica causa una scarsa attenzione da parte del pro-
grammatore, non esistono infatti ragioni “tecnologiche” Applicando lo stesso ragionamento di prima, in questo
che giustifichino simili vulnerabilità. Vediamo di cosa si caso un valore intenzionalmente modificato del campo
tratta. Pensiamo a una classica applicazione Web che txtUserID o txtPassword consente a un hacker di acce-
consente agli utenti di ricercare dei prodotti in un sito di dere al sistema anche senza password! Ma come può
commercio elettronico. un hacker sapere che dietro la nostra pagina Web c’è
La pagina di ricerca potrebbe fornire una casella di te- proprio del codice di quel tipo? È più semplice di quello
sto, chiamiamola txtRicerca, e un pulsante di ricerca, che sembra. Molto spesso una delle parti più trascurate
cmdCerca. Alla pressione di cmdCerca sul server verrà di un’applicazione è la gestione degli errori, che a vol-
eseguito del codice che, concatenando a mano i pezzi te è addirittura inesistente. La prima cosa che un hac-
di codice SQL, costruisce una query che rappresenta la ker può fare è scrivere dei valori non troppo casuali che
ricerca da eseguire sul database, come mostrato nel se- facciano andare in errore il motore SQL, nel caso in cui
guente esempio: il nostro codice si limiti a concatenare le stringhe per co-
struire le query. Per esempio può mettere nella casella
VBScript txtUserID un valore come: “qualcosa’ SELECT”. Ovvia-
<% mente concantenando le stringhe otterrebbe un errore
Dim sQuery ‘As String simile al seguente:
sQuery = “SELECT * FROM Prodotti WHERE Descrizione = ‘” +
Request(“txtRicerca”) + “’” Errore VBScript
… Microsoft OLE DB Provider for SQL Server (0x80040E14)
%> Line 1: Incorrect syntax near ‘ AND Password = ‘.

8 VBJ N. 60 - Novembre/Dicembre 2004


© 2004 Microsoft. Tutti i diritti riservati. Tutti i marchi registrati citati sono di proprietà delle rispettive società.
Scrivi il codice che conta.
Al resto ci pensa Visual Studio .NET 2003

Oggi le tue idee Visual Studio .NET 2003 riduce notevolmente la quantità di
possono diventare codice da scrivere, lasciandoti libero di concentrarti sulle cose
più importanti.
ancora più grandi.
Leader, il maggior distributore italiano di videogiochi, ha
sviluppato un’applicazione di Sales Force Automation in sei
mesi/uomo: “Visual Studio .NET 2003 ci ha garantito un notevole
risparmio dei tempi di sviluppo, grazie alla ridotta curva di
apprendimento del nuovo linguaggio C# e all’immediatezza
dell’ambiente visuale. L’applicazione sviluppata ha incrementato
l’efficienza dei nostri processi di vendita: ora è sufficiente un
Tablet PC per avere la completa disponibilità in tempo reale
delle informazioni di prodotto, fornire preventivi
personalizzati al cliente e gestire gli ordini.”
Per scoprire come Visual Studio .NET 2003 può aiutarti
a concentrarti sulle cose più importanti, visita il sito
microsoft.com/italy/vstudio/value/

004910-VisualBasic-205x275 1 1-09-2004, 17:12:50


DIFENDERSI DAGLI HACKER

Da questo errore potrebbe capire che stiamo proprio cmd.CommandText = sQuery


concatenando i pezzi di testo senza verificarli.
L’aspetto ancor più grave di questa vulnerabilità è che, cmd.Parameters.Append cmd.CreateParameter(“@UserID”, adVarChar,
una volta riscontrata, spesso è possibile ottenere l’acces- adParamInput, 50, Request(“txtUserID”))
so non solo alla tabella oggetto della query ma, compo- cmd.Parameters.Append cmd.CreateParameter(“@Password”,
nendo opportunamente le stringhe, anche ad altre tabel- adVarChar, adParamInput, 50, Request(“txtPassword”))
le di dati, eseguendo per esempio delle UNION. Come
riesce un hacker a conoscere i nomi delle tabelle e delle ‘ [...] Ottengo I dati all’interno di un ADODB.Recordset
colonne da richiedere al nostro server tramite SQL Injec-
tion? Spesso il modo più semplice è chiederle proprio al If Not rs.EOF Then
database stesso. Pensando a un SQL Server come ser- ‘ Se ho almeno un record significa che l’utente esiste
ver di database, nessuno vieta di interrogare le tabelle di End If
sistema per sapere quali sono le tabelle e le loro colon- %>
ne. I gradi di libertà che lasciamo a un hacker sono legati
a quanto abbiamo messo in sicurezza la nostra soluzio- Anche in ASP.NET possiamo utilizzare delle query pa-
ne software. Se per esempio stiamo utilizzando il data- rametriche nel modo seguente:
base con un utente ad alto livello di privilegi, non voglio
dire l’utente SA di SQL Server (quello ormai dovremmo C#
aver imparato tutti a non usarlo e a mettergli una pas- String query = “SELECT * FROM Users WHERE UserID = @UserID AND
sword!), ma comunque un utente dbo... beh, probabil- Password = @Pwd”;
mente siamo fritti! L’utente dbo può tutto sul database SqlConnection cn = new SqlConnection(“...”);
corrente, quindi l’hacker, dopo essersi preso i nostri dati, SqlCommand cmd = new SqlCommand(query, cn);
può anche decidere di cancellarli con una bella DELETE
o DROP TABLE inserita via SQL Injection in una query. cmd.Parameters.Add(“@UserId”, SqlDbType.VarChar, 50).Value =
Se poi l’utente con cui gira il servizio del server di data- Request[“txtUserID”];
base (non pensiamo solo a SQL Server) è per esempio cmd.Parameters.Add(“@Pwd”, SqlDbType.VarChar, 50).Value =
LOCAL_SYSTEM, che è il default, l’hacker avrà modo di Request[“txtPassword”];
arrivare anche sul sistema operativo che ospita il server
di database e farsi una bella escalation di privilegi sul- SqlDataReader dr = cmd.ExecuteReader();
la macchina… // Leggo i dati ottenuti...
È importante capire che questi problemi non sono le-
gati ad ASP o a SQL Server, ma sono più in generale le- Inoltre è sempre opportuno verificare l’input dell’utente.
gati ad applicazioni scritte male! Se scrivete male un sito Molti pensano che questi problemi siamo solo ricollegabili
Web in PHP+MySQL o JSP+Oracle o ASP.NET+SQL non a parametri testuali e che quindi la soluzione al problema
cambia nulla: prima o poi qualcuno potrà farvi il servi- sia semplicemente fare una sostituzione degli apici con
zio completo! doppi apici su tutte le stringhe, prima di concatenarle al
Ok, vediamo allora come ci si deve comportare per non codice SQL. Non dimentichiamo mai che gli hacker sono
essere vulnerabili agli attacchi di questo tipo. Innanzitut- in media più furbi di noi :-) o quanto meno più “smanet-
to è consigliabile utilizzare utenti con privilegi minimi, così toni”. Controllare le stringhe non basta, anche gli input
se anche ci dovessero violare l’applicazione non avranno numerici, le date o qualunque altro input possono esse-
a disposizione tutti gli strumenti di un SA o di un dbo o di re utilizzati. Alla peggio un hacker può farsi a mano una
LOCAL_SYSTEM. Poi dobbiamo abituarci a scrivere query paginetta di submit verso il nostro sito, con la quale può
parametriche o stored procedure parametriche, smettendo camuffare i dati da inviare in POST. Se utilizzate un da-
di concatenare le stringhe SQL nel codice. Nel caso del lo- tabase server che supporta le stored procedure, poi, una
gin avremmo dovuto scrivere codice simile al seguente: soluzione ancora più comoda è quella di sfruttare le sto-
red procedure parametriche (a patto di non concatena-
VBScript re le stringhe all’interno della stored procedure!): in que-
<% sto modo potrete unire al vantaggio dei parametri, che di
Dim sQuery ‘As String fatto impediscono l’injection, anche un incremento me-
sQuery = “SELECT * FROM Users WHERE UserID = ? AND Password = dio delle prestazioni. Infine, è sempre opportuno dare al-
?” l’utente corrente solo i permessi minimi sulle tabelle: su
un sito di pubblicazione in sola lettura, per esempio, è
Dim cmd ‘As ADODB.Command inutile avere anche il diritto di UPDATE o di DELETE (sa-
Set cmd = Server.CreateObject(“ADODB.Command”) rebbero utili solo all’hacker di turno).

10 VBJ N. 60 - Novembre/Dicembre 2004


DIFENDERSI DAGLI HACKER

Cross Site Scripting mo il nostro cookie. Anche in questo caso, finché siamo
Si tratta di una vulnerabilità legata al mondo Web e ba- noi a leggere il nostro cookie la situazione pare non es-
sata nuovamente sul fatto che spesso gli sviluppatori si sere grave. Ma se quel codice anziché mostrare con un
fidano troppo dei loro utenti e non ne controllano l’input. alert il cookie lo inviasse al sito di un hacker? Un hacker
Molto spesso nei siti Web capita di inserire dei dati all’in- può inviare migliaia di email a utenti della rete, tanto gli
terno di campi form, per la ricerca o per la registrazione, hacker la banda di rete non la pagano mai :-) a quanto
e di vedere questi stessi dati riproposti in fasi successi- pare, presentandole come email spedite dal sito affetto
ve. Per esempio, se eseguiamo una ricerca di solito la da Cross Site Scripting e chiedendo agli utenti di pre-
pagina con il risultato ci ricorda anche quale era il testo mere un link, per ottenere qualche offerta o regalo. Die-
da noi cercato. Ora proviamo a scrivere invece di “birre tro a quel link ci sarà una pagina reale del sito che ac-
rosse” il seguente testo: “<b>birre rosse</b>”. In HTML cetta Cross Site Scripting. Nel link ci sarà anche del co-
abbiamo scritto il testo in grassetto. Se la pagina con dice javascript inserito nella query string. Questo codice
il risultato della ricerca ci ripropone il testo birre rosse leggerà il vostro cookie per inviarlo a un sito dell’hacker
in grassetto e non “<b>birre rosse</b>” allora siamo in (ecco perchè si dice “Cross Site”) che a questo punto
presenza di un sito che potrebbe rendersi vulnerabile al potrà farsi credere voi e potrà fare shopping con la vo-
Cross Site Scripting. Proviamo infatti a scrivere “birre ros- stra carta di credito. Carino vero?
se <script>window.alert(‘Cross Site Scripting’);</script>” Anche in questo caso la prima misura da adottare è non
e a premere nuovamente il pulsante di ricerca ... sorpre- fidarsi mai dell’input ottenuto dagli utenti e, se deside-
si? Vi troverete di fronte a una finestra con il messaggio riamo riscriverlo in output, conviene sempre farne prima
“Cross Site Scripting”. Queste prime prove ci permetto- un HTML Encode.
no di capire che il programmatore che ha scritto il codice
della pagina di ricerca prende i dati in input da parte del- VBScript
l’utente e li mette sulla pagina senza fare alcun controllo. <% Response.Write Server.HtmlEncode(Request(“UserName”)) %>
Fino a qui non c’è nulla di sconvolgente. Ora pensiamo
al fatto che molto spesso i siti Web offrono la possibilità C#
di registrarsi e di farsi riconoscere. Pensiamo a un sito di Response.Write(Server.HtmlEncode(Request[“UserName”]));
commercio elettronico che registra la nostra carta di cre-
dito e ci riconosce sfruttando un cookie. A questo punto Inoltre possiamo decidere di aggiungere ai cookie che
proviamo a cercare “birre rosse <script>window.alert rilasciamo un attributo “HttpOnly” che ne impedirà l’ac-
(document.cookie);</script>” su quel sito. Se il sito è cesso da parte del codice JavaScript, rendendo di fatto
vulnerabile al Cross Site Scripting vedremo sullo scher- inutile un attacco di questo tipo.

Canonicalization
Con questo termine ci si riferisce a quella famiglia di at-
tacchi che si basano sull’uso di indirizzi di file o risorse
contraffatti o che si rivolgono ad applicazioni che utiliz-
zano l’input dell’utente per generare o fornire file. Han-
no fatto storia, nel recente passato, le email false firma-
te da hacker che si facevano credere Microsoft e che
raccomandavano di installare applicazioni o fix disponi-
bili a indirizzi che sembravano essere quelli di Microsoft,
ma che in realtà celavano gli indirizzi dei server utilizza-
ti dagli hacker.
Infatti un indirizzo come il seguente http://
www.microsoft.com:testomoltolungo@www.devleap.com/
a prima vista sembra corrispondere a www.microsoft.com,
in realtà il vero indirizzo è dopo il carattere @, quindi
www.devleap.com, mentre ciò che precede la chioccio-
la è solo la coppia nome utente e password, separati
dai due punti (:). Questo problema ha richiesto addirittu-
ra una fix di Internet Explorer che ha disabilitato il sup-
Figura 2 Evitare la navigazione sui percorsi superiori a porto a questo tipo di indirizzi.
quelli in cui è ospitata l’applicazione Web Ma nella Canonicalization rientrano anche i casi di at-
tacco in cui le applicazioni richiedono agli utenti dei nomi

N. 60 - Novembre/Dicembre 2004 VBJ 11


DIFENDERSI DAGLI HACKER

espliciti di file o da fornire o da salvare sul server. Pensia- ma prefissata. Avere 1000 thread che lavorano in paral-
mo a un’applicazione Web sviluppata con ASP.NET nella lelo a volte è peggio che non averne 100 che lavorano e
quale si chiede all’utente di fornire un nome di file da uti- una coda di attività da svolgere non appena vi saranno
lizzare per salvare il suo carrello prodotti. Dietro le quinte dei thread liberi per farlo. Un tipico esempio che faccio
la nostra applicazione utilizza quel nome per creare un in questo caso è quello relativo alla gestione degli erro-
file nella cartella relativa ./carrelli dell’applicazione Web. ri. Pensiamo a un’applicazione Web che ad ogni errore
Trovo decisamente insicuro e generalmente errato salva- manda una email al supporto prodotto in modalità sin-
re file su disco nelle applicazioni Web, ancor di più quan- crona, cioè utilizzando lo stesso thread che esegue la
do è l’utente finale a scegliere i nomi dei file, ma ciò non richiesta in errore. L’invio di una email richiede un mini-
toglie che vi siano parecchie applicazioni in produzione mo di tempo per risolvere l’indirizzo del server di posta e
su Internet che consentano di farlo. Ebbene, in un caso per il dialogo SMTP. Un hacker potrebbe sfruttare questo
come quello appena descritto un utente potrebbe forni- fatto per “ingozzare” il nostro server di richieste che ge-
re come nome di file “../web.config” ottenendo quale ri- nerano errori, consapevole del fatto che un errore con-
sultato quello di sovrascrivere il file web.config dell’appli- suma molte più risorse di una pagina normale, potendo
cazione, bloccandola. Oppure, nel caso di un download così saturare prima il nostro servizio.
di risorse, potrebbe tentare di spostarsi sul file system Se noi utilizzassimo un thread o un pool di thread, di-
usando percorsi relativi (come . e ..) riuscendo così a sca- verso da quello predefinito di .NET, sul quale accodare
ricare file per i quali non è autorizzato. le richieste di invio di email, le notifiche di errore non sa-
La soluzione a problemi di questo tipo è quella di im- rebbero più un’attività pesante per i singoli thread che
postare correttamente e in modo rigido i permessi sul- evadono le richieste, ma diventerebbero un’attività che
le ACL (Access Control List) del file system, evitare con viene svolta in background, quando ci sono risorse per
l’apposita opzione di IIS la navigazione sui percorsi su- farlo. Inoltre non ha senso mandare continuamente email
periori a quelli in cui è ospitata l’applicazione (“Enable tutte uguali che descrivono uno stesso errore. Oltre un
Parent Paths” disabilitato, Figura 2) e se possibile evi- certo limite è meglio mettersi in “regime di protezione”
tare in assoluto di richiedere agli utenti percorsi espliciti per evitare di intasare il server di posta, oltre che la ca-
di file o risorse fisiche. sella, del supporto prodotto.

Denial of Service Conclusioni


Sono attacchi organizzati e finalizzati a interrompere Le vulnerabilità del codice sono numerose e in questo
l’erogazione di un servizio o di un’applicazione. Di so- articolo abbiamo sfiorato le più frequenti e diffuse. In bi-
lito non sono realizzati per caso, ma sono rivolti a degli bliografia trovate alcuni testi e link per approfondire e in-
obiettivi precisi e scelti. Questi attacchi consistono nel tegrare l’argomento.
saturare le risorse (rete, memoria, CPU, ecc.) di un siste- In generale occorre essere consapevoli del fatto che
ma al fine di renderlo non disponibile. A volte lo scopo scrivere codice sicuro non è un’attività né semplice, né
finale è solo quello di neutralizzare un servizio, altre vol- tantomeno banale. Non bisogna mai assumere di essere
te il servizio viene neutralizzato per poi sostituirvisi con più furbi degli hacker e non si devono mai inventare del-
un servizio fittizio. le soluzioni fatte in casa. Scrivere codice sicuro richiede
Come programmatori possiamo solo fare del nostro me- tempo, attenzione e risorse. Come ho letto qualche tem-
glio per evitare che le nostre applicazioni siano vulnera- po fa sul sito della Università di Salerno: “Scrivere codi-
bili a questo tipo di attacchi, senza dimenticare comun- ce sicuro è lodevole, ma irrimediabilmente costoso”. Se
que che anche siti Web autorevoli e importanti in pas- vogliamo essere sviluppatori e consulenti seri dobbiamo
sato sono stati messi in ginocchio da questo tipo di at- mettere a budget questo costo, perchè l’alternativa è fare
tacchi, a volte portati a termine da ragazzi poco più che gli azzeccagarbugli.
adolescenti. A noi programmatori conviene per esempio
monitorare sempre il consumo di risorse e riciclare auto- Bibliografia
nomamente i servizi qualora consumino più di una deter- [1] Michael Howard, David LeBlanc - “Writing Secure
minata percentuale di soglia. Per un servizio che normal- Code, Second Edition”, Microsoft Press, 2002
mente consuma il 5% della CPU un consumo del 90% [2] Frank Swiderski, Window Snyder - “Threat Modeling”,
è una situazione sospetta e conviene non permettergli Microsoft Press, 2004
di arrivare a un simile livello, meglio fermarlo e riavviar- [3] Jason Bock, Tom Fischer, Nathan Smith, Pete
lo prima. Nel nostro codice possiamo cercare di arginare Stromquist - “.NET Security”, APress, 2002
queste situazioni evitando di creare indiscriminatamen-
te oggetti, thread e risorse in generale, ma magari crea- Riferimenti
re dei pacchetti (pool) di risorse, di dimensione massi- [4] http://msdn.microsoft.com/security/

12 VBJ N. 60 - Novembre/Dicembre 2004


DIFENDERSI DAGLI HACKER

La sicurezza
del codice managed
Vediamo alcune delle principali caratteristiche del Framework .NET rivolte
alla sicurezza del codice e delle applicazioni.

di Paolo Pialorsi

L
e applicazioni sviluppate con il Framework .NET C#
di Microsoft si dicono “managed” in quanto la loro // Dichiaro uno StringBuilder per una
esecuzione è “gestita” dal motore di esecuzione del stringa da 1 a 10 caratteri
Framework stesso, cioè dal Common Language Runtime StringBuilder bld = new StringBuilder(1,
(CLR). Tra i vantaggi offerti dal CLR vi è il fatto che ci viene 10);
messa a disposizione un’infrastruttura di sicurezza nativa,
in molti casi automatica e per noi trasparente. Vediamo in for (Int32 c = 0; c < 10; c++) {
questo articolo alcune delle caratteristiche più importanti bld.Append(“a”);
orientate alla sicurezza del codice managed. }
bld.ToString();
Gestione della memoria
Una delle prime caratteristiche che il Framework .NET ci Nell’esempio appena visto, un even-
offre è la gestione automatica della memoria, sia in termini tuale tentativo di scrivere più di 10
di allocazione che di rilascio delle risorse. Grazie a questa caratteri all’interno dello StringBuil-
possibilità i classici problemi di sicurezza quali buffer over- der solleverebbe un’eccezione (Argu-
run, overflow su numeri o indici e simili, diventano tecnica- mentOutOfRangeException).
mente impossibili da realizzare. Pensiamo al buffer over- Il gestore di memoria del CLR è inol-
run su stack, ottenuto sovraccaricando il contenuto di una tre in grado di controllare l’accesso
stringa, come mostrato nell’articolo precedente. alle singole aree di memoria, consen-
Con .NET le stringhe sono oggetti che vengono allocati in tendoci di isolare eventuali assem-
memoria nel momento in cui vengono assegnate. Alla loro bly in esecuzione all’interno di uno
variazione di contenuto avremo una riallocazione, in una stesso processo, sfruttando il con-
nuova area di memoria, dello spazio necessario a conte- cetto di Application Domain. Possia-
nere il nuovo valore. mo pensare agli AppDomain come
Per come ho appena descritto la situazione, è impossi- a dei sotto-processi, completamen-
bile utilizzare una stringa .NET per eseguire un attacco di te isolati e protetti tra loro, eseguiti
tipo buffer overrun. Nel caso in cui poi vogliamo costrui- all’interno di un unico processo del
re dinamicamente delle stringhe di dimensione massima sistema operativo. Tutte le volte che
prefissata, esiste la classe StringBuilder che di lavoro fa abbiamo l’esigenza di eseguire del
proprio questo: codice managed con privilegi parti-
colari o isolandolo dal resto del con-
testo applicativo, possiamo creare un
AppDomain ed eseguire al suo inter-
Paolo Pialorsi è un consulente e autore specializzato nello
no il codice. In questo modo avre-
sviluppo di Web Service e soluzioni Web con il Framework
.NET di Microsoft. Lavora nell’omonima società Pialorsi mo pieno isolamento tra i vari livel-
Sistemi S.r.l. e fa parte del gruppo DevLeap. Può essere li di accesso al sistema. Il motore di
contattato via email: paolo@devleap.it. ASP.NET sfrutta proprio il concetto

N. 60 - Novembre/Dicembre 2004 VBJ 13


DIFENDERSI DAGLI HACKER

Innanzitutto si deve creare un’istanza di IsolatedStora-


geFile, in questo esempio si richiede uno storage locale
in base all’utente e all’assembly corrente (GetUserStore-
ForAssembly). Ottenuto un riferimento allo storage pos-
siamo creare file, directory, stream di byte su file, ecc.
Nell’esempio creiamo un IsolatedStorageFileStream, per
scrivere sul disco virtuale un file di testo puro. Per impo-
stazione predefinita le applicazioni managed che scari-
chiamo da Internet non hanno accesso, per motivi di si-
curezza, al file system fisico delle nostre macchine, ma
possono tranquillamente utilizzare l’Isolated Storage. Esi-
ste anche un tool a riga di comando (STOREADM.EXE)
che permette di gestire ed eventualmente cancellare gli
Isolated Storage creati.
Figura 1 L’applicazione di amministrazione di
NET Framework Strong name
Quando creiamo un progetto con Visual Studio .NET
o con qualsiasi editor di codice .NET e poi lo compilia-
di AppDomain per eseguire diverse applicazioni Web al- mo, otteniamo come risultato uno o più file .EXE, .DLL o
l’interno di uno stesso processo, garantendo così l’iso- .NETMODULE, che rappresentano degli assembly o dei
lamento completo tra le aree di memoria assegnate alle moduli di un assembly. In .NET l’assembly può essere
singole applicazioni. definito come “unità minima di deployment” e in pratica
rappresenta uno o più file, che costituiscono una parti-
Isolated storage colare versione di una porzione di codice. Dal punto di
Sempre a proposito di isolamento il Framework .NET vista del deployment, cioè del rilascio del codice, con
ci offre la possibilità di utilizzare un file system virtuale, .NET non esiste nulla di più piccolo rispetto all’assembly.
chiamato Isolated Storage, che consente di salvare file Questo significa che al minimo potremo gestire l’installa-
anche ad applicazioni non autorizzate ad accedere al zione e il versioning degli assembly, ma non dei singoli
disco fisico della macchina client. file di cui sono costituiti.
Più avanti in questo articolo, quando parleremo di Code Ogni volta che generiamo un assembly, di solito com-
Access Security, le cose risulteranno più chiare, per ora pilando un progetto con Visual Studio .NET, otteniamo
assumiamo che l’Isolated Storage sia un disco virtuale, un assembly mono-modulo, cioè costituito di un solo file.
sul quale un nostro applicativo managed può lavorare Durante la compilazione possiamo decidere di associa-
come se fosse un disco vero. re all’assembly una serie di informazioni come il nome,
Inoltre rispetto a un disco reale vi è il fatto che pos- la cultura, la versione e volendo anche una firma digitale
siamo definire delle quote e associare il file system a basata sul suo contenuto, sfruttando un algoritmo a chiavi
singoli utenti e/o applicazioni (assembly), per un’even- asimmetriche (chiave pubblica e chiave privata). Queste
tuale condivisione di informazioni. Per utilizzarlo dob- informazioni in Visual Studio .NET si trovano nei file au-
biamo fare riferimento alle classi del namespace Syste togenerati con nome AssemblyInfo.cs o AssemblyInfo.vb.
m.IO.IsolatedStorage nel modo seguente: Come impostazione predefinita un assembly autogenera-
to da Visual Studio .NET è dotato solo di nome e cultura
C# neutrale. Possiamo però modificare il file AssemblyInfo.*
IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStore e inserire anche altre informazioni:
ForAssembly();
C#
using(IsolatedStorageFileStream fs = new IsolatedStorageFile using System.Reflection;
Stream(“doc.txt”, FileMode.OpenOrCreate, FileAccess.Write, using System.Runtime.CompilerServices;
FileShare.None)) {
String testo = “testo da scrivere”; [assembly: AssemblyTitle(“Applicazione dimostrativa”)]
fs.Write(System.Text.Encoding.ASCII.GetBytes(testo), 0, [assembly: AssemblyCompany(“DevLeap”)]
testo.Length); [assembly: AssemblyProduct(“ClassLibraryDemo”)]
} [assembly: AssemblyCopyright(“(C) Paolo Pialorsi, 2004”)]
[assembly: AssemblyCulture(“it-IT”)]
isoFile.Close(); [assembly: AssemblyVersion(“1.0.0.1”)]

14 VBJ N. 60 - Novembre/Dicembre 2004


DIFENDERSI DAGLI HACKER

[assembly: AssemblyDelaySign(false)]
[assembly: AssemblyKeyFile(@”d:\keys.snk”)]

In questo esempio si dichiarano delle voci puramente in-


formative come il titolo, l’azienda produttrice, il nome del
prodotto e il copyright e delle informazioni particolari come
la versione (1.0.0.1), la cultura (it-IT) e un file (keys.snk)
da utilizzare per firmare digitalmente l’assembly.
Il file keys.snk a cui si riferisce il codice di esempio può
essere generato con il tool a riga di comando SN.EXE
nel modo seguente:

Command Prompt di Visual Studio .NET


SN.EXE –k Keys.snk
Figura 2 La gestione dei permessi facenti parte di un
dove –k indica di generare una coppia di chiavi e il secon- Permission Set
do parametro è il nome del file che conterrà le chiavi.
Se compiliamo un assembly che presenta tutte que-
ste informazioni (nome, cultura, versione e firma digita- comunque della manomissione in quanto all’interno del
le), esso si dirà dotato di uno “strong name”. Potremmo client è presente non solo il riferimento all’assembly, ma
tradurre questa espressione in “nome solido” o “nome anche il riferimento alla coppia di chiavi utilizzate origi-
sicuro”, in realtà trovo che suoni molto meglio la defini- nariamente per firmare l’assembly. Questa informazione
zione inglese, anche se il suo significato è proprio quel- è detta “publicKeyToken” e nuovamente, se non c’è cor-
lo di dare solidità e sicurezza a un assembly. Tutti gli as- rispondenza tra il publicKeyTone del client e quello del
sembly dotati di strong name infatti sono verificati e ve- server, il CLR blocca il caricamento dell’assembly segna-
rificabili rispetto alla firma digitale applicatagli. lando la manomissione.
Gli assembly con strong name possono essere instal-
lati nella stessa cartella delle singole applicazioni che li Code Access Security
usano, in questo caso si dicono assembly locali, oppu- Quando il CLR carica in memoria un assembly svolge
re nella Global Assembly Cache (GAC) e si dicono as- una serie di verifiche finalizzate a decidere quali permessi
sembly condivisi. di esecuzione concedergli. Queste verifiche sono basate
Se realizziamo un’applicazione .NET (client del compo- su una serie di prove (evidence) che consentono al CLR
nente) che utilizza un assembly locale (componente ser- di capire quale sia la provenienza dell’assembly (per es.
ver) con strong name, il motore del CLR, prima di cari- PC locale, internet, intranet, ecc.), se ha uno strong name
care in memoria l’assembly che rappresenta il compo- o meno, se è firmato con Authenticode, ecc. Sulla base
nente server, ne verificherà l’integrità rispetto alla firma di queste prove gli assembly vengono quindi associati a
digitale. Se qualcuno dovesse manomettere il contenu- dei gruppi (Code Group) ai quali poi sono associati dei
to dell’assembly rispetto a quando l’applicazione client permessi (Permission Set). I Code Group sono suddivisi
è stata compilata, il CLR se ne accorgerà, bloccando- in diversi livelli di Policy:
ne il caricamento.
Se invece utilizziamo un assembly condiviso, quindi in- • Enterprise: definisce le politiche di sicurezza a livello
serito nelle GAC, la verifica dell’integrità dell’assembly non di intera infrastruttura di rete (enterprise)
sarà ripetuta a ogni caricamento, ma sarà eseguita solo • Machine: dichiara le politiche relative al PC corrente
all’atto dell’inserimento nella GAC. La GAC infatti di default • User: descrive le politiche di sicurezza per l’utente
è accessibile in modifica solo ed esclusivamente a utenti corrente
membri del gruppo Administrators, quindi si assume che • AppDomain: configurabile da codice a livello di AppDo-
gli amministratori non manomettano intenzionalmente gli main
assembly rilasciati. Da questo ultimo concetto si evince
un’altra ragione (se non ve n’erano già abbastanza!) per Questi livelli sono configurati su ogni sistema con .NET
cui è di fondamentale importanza non sviluppare codice installato e sono gestibili sia dal prompt dei comandi, uti-
utilizzando un utente con diritti amministrativi. lizzando il tool CASPOL.EXE (CASPOL = Code Access
Se poi un hacker dovesse manomettere un assembly e Security Policy) sia - più comodamente - utilizzando un
successivamente ri-firmarlo con una nuova firma, basa- tool amministrativo con interfaccia grafica. Quest’ultimo
ta su una chiave privata diversa, il CLR si accorgerebbe tool si chiama “Microsoft .NET Framework 1.1 Configu-

N. 60 - Novembre/Dicembre 2004 VBJ 15


DIFENDERSI DAGLI HACKER

ration” (Figura 1) e consente di creare, all’interno dei pri- soft SQL Server, eventualmente impedendo l’uso di
mi tre livelli di policy, dei Code Group e Permission Set server SQL con connessioni a password nulla.
personalizzati.
Vediamo quindi come ragiona il CLR per decidere i per- Infine i Code Group hanno due flag che permettono ri-
messi da associare a un assembly. spettivamente di dichiarare l’esclusività dei loro Permis-
Gli assembly sono associati ai Code Group in base sion Set per gli assembly che vi appartengono e la non
a condizioni di appartenenza (Membership Conditions) ridefinibilità dei Permission Set che descrivono, a livelli
come le seguenti: di Policy più bassi.

• Application Directory: tutti gli assembly caricati dalla Il caricamento di un assembly


stessa cartella o da una cartella figlia di quella in cui Vi siete mai chiesti perchè un programma sviluppato con
è stato caricato l’assembly principale .NET, se eseguito da un disco di rete anzichè dal PC lo-
• Hash: l’hash code dell’assembly cale, può cambiare comportamento e in alcuni casi ad-
• Publisher: il produttore dell’assembly, individuato tra- dirittura non si avvia nemmeno, restituendoci un errore
mite un certificato Authenticode di sicurezza? Vediamo insieme, in questa sezione, il per-
• Site: il site di provenienza chè di questo comportamento.
• Strong name: il publicKeyToken del produttore ed Al caricamento dell’assembly il CLR legge le sue eviden-
eventualmente il nome e la versione esplicite dell’as- ce e stabilisce i Code Group, di ogni livello di Policy, ai
sembly quali appartiene. Per ogni livello di Policy poi viene fatta
• URL: la URL di provenienza o porzione di essa l’unione dei Permission Set associati ai Code Group cui
• Zone: la zona di provenienza del codice (My Compu- appartiene l’assembly.
ter, Local Intranet, Internet, Trusted Sites, Untrusted Nel caso di Code Group con il flag di esclusività, verrà
Sites) preso solo il suo Permission Set.
• Custom: criteri di appartenenza personalizzati Il risultato di questa prima fase è, per ogni livello di Po-
licy, un insieme di permessi, quelli ottenuti dall’unione dei
I permessi di cui sono costituiti i Permission Set pos- Permission Set.
sono essere scelti tra quelli predefiniti di .NET oppure A questo punto il CLR esegue l’intersezione di questi
essere permessi personalizzati, che possiamo creare e tre insiemi di permessi, per ricavare i reali permessi da
configurare noi stessi. associare all’assembly.
Alcuni dei permessi più utilizzati e predefiniti del Fra- Lo so, sembra un esame di Algebra del primo anno di
mework .NET sono (Figura 2): Ingegneria :-), ma cerchiamo di capire con un esempio
concreto.
• File IO: consente di definire le regole di accesso al Consideriamo un assembly (di nome ServiceProxy), di
file system, in termini di Read, Write, Append e Brow- tipo class library, con le seguenti caratteristiche:
se di file e risorse, eventualmente consentendo an-
che di impostare dei filtri sui path ai quali si conce- • URL di provenienza: http://www.devleap.com/
de l’accesso. Potremmo cioè concedere un accesso • Strong name publicKeyToken: 714cc0ec76570e52
completo al path C:\Temp e in sola lettura al path C:
\Documenti. Ipotizziamo che venga caricato in memoria da un altro
• Isolated Storage File: abilita l’accesso all’Isolated Sto- assembly che rappresenta un’applicazione Console (Ser-
rage (vedi sezioni precedenti) indicando anche la quo- viceClient).
ta massima consentita. Immaginiamo poi che nel nostro sistema siano configu-
• Registry: consente di abilitare l’accesso in varie mo- rati i seguenti Code Group a livello di macchina:
dalità (Read, Write, Create) alle chiavi del registro di
sistema. • CodeGroupDevLeapSiteMachine: vi appartengono
• Security: permette di configurare alcuni permessi qua- tutti gli assembly che provengono dalla URL http://
li l’esecuzione di codice, l’utilizzo di .NET Remoting, www.devleap.com/. È associato al seguente Permis-
la serializzazione di oggetti, le chiamate a codice un- sion Set:
managed, ecc. • File IO: sola lettura su C:\Program Files\DevLeap
• User Interface: consente di esporre un’interfaccia e basta
utente a finestre o meno, controllando anche il tipo • Isolated Storage File: permesso di accesso con
di messaggi Windows che si possono ricevere e l’ac- quota di 20Kb
cesso alla Clipboard. • CodeGroupDevLeapSNMachine: vi appartengono tutti
• SQL Client: abilita l’accesso a server di dati Micro- gli assembly che hanno uno strong name con il pu-

16 VBJ N. 60 - Novembre/Dicembre 2004


DIFENDERSI DAGLI HACKER

blicKeyToken ricavato dalla coppia di chiavi di Dev- Infatti questo è l’unico permesso in comune a tutti e tre
Leap. È associato al seguente Permission Set: i livelli di Policy. L’intersezione è l’operazione insiemistica
• File IO: controllo completo sul path C:\Temp corretta da eseguire in questo contesto, per evitare che
un utente o un PC possano avere permessi più ampi di
Il CLR analizzando queste informazioni saprà che l’as- quelli che la macchina o le regole di sicurezza della rete
sembly ServiceProxy appartiene a entrambi i CodeGroup, gli concederebbero. Cosa accade a un assembly, come
quindi i suoi permessi, relativamente al solo livello di po- quello dell’esempio precedente, che non ha il permes-
licy di tipo Machine, saranno: so di accedere al disco fisico del PC, ma solo al disco
virtuale (Isolated Storage), qualora tentasse di aprire un
• File IO: sola lettura su C:\Program Files\DevLeap e file, per esempio su C:\temp?
basta Una SecurityException ci informerà del problema, nel
• Isolate Storage File: permesso di accesso con quota caso in cui si tenti esplicitamente di eseguire un’opera-
di 20Kb zione non consentita.
• File IO: controllo completo sul path C:\Temp
Verifica e richiesta di permessi
Finchè siamo noi a creare e installare le nostre appli-
cazioni non dovremmo avere problemi a darci o farci as-
Se compiliamo un assembly segnare i permessi necessari al corretto funzionamento
del nostro codice. Quando però il software che svilup-
provvisto di nome, cultura, piamo viene reso disponibile a numerosi utenti, magari
versione e firma digitale, pacchettizzato, abbiamo l’esigenza di rilevare l’esisten-
za o meno di permessi per noi necessari, per evitare
esso si dirà dotato di uno che le nostre applicazioni vadano in crash (sollevando
una SecurityException) nel momento in cui cercano di
“strong name” svolgere operazioni non consentite. Possiamo assolve-
re a questa esigenza utilizzando due differenti tecniche
tra loro alternative.
Il primo modo di lavorare prevede l’utilizzo di classi che
Cioè appunto l’unione dei Permission Set dei singo- descrivono permessi, cioè classi che implementano l’in-
li Code Group del livello Machine ai quali ServiceProxy terfaccia IPermission, chiedendo al CLR, per esempio
appartiene. Ora ipotizziamo che esista a livello di Policy tramite l’apposito metodo Demand dell’interfaccia, se il
Enterprise un Code Group, definito dall’amministratore particolare permesso è concesso o meno.
di rete, come il seguente:
C#
• CodeGroupDevLeapSiteEnterprise: vi appartengono FileIOPermission fp = new FileIOPermission(FileIOPermission
tutti gli assembly che provengono dalla URL http:// Access.Read, @”C:\TEMP\INFO.TXT”);
www.devleap.com/. È associato al seguente Permis- try {
sion Set: fp.Demand();
• Isolated Storage File: permesso di accesso con }
quota di 20Kb catch (SecurityException secEx) {
// Se rilevo una SecurityException
Quindi il nostro ServiceProxy apparterrà anche a que- // significa che non ho il permesso
sto Code Group. // di accedere il file
Il livello di Policy relativo all’utente corrente conside- Console.WriteLine(secEx.Message);
riamolo dotato di un solo Code Group, che comprende }
qualunque assembly, con associato un unico Permission
Set che consente tutto a tutti (FullTrust). Nell’esempio precedente si richiede il permesso di ac-
Si tratta tra l’altro della impostazione predefinita. Il CLR cesso in lettura al file C:\TEMP\INFO.TXT. Si noti il fatto
dovrà a questo punto intersecare i permessi di ciascun che la richiesta è inclusa in un blocco try...catch al fine
livello di Policy, ottenendo come risultato il seguente per- di interecettare l’eventuale SecurityException. Il funzio-
messo: namento di tutti i metodi Demand di tutti i permessi pre-
vede infatti lo scatenarsi di una SecurityException, se la
• Isolated Storage File: permesso di accesso con quo- richiesta del permesso fallisce. Quella appena vista si
ta di 20Kb dice verifica imperativa dei permessi.

N. 60 - Novembre/Dicembre 2004 VBJ 17


DIFENDERSI DAGLI HACKER

In alternativa all’approccio imperativo possiamo utilizzare


la sicurezza cosiddetta dichiarativa, che prevede l’utilizzo
di attributi .NET, derivati dalla classe base CodeAccess-
SecurityAttribute. In questo secondo caso sarà il motore
del CLR a eseguire per conto nostro la verifica del per-
messo da noi dichiarato tramite attributo, al momento del
caricamento dell’assembly o della classe, piuttosto che
all’esecuzione di un particolare metodo. Anche in que-
sto caso, se il permesso è negato, avremo una Securi-
tyException da intercettare e gestire.

C#
static void Main(string[] args) {
try {
LeggiFile();
}
catch (SecurityException secEx) {
Console.WriteLine(secEx.Message);
}
} Figura 3 Schema dell’esame dello stack di chiamata
durante la verifica dei permessi
[FileIOPermission(SecurityAction.Demand, Read=@”C:\TEMP\
INFO.TXT”)]
static void LeggiFile() { ta, verificando che tutti gli assembly nello stack abbia-
//... no quel permesso.
} Se e solo se tutti gli assembly nello stack hanno il per-
messo di eseguire una determinata operazione, allora
Come si vede nell’esempio, il metodo LeggiFile è deco- quest’ultima sarà autorizzata (Figura 3), altrimenti avre-
rato con l’attributo FileIOPermission, che informa il CLR mo la solita SecurityException.
del fatto che per essere eseguito deve avere accesso in Qualora poi avessimo un assembly che deve sempre e
lettura al solito file C:\TEMP\INFO.TXT. comunque poter eseguire una determinata operazione,
Un aspetto di Code Access Security interessante e da per la quale è autorizzato, a prescindere dai permessi dei
non sottovalutare è il fatto che i permessi, così come le chiamanti, possiamo richiedere - assumendocene tutti
classi per il loro utilizzo dichiarativo e/o imperativo, sono i rischi - che venga disattivata la verifica a ritroso nello
personalizzabili ed estendibili. stack di chiamata, per un particolare permesso.
Possiamo cioè creare all’interno delle nostre applica-
zioni .NET una nostra logica di sicurezza, basata su per- Ecco un esempio:
messi personalizzati e classi *Permission e *Permissio-
nAttribute personalizzate. C#
public void LeggiFile() {
Stack di chiamata e FullTrust FileIOPermission fp = new FileIOPermission(FileIOPermission
L’ultimo aspetto da valutare, in questa breve carrel- Access.Read, @”C:\TEMP\INFO.TXT”);
lata sulle funzionalità di sicurezza di .NET, riguarda il fp.Assert();
caso in cui un hacker tenti di utilizzare un nostro as- // ...
sembly, autorizzato a svolgere determinate operazioni FileIOPermission.RevertAssert();
in quanto nostro. }
In sostanza a un hacker potrebbe venire la tentazione
di creare una sorta di “Cavallo di Troia” che sfrutti i per- In questo caso il metodo LeggiFile potrà accedere al
messi concessi ai nostri assembly per i suoi scopi. file C:\TEMP\INFO.TXT, qualora ne abbia il permesso,
Fortunatamente per come funziona il motore di au- anche se dovesse essere invocato da un oggetto che
torizzazione del CLR, in caso di chiamate annidate, il non ha quel permesso, perchè il metodo Assert spegne
CLR non si limita a verificare che l’assembly corrente la verifica dello stack per quel particolare permesso (Fi-
abbia i permessi per eseguire una determinata opera- leIOPermission), con quella configurazione (Read su C:
zione, ma ripercorre a ritroso l’intero stack di chiama- \TEMP\INFO.TXT).

18 VBJ N. 60 - Novembre/Dicembre 2004


DIFENDERSI DAGLI HACKER

Si noti che viene richiamato anche un metodo statico lizzare l’attributo StrongNameIdentityPermissionAttribute,
FileIOPermission.RevertAssert che abilita nuovamente la che prevede la possibilità di dichiarare esplicitamente da
verifica del permesso sullo stack di chiamata. quali assembly accettiamo di essere invocati, applican-
Una chiamata al metodo Assert ha effetto solo fino dolo alle classi e/o ai metodi da proteggere.
alla fine dell’esecuzione del metodo che la contiene, In questo caso però gli assembly chiamanti devono avere
tuttavia per avere il livello massimo di sicurezza con- almeno uno strong name, per poter essere identificati.
viene disabilitare la verifica di un particolare permesso
sullo stack di chiamata, solo per il tempo strettamen- C#
te necessario. [StrongNameIdentityPermission(SecurityAction.LinkDemand,
Sempre a proposito della verifica dei permessi sull’in- PublicKey=”024048...”)]
tero stack di chiamata, si presenta un'ulteriore situa- public class Utility {
zione interessante. //...
Gli assembly inseriti nella GAC, dal momento che sono }
dotati di strong name e che solo gli utenti del gruppo Ad-
ministrators possono gestirli, vengono automaticamente Non abbassiamo mai la guardia
dotati di un Permission Set illimitato (FullTrust). Quando si parla di sicurezza si dice spesso che il
Da un lato questo aspetto deve farci riflettere sull’op- massimo livello di sicurezza di un’applicazione è dato
portunità o meno di mettere un assembly nella GAC, dal suo punto più debole.
dall’altro pone un problema: per impostazione predefi- Prestiamo molta attenzione a questo concetto e ricor-
nita un assembly non può essere utilizzato da altri as- diamoci che anche se il Framework .NET è decisamente
sembly con un livello di trust più basso del suo. più sicuro rispetto agli ambienti di sviluppo preceden-
ti, ogni volta che utilizziamo dei componenti unmana-
ged come DLL sviluppate in C++ o le API di Windows,
possiamo perdere alcune delle sicurezze che .NET ci
Quando il CLR carica in me- offre. Per esempio se passiamo una stringa da .NET a
moria un assembly svolge una API e per caso questa API è soggetta a problemi
di buffer overrun, sapere che in .NET i buffer overrun
una serie di verifiche finalizza- non sono possibili ci servirà a poco... l’hacker tenterà
te a decidere quali permessi di attaccarci sfruttando la vulnerabilità della API.
Teniamo inoltre presente il fatto che questi meccani-
di esecuzione concedergli smi di sicurezza non si sostituiscono ai criteri di sicu-
rezza nativi di Windows, ma si integrano con essi.
La cosa migliore è sfruttare tutte le possibilità a no-
stra disposizione per realizzare soluzioni il più possi-
Questo fatto è ancora una volta dovuto alla volontà di bile sicure. Infine non dimentichiamo mai di costrui-
evitare che un hacker tenti di sfruttare componenti al- re le nostre applicazioni affinché richiedano i privilegi
trui a proprio vantaggio. minimi sul sistema. Un utente appartenente al gruppo
Nel caso in cui si voglia quindi utilizzare un assem- degli Administrators infatti sarà in grado di spegnere
bly inserito nella GAC, invocandolo con altri assembly completamente la sicurezza del CLR, rendendo inuti-
che contrariamente a lui non siano dotati di FullTrust, li tutti i nostri sforzi.
per esempio perchè non hanno uno strong name e non
sono inseriti nella GAC, dobbiamo esplicitamente au- Bibliografia
torizzarli. [1] Jason Bock, Tom Fischer, Nathan Smith, Pete
Per farlo si utilizza un attributo .NET che si chiama Al- Stromquist - “.NET Security”, APress, 2002
lowPartiallyTrustedCallersAttribute che va esplicitato nel-
l’assembly da inserire nella GAC. Riferimenti
Nel file AssemblyInfo.* dovremmo inserire una riga [2] http://msdn.microsoft.com/security/
come la seguente: [3] http://www.devleap.com/Default.aspx?IdCategoria=
SECURITY
C# [4] http://www.devleap.com/SchedaArticolo.aspx?IdAr
[assembly:AllowPartiallyTrustedCallers] ticolo=10150
[5] http://msdn.microsoft.com/msdnmag/issues/04/04/
Per evitare poi che chiunque possa caricare il nostro as- SecurityBriefs/default.aspx
sembly dalla GAC e invocarne gli oggetti, possiamo uti- [6] http://blogs.msdn.com/shawnfa/

N. 60 - Novembre/Dicembre 2004 VBJ 19


DIFENDERSI DAGLI HACKER

Applicazioni sicure
con IIS 6 e ASP .NET
L’accoppiata IIS 6 e ASP.NET garantisce la possibilità di creare e far funzio-
nare in maniera sicura applicazioni web con pochi e semplici sforzi. Anche se
entrambi i sistemi sono già sicuri appena installati, è necessario un ulteriore
tocco per garantire alle nostre applicazioni un elevato livello di sicurezza.

di Daniele Bochicchio

S
pesso quando si parla di sicurezza, si pensa a strani La sicurezza di un sistema infat-
e complicati esorcismi, trucchi o danze propiziato- ti si può suddividere in questi ulte-
rie da eseguire per aggiungere alle nostre applica- riori punti:
zioni web quello che è in realtà uno dei punti di partenza
e dei requisiti imprescindibili di ogni software. • sicurezza della rete fisica:
La sicurezza in realtà si compone di poche e semplici re- firewall hardware, politiche di ac-
gole da seguire, sia in fase di sviluppo che in fase di defi- cesso alle porte TCP/IP e conse-
nizione dei requisiti delle nostre applicazioni. guenti filtri sul traffico;
Nel caso del web, infatti, ogni singola richiesta che arriva • sicurezza del web server e del da-
al web server è potenzialmente dannosa e maligna, fino a tabase server: adeguata configura-
prova contraria: dobbiamo quindi cominciare ad imparare zione, in base alle best practices;
a schermare il nostro lavoro dall’esterno, per fare in modo • sicurezza a livello applicativo:
che sia a prova di attacco e che gli eventuali dati trattati scrivere codice (ASP.NET e T-SQL)
siano al sicuro da occhi indiscreti. che non presenti punti di ingresso
per chi cerca di attaccarci.
La sicurezza viene da lontano
Dobbiamo prestare attenzione, in realtà, ai diversi ambiti In questo articolo ci soffermeremo
in cui la sicurezza va applicata. Possiamo scrivere applica- in modo particolare sugli aspetti del
zioni sicure dal punto di vista applicativo, ma poi farle gira- secondo punto, che riguardano nello
re su un server non configurato a dovere per inficiarne co- specifico IIS 6, e su alcuni “trucchi”
munque la bontà. Dunque prima di analizzare alcune tecni- da poter sfruttare per rendere più si-
che utili per scrivere applicazioni web sicure, dobbiamo as- cure le nostre applicazioni basate su
sicurarci che la piattaforma sulla quale andiamo ad instal- ASP.NET. Potrete trovare ampie trat-
lare le nostre applicazioni non sia da meno. tazioni della sicurezza a livello appli-
cativo negli altri articoli di questo nu-
mero della rivista.

La sicurezza è essere proattivi:


proteggiamo il web server
Daniele Bochicchio è il content manager di ASPItalia.com, Essere proattivi vuol dire prevedere
community che si occupa di ASP.NET, Classic ASP e eventuali pericoli che possono esse-
Windows Server System. Si occupa di consulenza e re causati in maniera volontaria o ca-
formazione, specie su ASP.NET, e scrive per diverse
suale nella nostra applicazione. Un’ap-
riviste e siti. È Microsoft .NET MVP, un riconoscimento
per il suo impegno a supporto delle community e per plicazione che si blocca (per qualsiasi
l’esperienza maturata negli anni. Il suo blog è all’indirizzo motivo) non deve in alcun modo in-
http://blogs.aspitalia.com/daniele/ fluire sulle altre presenti sullo stesso

20 VBJ N. 60 - Novembre/Dicembre 2004


DIFENDERSI DAGLI HACKER

Meno privilegi, più robustezza


IIS 6 gira sfruttando “local service” come utente anzi-
ché “network service”, potendo contare dunque su pri-
vilegi decisamente inferiori.
Se c’è un problema realmente legato ad IIS è la confi-
gurazione delle ACL di Windows, ovvero dei privilegi di
accesso al file system.
Appare ovvio che meno privilegi un processo ha, più
robusta risulterà l’intera piattaforma.
La regola che vige in questi casi è quella di impostare
sul server i permessi in modo che ogni singola applica-
zione possa accedere solo ai file che sono strettamente
necessari e sicuramente in modo che non possa asso-
lutamente arrivare a file di sistema.
Questa semplice regola molte volte è ignorata anche in
Figura 1 Per ogni application pool va specificato un re- ambienti di hosting condiviso, dove ogni utente ha ac-
lativo utente di Windows da utilizzare. In figura cesso ai file degli altri, in barba alla privacy (oltre che al
la maschera che mostra come cambiarlo
buon senso).
Per fare in modo che ognuno possa accedere solo a
ciò che gli è concesso, è sufficiente creare per ogni ap-
web server. Può sembrare un’eventualità remota ed un plicazione un utente, da inserire in un gruppo specifico
concetto del tutto scontato, ma se state usando IIS 5 (e chiamato ad esempio “Web Users”, ed impostare sulle
quindi Windows 2000 Server) con molta probabilità una directory che compongono l’applicazione l’accesso solo
situazione del genere è tutt’altro che lontana da realizzar- a quell’utente.
si. Ci sono metodi per evitare che ciò accada se state an- Successivamente dovremo dire ad IIS 6 di utilizza-
cora utilizzando IIS5, ma sono solo palliativi. Un approccio re come utente per quell’applicazione l’utente appena
che può funzionare, ma che porta ad un consumo mag- creato. Si può trovare un’insieme di schermate che spie-
giore di risorse, è la modalità di isolamento alta, così chia- gano meglio il procedimento in Figura 1 e 2. Si arriva
mata per via della possibilità, in questo stato, di isolare il a questa maschera dalle proprietà dell’application pool,
processo che causa problemi rispetto agli altri. Tuttavia si alla voce Identity.
tratta solo di un palliativo temporaneo. IIS 5 nasce in un Il risultato sarà che l’accesso alle risorse del file sy-
periodo profondamente differente rispetto ad IIS 6, di cui stem (oltre che alle altre risorse del sistema) sarà effet-
ci occuperemo a breve, e quindi risente di alcune man- tuato proprio con questo utente, rendendo impossibile
canze a livello architetturale che fortunatamente la versio- per una pagina scritta male (o i cui parametri siano for-
ne 6 ha colmato in toto. zati ad arte) l’accesso a risorse contenute al di fuori dal-
Tanto per cominciare, “IIS 6 è secure by default”, che vuol lo spazio riservato all’applicazione.
dire, molto semplicemente, che è sicuro anche appena in-
stallato. A differenza di IIS 5, non viene installato se non Cosa può fare IIS 6 per noi: gli application pool
esplicitamente chiesto dall’amministratore del server, e non Dal punto di vista della sicurezza, un ruolo fondamen-
viene abilitata di default nessuna delle estensioni esterne. tale è giocato anche dagli application pool, che sono un
Questo vuol dire che appena installato, il web server si li- po’ il concetto di web application (o virtual directory) di
miterà ad elaborare solo le semplici pagine HTML e che il IIS 5 rivisto in una chiave differente, dove all’interno di
supporto per ASP.NET, ASP, WebDav e Front Page Exten- un application pool possono essere presenti più web ap-
sions va attivato esplicitamente ed a parte, dalla console di plication che condividono certi parametri.
gestione di IIS. Questo è un vantaggio perché ci permette IIS 5 ha un’architettura profondamente diversa rispetto
di rendere funzionanti solo quelle caratteristiche che sono a quella di IIS 6. In pratica è tutto racchiuso in un solo
strettamente necessarie, evitando di tenere attive funzio- processo, inetinfo.exe, che si occupa di gestire i proces-
nalità, come WebDav, che ci espongo al rischio di attac- si necessari all’esecuzione delle richieste, l’amministra-
chi da remoto. In caso di motore disabilitato, la richiesta zione del web server ed il controllo sullo stato di salu-
produrrà un errore 404 (risorsa non trovata). te dello stesso.
È da notare che l’errore 404 si avrà anche in presenza È chiaro che se un sito web porta ad un crash di
del file richiesto sul disco fisso: se il motore associato è inetinfo.exe, il relativo sistema di controllo va in crash
disabilitato, non ci sarà verso per il web server di fornire con il servizio stesso, rendendo di fatto non funzionante
quel file al client. il sistema di controllo.

N. 60 - Novembre/Dicembre 2004 VBJ 21


DIFENDERSI DAGLI HACKER

IIS 6 invece si basa su 3 processi separati, ciascuno Cosa possiamo fare noi per IIS 6
dei quali assolve a compiti specifici ([1]). Che IIS 6 sia sicuro è ormai, a circa un anno e mezzo
In particolare il processo responsabile per la buona sa- dalla sua uscita ufficiale, un dato di fatto.
lute degli application pool è W3SVC, che si occupa di far Lo dimostra anche la realtà: in questi 18 mesi i bug
partire i worker process e di monitorarne lo stato. Questo scoperti per IIS 6 non hanno paragone con le preceden-
vuol dire che se un application pool ha problemi, IIS 6 è ti versioni. Sono semplicemente zero.
in grado di isolarlo e terminarne l’esecuzione, se neces- Tutto dipende dal fatto, con buona probabilità, che IIS 6
sario, senza intaccare minimamente gli altri application è stato riscritto completamente rispetto ad IIS 4 o 5 per
pool (e quindi le altre applicazioni) presenti. essere, prima di tutto, un web server sicuro, affidabile e
Tra l’altro viene effettuato un recovery automatico in caso dalla garantite prestazioni.
di consumo eccessivo di risorse, come CPU o memoria Per rendere però ancora più sicuro il nostro web server
(parametro impostabile dall’amministratore), in caso di dobbiamo metterci del nostro, evitando alcuni comporta-
blocco del processo per un numero di secondi stabilito e menti ed osservando alcune semplici regole.
cosa molto importante, anche in caso di buffer overflow, Partiamo da ciò che bisogna sempre evitare. Di sicu-
togliendo quindi una potenziale porta di ingresso. ro, come già detto, una cattiva pratica è quella di usare
Gli altri due processi, non meno importanti in senso as- un utente per tutti gli application pool (e quindi per tutte
soluto ma di minor interesse per quanto riguarda la sicu- le web application). Vanno impostati i permessi in modo
rezza, sono http.sys e W3Core: tale che non sia possibile sfruttare problemi delle appli-
cazioni per arrivare a leggere il contenuto del disco. Allo
• HTTP.SYS, come l’estensione stessa suggeri- stesso modo, è consigliabile tenere i siti in una partizio-
sce, è un driver in kernel mode, che si occupa sempli- ne separata, in modo che eventuali tentativi di forzatu-
cemente di prendere le richieste che arrivano allo stack ra dei parametri non permettano facilmente l’accesso al
di rete di Windows Server 2003 e di smistarle, attraver- disco di sistema.
so W3Core, al worker process per l’esecuzione. Il fatto È poi ovviamente consigliato non tenere attivi motori
che http.sys sia nella kernel area anziché nella user area non utilizzati (come WebDav) e servizi non sfruttati (come
non rappresenta un pericolo, perché è un processo che POP3, SMTP o NNTP). Il sistema più semplice per veri-
di fatto non esegue codice, ma smista solo richieste e ficare che non lo siano è mostrato in Figura 3. Come in
risposte sullo stack di rete. tutto ciò che riguarda IIS, ci si arriva seguendo la voce
• W3Core, si occupa dell’hosting vero e proprio “Internet Information Services” all’interno di “Administra-
dei worker process (sono quei processi w3wp.exe che tive tools” nel pannello di controllo.
possiamo notare con il task manager). È poi un atto quasi dovuto disattivare il default web site
e l’administrative web site. Infine IIS 6 non andrebbe usa-
to su domain controller, per evitare di compromettere un
server che ricopre un ruolo centrale all’interno di una rete
basata su Windows.
Di particolare interesse per la serie “cose da fare asso-
lutamente”, c’è la buona regola di tenere sempre da par-
te gli eseguibili CGI, in modo che il permesso di esecu-
zione venga dato solo ad un certo percorso, e l’elimina-
zione del permesso Execute per l’utente anonimo sulla
directory %windir%.
Ed ovviamente vige la regola di tenere sempre aggior-
nato, con patch e quant’altro, il server.

Protezione contro il code injection in ASP.NET 1.1


Nelle altre pagine della rivista avrete certamente trova-
to spunti di riflessioni su questa tecnica.
Senza soffermarci ulteriormente sugli aspetti specifici di
questo attacco, cerchiamo di capire invece cosa ASP.NET
1.1 fa di default per noi, in modo da poter valutare, even-
Figura 2 Più di un sito web può appartenere ad un
tualmente, gli ambiti in cui possiamo muoverci per per-
application pool, anche se è consigliabile
specificarne uno differente per ogni sito, in sonalizzarne l’efficacia.
modo da isolare l’accesso alla risorse Nella versione 1.1 (ed attenzione che questo controllo
non viene effettuato con la 1.0) di ASP.NET c’è dunque

22 VBJ N. 60 - Novembre/Dicembre 2004


DIFENDERSI DAGLI HACKER

Un sistema per evitare questa incertezza consiste nella


creazione di un semplice HttpModule (vedi [2]).
Gli HttpModule sono delle classi particolari che per-
mettono di intercettare gli eventi di un’applicazione
ASP.NET.
Nel nostro caso l’evento che sfrutteremo è ovviamen-
te OnError della classe HttpApplication.

C#
Private void OnError (Object o, EventArgs e) {

// verifica tipo di errore


Exception ex = Server.GetLastError();

// intercetta solo l’errore specifico


Figura 3 Si può notare come sia semplice disattivare il if (ex.GetType().ToString() == “System.Web.HttpRequest
supporto per un motore non richiesto. ValidationException”) {
In figura WebDav, ad esempio, è disattivato
Response.Redirect(“injection.aspx”);
}
}
un controllo built-in, che può essere disattivato con la
proprietà validateRequest della direttiva @Pages (o del- La pagina injection.aspx mostrerà un testo specifico che
l’analoga proprietà nel web.config su base di tutta l’ap- avverte l’utente del problema, migliorando quindi allo stes-
plicazione), che in breve controlla che all’interno di coo- so tempo l’usabilità della nostra applicazione.
kie, querystring o campi inviati tramite il metodo post, È utile notare che questo controllo non mette al riparo
non si verifichino queste condizioni: da XSS (Cross Site Scripting) o SQL-injection, dunque è
solo un primo scudo, ma vale sempre la pena di effettuare
• presenza del carattere “<” seguito da un carattere al- successivamente dei controlli personalizzati sull’input.
fanumerico, oppure da “!”;
• presenza della sequenza “&#”, per prevenire l’in- Nascondere gli errori e metterli in cassaforte
serimento di codici particolari, legati ad entities Quante volte vi è capitato di arrivare su un sito con
(X)HTML; un’immagine oggettivamente antiestetica, come quel-
• presenza del termine “script”, seguita da spazi o vir- la mostrata in Figura 4?
gole, per evitare inserimenti di codice Javascript; Oltre alla bruttezza (ed alla poca cura che chi ha svi-
• presenza del termine “expression”, per evitare injec- luppato quel sito ha messo nel proprio lavoro), c’è da
tion di codice Javascript attraverso la forma “style=a: considerare anche la pericolosità che un errore così
expression(javascript)”; dettagliato può offrire all’utente.
• presenza del termine “on” preceduto da spazi, seguito Non è raro che venga mostrato, in certi ambiti e con il
da caratteri alfanumerici, seguito da spazi e dal sim- debug attivato, il pezzo di codice che ha causato l’er-
bolo “=”, per prevenire injection di codice come “on- rore, che magari può offrire all’utente un meccanismo
Click=”. per forzare la nostra applicazione.
Spesso il motivo per cui viene rimossa la pagina per-
Se uno di questi controlli non viene passato, viene sonalizzata risiede nel fatto che se c’è bisogno di fare
scatenata un’eccezione di tipo HttpRequestValidatio- “debug” in tempo reale su un sito che è già in produ-
nException. zione, non ci sono altre strade percorribili con quello
Di default purtroppo non c’è modo di visualizzare una che ASP.NET ci offre.
pagina personalizzata che spieghi all’utente il motivo Di default possiamo infatti impostare una pagina d’er-
dell’errore, visto che ASP.NET lo considera una norma- rore personalizzata che viene visualizzata sempre, mai
le eccezione non gestita e per questo viene invocata la o solo se si accede alla pagina dallo stesso indirizzo
pagina di errore personalizzata o viene mostrato il soli- IP sul quale gira.
to messaggio. Molto spesso invece l’intervento è effettuato da un
Di fatto l’utente non è in grado di capire se l’errore è indirizzo IP remoto, che magari è sempre fisso e non
stato provocato da qualcosa che ha fatto o dalla nostra cambia, e può tornare utile aggiungere un ulteriore op-
applicazione. zione a quelle offerte all’interno del web.config, per po-

N. 60 - Novembre/Dicembre 2004 VBJ 23


DIFENDERSI DAGLI HACKER

ter specificare un ulteriore indirizzo IP a cui dare ac- );


cesso all’errore completo. // ripulisco gli errori
La soluzione in questo caso è, ancora una volta, l’uso Context.ClearError();
di un HttpModule che banalmente verifichi se la richiesta // blocco l’esecuzione del resto
arriva dall’IP specificato all’interno del web.config. Context.Response.End();
Solo in questo caso il flusso della risposta sarà blocca- }
to e sarà stampato a video, sfruttando il codice che se- }
gue, lo stesso identico errore che ASP.NET mostra quan-
do gli errori personalizzati sono disabilitati. Perché il tutto abbia un senso, ancora una volta andre-
mo ad intercettare l’evento OnError della classe HttpAppli-
C# cation, costruendo un HttpModule che se ne occupi [3],
private void OnError(object o, EventArgs e) oppure aggiungendo più semplicemente questo controllo
{ all’HttpModule che abbiamo creato in precedenza.
HttpContext Context = HttpContext.Current; Una volta compilata la classe, l’assembly generato va
// ricava indirizzo IP locale e in web.config inserito nella directory /bin/ dell’applicazione (o in GAC)
string localIP = Context.Request.UserHostAddress; e va registrato il relativo riferimento all’HttpModule all’in-
string localIPconfig = ConfigurationSettings.AppSettings terno del web.config.
[“localIP”]; Il codice può essere ovviamente modificato, in modo che
il controllo non venga fatto solo sull’IP, ma ad esempio
if (localIP == localIPconfig) sfruttando la Forms Authentication di ASP.NET, in base
{ al role associato all’utente [4].
Context.Response.Clear(); Con questo semplice accorgimento abbiamo dunque
reso il nostro lavoro ancora più sicuro.
HttpException ex = (HttpException)Context.Server.GetLast
Error(); Conclusioni
Come si può notare, la sicurezza è un argomento dav-
// errore specifico o generico vero semplice, che spesso si risolve più che altro nell’ap-
Context.Response.Write((ex.GetHtmlErrorMessage()!= null)? plicazione del buon senso, oltre che di qualche trucco
ex.GetHtmlErrorMessage(): imparato con il tempo (o con letture a tema).
String.Concat(“<pre>”, Nel caso specifico, sia IIS 6 che ASP.NET ci danno
Context.Server.GetLastError().ToString(), un’ottima mano, considerato che partire su una piatta-
“</pre>”) forma robusta permette di arrivare più facilmente a quello
che è un prerequisito del quale non ci
si può dimenticare: la sicurezza.

Riferimenti
[1] Gli application pool di IIS 6 – Da-
niele Bochicchio
http://www.aspitalia.com/articoli/
win2003/iis6_application_pool.aspx
[2] HttpModule e HttpHandler – Danie-
le Bochicchio
http://blogs.aspitalia.com/daniele/
post53.aspx
[3] #528 - Visualizzare l’errore esteso di
ASP.NET in base all’indirizzo IP di con-
nessione – Daniele Bochicchio
http://www.aspitalia.com/liste/usag/
script.aspx?ID=528
[4] Autenticazione di ASP.NET: For-
ms Authentication con roles - An-
Figura 4 Un anonimo ma molto dettagliato errore può contenere molte infor- drea Zani
mazioni utili per chi tenta di attaccare la nostra applicazione! http://www.aspitalia.com/articoli/
aspplus/formauthroles.aspx

24 VBJ N. 60 - Novembre/Dicembre 2004


DIFENDERSI DAGLI HACKER

Sviluppare senza
essere amministratori
Sviluppare applicazioni senza essere amministratori è importante per la
sicurezza e per scrivere applicazioni eseguibili con il minimo dei privilegi
necessari. Vediamo cosa c’è da sapere su Windows e Visual Studio .NET e
quali tool sono utili per affrontare questo scenario.

di Marco Russo

S
crivere software è un’operazione complessa che ri- è LocalSystem un’eventuale vulnerabi-
chiede al programmatore un controllo più o meno lità può consentire l’accesso a tutte le
completo sulla macchina che sta utilizzando. risorse del sistema, mentre se l’uten-
Questa esigenza, unita a un errato luogo comune secondo te ha i diritti minimi per eseguire l’ap-
cui molte attività (come il debug) richiedono un utente am- plicazione web, ma non può accedere
ministratore, contribuisce ad avere una percentuale altissi- ad altre risorse, i danni derivati da un
ma di sviluppatori che usano quotidianamente un utente con attacco sono più limitati. Analogamen-
privilegi amministrativi per fare tutte le operazioni, dalla na- te, un utente amministratore che apre
vigazione in internet alla lettura della posta all’installazione l’allegato a una mail o naviga sul web
dei tool di cui ha bisogno. La mia personale statistica, ba- può installare (magari inavvertitamente)
sata su sondaggi empirici fatti in conferenze e corsi tenuti qualsiasi software sul suo PC e ha i di-
nell’ultimo anno, valuta questa maggioranza nel 90-95% dei ritti di modificare tutti i file del sistema
programmatori. Bene, è ora di cambiare queste brutte abi- operativo e l’intero registry. Cosa c’en-
tudini! Già, perché usare quotidianamente un account am- trano i programmatori in tutto questo?
ministratore è pericoloso per un utente normale, ma per un Prima di tutto, anche noi siamo uten-
programmatore è addirittura sbagliato. Accusare in questo ti e in quanto tali dovremmo adottare
modo una percentuale così alta di colleghi è volutamente dei comportamenti sicuri. In secon-
provocatorio, ma ci sono delle buone ragioni per dirlo: ve- do luogo, il software che realizziamo
diamo quali sono e come fare per cambiare abitudini. deve essere progettato per poter es-
sere eseguito con il minimo dei privilegi
Perché è giusto farlo necessari: può sembrare un’esigenza
La sicurezza è un problema che va affrontato da tanti punti banale, ma se quotidianamente si usa
di vista. Quello che ci interessa esaminare in questo articolo un utente con privilegi amministrativi,
è la necessità di eseguire il codice con il minimo dei privilegi come si può essere sicuri di scrivere
necessari, così da limitare i danni in caso di errore o attacco. del codice che sarà utilizzabile anche
Un classico esempio è IIS: se l’utente che esegue il servizio da utenti normali? Certo, si potrebbe
usare un utente di test con cui effettua-
re tutte le verifiche del caso, ma nulla
è più istruttivo che mettersi nei panni
dell’utente comune e vedere che tipo
di esperienza può dover subire.
Marco Russo è un consulente specializzato nello sviluppo Usare un utente non amministrato-
di applicazioni con .NET Framework e nella realizzazione di
re per un programmatore ha un dupli-
soluzioni di Business Intelligence. Autore, docente, speaker
a conferenze, fa parte del gruppo DevLeap. Può essere ce vantaggio: consente di adottare un
contattato via email: marco@devleap.it. Mantiene un blog comportamento più sicuro in qualità
all’indirizzo: http://blogs.devleap.com/marco.blog. di utente e permette di comprende-

N. 60 - Novembre/Dicembre 2004 VBJ 25


DIFENDERSI DAGLI HACKER

runas /user:administrator program.exe

L’uso nidificato di RunAs permette la creazione di una


finestra con un utente locale che, però, accede in rete con
un access token del dominio (presupponendo che l’uten-
te amministratore locale della macchina non sia anche un
utente del dominio). Questa combinazione è importantis-
sima quando si lavora in rete, anche soltanto per instal-
lare una patch disponibile su un server remoto.

runas /user:administrator “runas /netonly /user:DOMAIN\username


cmd.exe”

Avviare un’applicazione con queste tecniche è scomo-


do (ogni volta viene richiesta la password dell’ammini-
stratore), ma il suo uso dovrebbe essere un’eccezione e
non la regola. Purtroppo in un primo momento sembra
l’unica soluzione per avviare tutti quei programmi che,
Figura 1 Per default un utente ha diritti di sola lettura su con un utente non amministratore, si rifiutano di partire
HKEY_LOCAL_MACHINE senza nemmeno fornire una chiara spiegazione dell’er-
rore che si verifica.
Molti a questo punto desistono e tornano nel vituperato
re prima e meglio gli errori da evitare (anche osservando gruppo amministrativo, ma sicuramente chi legge questo
quelli dei programmi che non sono scritti così bene). articolo non vorrà gettare la spugna tanto presto. Il più
delle volte il problema di un’applicazione che non par-
Primo ostacolo: l’esperienza da utente te con un utente normale è attribuibile a uno scorretto
Se modificare il proprio utente rimuovendolo dal grup- uso di Registry o file su disco. Per capire come risolvere
po di amministratori non presentasse degli effetti col- i problemi è necessario comprenderne la causa e quin-
laterali, questo articolo non avrebbe ragione di esiste- di trarre le prime lezioni su come scrivere un programma
re. L’esperienza iniziale di un utente qualsiasi (non solo eseguibile con il minimo dei privilegi.
di un programmatore) è normalmente traumatica. Dopo All’installazione di Windows il registry e i file su disco
aver abbandonato il gruppo degli onnipotenti (gli ammi- sono protetti con delle ACL (Access Control List) che
nistratori), al nuovo logon vi accorgerete di avere mol- definiscono chi può fare che cosa. Nel Registry tutte le
te limitazioni: voci all’interno di HKEY_LOCAL_MACHINE sono visibili
in lettura da tutti gli utenti, ma sono modificabili solo dal
• Non potete installare applicazioni. gruppo di amministratori (come si può vedere in Figu-
• Non potete installare plug-in e ActiveX su Internet ra 1). Per vedere le ACL associate al registry è neces-
Explorer. sario usare Regedit su Windows XP e Windows 2003,
• Non potete aggiornare le applicazioni esistenti. mentre su Windows NT 4 e Windows 2000 si usa Rege-
• Alcune applicazioni già installate non si possono più dt32. Sul disco tutti i dati nelle directory di sistema (tipi-
avviare o presentano dei problemi di funzionamento. camente c:\windows o c:\winnt) e dei programmi (come
c:\Programmi o c:\Program Files) e i file nella root (c:\)
Ce n’è abbastanza per desistere da subito. La maggior sono visibili in lettura a tutti gli utenti e modificabili solo
parte dei problemi si possono aggirare con “RunAs…” dagli utenti nei gruppi Administrators e Power Users. No-
(SHIFT + clic col tasto destro sull’icona di un’applicazio- tare che far parte del gruppo Power Users non è molto
ne) che consente di avviare un processo utilizzando un diverso, in termini di mancanza di sicurezza, dall’appar-
utente differente, chiedendone l’autenticazione. tenere al gruppo di amministratori, quindi per il nostro ra-
Il programma è avviato con un access token (informa- gionamento è ugualmente sconsigliabile associare il pro-
zioni che descrivono l’utente) diverso da quello con cui prio utente a tale gruppo.
si stanno eseguendo le altre applicazioni. Quando un’applicazione si rifiuta di partire con un uten-
Un’alternativa all’interfaccia utente è l’uso del coman- te normale, ma funziona regolarmente se avviata da un
do RunAs, che consente di creare dei batch che ese- amministratore, nel 99% dei casi il motivo è che tenta
guono applicazioni, pannelli di controllo o console am- un’operazione non autorizzata sul registry o sul disco.
ministrative: Se le applicazioni fossero scritte seguendo fedelmente i

26 VBJ N. 60 - Novembre/Dicembre 2004


DIFENDERSI DAGLI HACKER

Va notato che a volte l’errore è veramente banale: se


un’applicazione ha bisogno di leggere un file ma al mo-
mento dell’apertura non specifica che essa avviene in
modalità read-only, il sistema operativo genera un erro-
re (il classico access denied) già in fase di apertura del
file; questo spiega lo sconcerto di chi cerca inutilmen-
te nel proprio sorgente delle funzioni di scrittura su file
senza trovarne. Attenzione perciò a specificare sempre i
privilegi minimi anche quando si apre una risorsa (un file,
una connessione di rete, una porta di comunicazione), ri-
chiedendo solo i servizi minimi indispensabili per la fun-
zionalità richiesta successivamente. Se il file deve inve-
ce essere modificabile, è necessario metterlo in una di-
rectory adeguata: all’interno della cartella C:\Documents
and Settings esistono directory diverse per ogni utente
all’interno delle quali sono memorizzati i documenti per-
sonali, la configurazione del menu Start e dati specifi-
ci per l’utente delle applicazioni installate. È importan-
te ricordare che tutte le directory “speciali” come que-
ste devono essere ottenute con funzioni apposite come
SHGetFolderPath.
Se il programma è nostro, quindi, correggiamo l’errore,
usiamo la tecnica giusta, ricompiliamo e possiamo usare
l’applicazione con un utente normale. Sviluppando senza
essere amministratori ci si accorgerà molto presto di pro-
blemi simili e il costo necessario a risolvere il problema
sarà bassissimo: più un bug invecchia, più la sua elimi-
Figura 2 Impostazione di uno shortcut equivalente a un
RunAs automatico per ogni avvio nazione diventa costosa (il caso peggiore è quando arri-
va fino all’utente finale).
Quando però il programma non è nostro e non abbia-
dettami delle tante linee guida e dei requisiti per ottenere mo il codice sorgente, ci sono poche alternative. Se sia-
il logo Windows non ci sarebbe molto da dire, purtrop- mo fortunati, c’è una versione più recente che è scritta
po il mondo reale non segue le regole e dobbiamo an- meglio; se siamo sfortunati, dobbiamo tenerci l’applica-
che considerare che molte applicazioni nascono su Win- zione scritta male.
dows 9x, dove in pratica non esiste il concetto di utente Per evitare di dover ricorrere a RunAs tutte le volte,
come lo intendiamo oggi e quindi tutti possono fare tut- possiamo modificare (con un utente amministratore!) le
to ovunque sul disco… ACL della zona incriminata, registry o disco che sia. Ma
Senza pretendere di essere esaustivi, riassumiamo al- come sapere cosa toccare? Una tattica un po’ grosso-
cuni degli errori commessi più di frequente, ripassando lana è quella di individuare il nodo principale sul regi-
le regole che violano: stry e la directory dell’applicazione sul disco e modifi-
care le ACL per tutti i file e tutte le directory (o le chiavi
• Non si può scrivere su file e directory di sistema (come di registry) contenute, assegnando il privilegio di scrittu-
c:\windows): alcune applicazioni creano e/o scrivo- ra anche a tutti gli utenti che vogliamo abilitare all’uso
no dei file .INI o dei file che dovrebbero lasciare una del programma.
traccia dell’avvenuto uso del programma in una cer- Un approccio migliore, però, consiste nel limitare la
ta data, come sistema di controllo della scadenza di modifica delle ACL ai soli punti in cui ciò è indispensa-
una versione demo. bile: per esempio il singolo file (o chiave di registry) og-
• Non si può scrivere su file e directory contenuti nella getto del tentativo di modifica. Il problema è capire cosa
directory dei programmi (come c:\programmi): molte toccare.
applicazioni usano dei file contenuti in queste cartelle
come file di dati dell’applicazione, per esempio crea- Analizzare il comportamento dei programmi
no un file di configurazione che viene modificato se Il vantaggio di avere i sorgenti di un programma è che
l’utente cambia le impostazioni del programma; per si può avviare il debugger e aspettare che succeda qual-
queste necessità esistono delle directory apposite. cosa, magari controllando quale chiamata genera inizial-

N. 60 - Novembre/Dicembre 2004 VBJ 27


DIFENDERSI DAGLI HACKER

mente un errore che porta all’interruzione ed eventual- di seguire. Semplicemente, questo è il male minore: un
mente all’uscita dall’applicazione. Se però non si dispone eventuale attacco può danneggiare alcune risorse dell’ap-
di queste informazioni (o non si ha il tempo e/o la capa- plicazione attaccata ma non va a intaccare altre risorse
cità di addentrarsi nella giungla di codice scritto da ter- o altre applicazioni della stessa macchina.
zi), una strategia forse addirittura migliore è quella di os- Certo, la soluzione ideale resta quella di correggere il
servare l’applicazione dall’esterno utilizzando degli stru- software, ma fino a che ciò non avviene si cerca di limi-
menti adatti. tare i potenziali danni.
RegMon e FileMon sono due utility scritte da Mark La mia esperienza è che i primi due giorni sarete molto
Russinovich e Bryce Cogswell (e disponibili su arrabbiati con chi scrive male i programmi perché tutto
www.sysinternals.com) che consentono di tracciare tut- il ciclo di attività per individuare i problemi descritti e ri-
te le chiamate alle API di Windows responsabili, rispetti- solverli è piuttosto lungo e noioso (tolti i primi due casi
vamente, dell’accesso al registry e ai file. Per usare que- che potreste trovare divertenti, visto che si tratta di una
ste utility è necessario essere amministratori, perché in- cosa nuova). Questa arrabbiatura è però un’utile lezione
stallano dinamicamente un driver che intercetta le chia- per imparare a scrivere meglio il proprio software.
mate API Win32 interessate.
Questi strumenti consentono di definire dei filtri (è uti- Visual Studio .NET
le filtrare solo le chiamate fatte dal processo analizzato) Terminato il primo periodo di adattamento come uten-
e di osservare, tra le altre cose, l’esito della chiamata e te non amministratore, l’ostacolo successivo consiste nel
i diritti di accesso richiesti. capire come usare Visual Studio .NET senza limitazioni
Per esempio, un programma che tenti di aprire in lettura/ particolari. In generale, l’utente sviluppatore dovrebbe ap-
scrittura un file di configurazione genera una chiamata partenere a questi gruppi locali:
Open che fallisce; analizzando il nome del file e i diritti
richiesti sarà facile individuare l’entità minima (il file) a cui • Users
apportare modifiche della ACL (si concederà il diritto di • Debugger Users
modifica al singolo utente o al gruppo Users). Per l’ac- • VS Developers
cesso al registry la tecnica è analoga anche se gli stru-
menti usati sono diversi. Come abbiamo già detto, l’utente non deve apparte-
Dal punto di vista della sicurezza il fatto di aumentare i nere ai gruppi Administrators e Power Users. Per lo svi-
privilegi di accesso ad alcuni file posti in zone “critiche” luppo e il debug di applicazioni Web sono necessarie al-
del disco non va contro i principi che stiamo cercando tre impostazioni che vedremo più avanti. Alcune attivi-
tà, però, restano necessariamente prerogativa degli am-
ministratori:

• Registrazione di componenti COM (regsvr32/


regasm)
• Installazione di assembly nella GAC (gacutil)
• Installazione di componenti .NET nel catalogo COM+
(regsvcs)

In questi casi si è obbligati a rinunciare alla funzionalità


dei post-build step di Visual Studio .NET, effettuando la
registrazione a mano con un utente amministratore.
Per effettuare il debug l’utente deve avere dei diritti par-
ticolari, che abbiamo già ottenuto assegnando l’utente al
gruppo Debugger Users (in realtà ciò che conta è il dirit-
to SeDebugPrivilege associato all’access token, ma Vi-
sual Studio aggiorna già le policy assegnando tale dirit-
to al gruppo Debugger Users).
.NET impone però un’ulteriore limitazione rispetto al de-
Figura 3 Impostazione dell’Application Pool con l’utente bug di un processo eseguito con un utente diverso: per
usato per sviluppare: le directory virtuali corri-
fare ciò è necessario essere amministratori (non è così
spondenti alle applicazioni web sviluppate do-
vranno essere assegnate a questo Application per le applicazioni unmanaged).
Pool (che va creato manualmente). La limitazione non è percepibile per le applicazioni Win-
dows Forms eseguite dall’interno dell’IDE di Visual Studio,

28 VBJ N. 60 - Novembre/Dicembre 2004


DIFENDERSI DAGLI HACKER

ma coinvolge chi sviluppa dei servizi o delle applicazioni


Web e chi vuole fare debug in remoto. La cosa migliore,
in questi casi, è quella di eseguire l’applicazione con lo
stesso utente con cui si fa il debug. Se il debug avvie-
ne in remoto, l’utente usato deve avere il privilegio Se-
DebugPrivilege anche sulla macchina remota (dove, se
non c’è Visual Studio, il gruppo Debugger Users non è
stato creato, quindi bisogna modificare le policy a mano)
e deve essere amministratore della macchina remota se
l’applicazione è di tipo .NET (managed).

Applicazioni Web
Per lo sviluppo e il debug di applicazioni Web vale la
pena fare un discorso a parte, perché entrano in gioco
diversi fattori.
Per quanto riguarda lo sviluppo, la creazione di un’ap-
plicazione ASP.NET da Visual Studio può presentare un
problema se si usano le Front Page Server Extension
anziché il file share [1]: poiché il default è la modalità di Figura 4 Associazione di una directory virtuale all’Appli-
connessione file share, questo non è un bug così noto. cation Pool usato per il debug delle applicazioni
L’appartenenza al gruppo VS Developers garantisce i di-
ritti necessari per la creazione di una Virtual Directory in
IIS, ma in caso contrario (per es. server web remoto) è Application Pool, consentendo così di differenziare gli
sempre possibile creare la Virtual Directory con un uten- utenti per applicazioni ASP.NET diverse.
te che ha privilegi sufficienti (per es. amministratore) per L’utente assegnato all’Application Pool (il nostro uten-
poi creare il relativo progetto in Visual Studio con l’uten- te, se vogliamo fare debug) deve appartenere al gruppo
te normale. IIS_WPG perché sia utilizzabile con ASP.NET. In Figura 3
Per il debug di un’applicazione ASP.NET bisogna con- è visibile la configurazione di un Application Pool creato
siderare due aspetti: l’utente con cui gira l’applicazione per fare debug (l’utente associato è lo stesso usato per
e i diritti sulle directory usate da ASP.NET. sviluppare e fare debug).
L’utente si può modificare impostando in IIS 5 (Win- In Figura 4 è evidenziato come si associa una virtual
dows XP) il tag processModel di ASP.NET (notare la pas- directory di IIS a un Application Pool (in questo caso De-
sword in chiaro, che si può cifrare con l’utility aspnet_ buggable App).
setreg [2]): L’utente usato deve avere anche il diritto di accedere in
lettura e scrittura alle directory usate da ASP.NET, come
<processModel enable=”true” la directory in cui sono generati gli assembly a partire
userName=”DOMAIN\username” dalle pagine ASPX (Temporary ASP.NET Files, per cui il
password=”pwd” gruppo IIS_WPG ha già Full Control). Il ricorso a Filemon
/ > consente di individuare eventuali problemi di questo tipo,
in genere causati da componenti o librerie esterne usa-
Con IIS6 (Windows 2003), invece, si agisce creando un te dall’applicazione web (in particolare se usate compo-
Application Pool: ogni Virtual Directory è assegnata a un nenti COM).
Su MSDN è disponibile un documento [3] che descri-
ve molto bene i passi operativi necessari per impostare
Riquadro 1 Esecuzione con credenziali diverse le configurazioni che abbiamo analizzato in questo arti-
colo rispetto all’uso di Visual Studio .NET con un utente
non amministratore.
Nelle impostazioni avanzate delle proprietà di uno shortcut
è possibile specificare la richiesta di credenziali diverse per
ogni esecuzione, evitando di dover cercare il menu RunAs Applicazioni Visual Basic 6
tutte le volte. Se, anche solo per necessità, sviluppate ancora con
La Figura 2 mostra questa configurazione sullo shortcut Visual Basic 6, purtroppo dovete fare i conti con il fatto
di FileMon.
che VB6 non è stato minimamente pensato per svilup-
pare senza essere amministratori; più che l’ambiente
di sviluppo, poi, molti problemi li creano i tanti com-

N. 60 - Novembre/Dicembre 2004 VBJ 29


DIFENDERSI DAGLI HACKER

ponenti di cui è dotato VB6. Il problema è in parte ag- Per partire con il piede giusto è necessario capire qua-
girabile con i sistemi già descritti, usando Filemon e li sono le problematiche più frequenti e come modifica-
Regmon per capire dove modificare l’accesso a par- re (per il minimo indispensabile) i diritti di directory e re-
ti del disco e del registry, ma va detto che a volte la gistry necessari a evitare il ricorso al RunAs, che resta
colpa (di sviluppare con utenti amministratori) non è indispensabile per alcune attività di tipo amministrativo.
tutta degli sviluppatori ma anche di chi gli ha dato le Strumenti come Filemon e Regmon sono preziosissimi
brutte abitudini... per individuare queste criticità.

Conclusioni Riferimenti
Usare Windows e svilupparci con un utente non-ammi- [1] Bug di Visual Studio, KB833896, http://
nistratore è doveroso. L’esperienza da utenti non ammi- support.microsoft.com/default.aspx?scid=kb;EN-
nistratori aumenta la consapevolezza dei comportamenti US;833896
che vanno evitati per scrivere applicazioni utilizzabili con [2] Uso di aspnet_setreg, KB329290, http://
il minimo dei privilegi. support.microsoft.com/default.aspx?scid=kb;EN-
Purtroppo non è semplice e immediato come potreb- US;329290
be e dovrebbe essere. In futuro (con Longhorn, la pros- [3] Developing Software in Visual Studio .NET with Non-
sima versione di Windows) ci saranno molte novità per Administrative Privileges, http://msdn.microsoft.com/
migliorare la situazione, ma negli anni che ci separano library/en-us/dv_vstechart/html/tchDevelopingSoftwa
da questo traguardo non ci si può permettere di conti- reInVisualStudioNETWithNon-AdministrativePrivileges
nuare a seguire comportamenti a rischio. .asp

30 VBJ N. 60 - Novembre/Dicembre 2004


BEGINNER

Programmare Excel da
Visual Basic .NET
Analisi di tre soluzioni per trasferire dati a Excel usando Visual Basic .NET e le classi del
.NET framework

di Fabio Scagliola

Q
uesto articolo descrive tre soluzioni diverse per dati), System.IO (per scrivere nel
trasferire dati a Excel usando Visual Basic .NET file di testo) e System.Xml (per
e le classi del .NET framework. manipolare i documenti XML).
La prima soluzione usa il modello a oggetti di Excel per In particolare il codice dei listati
scrivere nelle celle del foglio di lavoro, come si farebbe presuppone le direttive seguenti.
attraverso l’interfaccia grafica del programma, e crea un
grafico basato sui dati trasferiti. Imports System
La seconda soluzione crea un file di testo separato da Imports System.Data
tabulazioni che Excel possa aprire come se fosse una Imports System.Data.SqlClient
cartella di lavoro. Imports System.IO
Imports System.Xml
Imports System.Xml.Xsl

I dati
Le tre soluzioni estraggono dati dal
database Northwind su SQL Server
2000 eseguendo la stored procedure
CustOrdersDetail.
Dopo aver assegnato il numero di
un ordine al suo unico parametro
OrderID, la stored procedure
restituisce i dettagli di quell’ordine.
Per eseguirla, tutte le soluzioni
usano ADO .NET e in particolare
oggetti SqlConnection e
Figura 1 Aggiungere un riferimento alla libreria COM
SqlCommand. Poi le prime due
di Excel
useranno un SqlDataReader, e la
terza una coppia DataAdapter/
DataSet.
La terza soluzione crea un XML Spreadsheet. Tutte usano Il codice seguente, comune alle
le classi del namespace System.Data (per accedere ai tre soluzioni, crea un oggetto
SqlConnection per collegarsi al
database e un oggetto SqlCommand
per eseguire la stored procedure.
Fabio Scagliola (MCSD, MCSE, MCT) fornisce “software e
consulenza in materia di informatica” in giro per il mondo.
Torna spesso a Milano per insegnare nelle aule di Talento Dim cn As New SqlConnection(“DATA
Education & Training SOURCE=(local)\INSTANCE1;INITIAL

N. 60 - Novembre/Dicembre 2004 VBJ 31


BEGINNER

di prodotti. Per maggiori informazioni su ADO.NET si


Listato 1 Programmare il modello a oggetti di
veda [1].
Excel

Programmare il modello a oggetti di Excel


Dim cn As New SqlConnection(“DATA SOURCE=(local)\ I programmatori VB usano il modello a oggetti di Excel
INSTANCE1;INITIAL CATALOG=Northwind;USER ID=sa;PASSWORD (e di tutte le applicazioni Office) con maggiore naturalezza
=password”)
dei programmatori C#. Progettato per Visual Basic for
Dim cm As New SqlCommand(“CustOrdersDetail”, cn)
cm.CommandType = CommandType.StoredProcedure Applications, il modello include molti metodi che accettano
Dim OrderID As SqlParameter = cm.Parameters.Add(“@OrderI argomenti facoltativi (supportati solo da VB).
D”, SqlDbType.Int) Mentre i programmatori VB possono usare named
OrderID.Value = 11077
argument per assegnare valori solo agli argomenti
Try
cn.Open() necessari, i programmatori C# devono assegnare a ogni
Dim dr As SqlDataReader = cm.ExecuteReader() argomento facoltativo il valore Type.Missing o il valore
Dim xl As Excel.Application = New Excel.Application predefinito di quell’argomento. Inoltre, dal momento
xl.Visible = True
Dim wb As Excel.Workbook = xl.Workbooks.Add()
che C# non supporta proprietà con argomenti (indexer
Dim ws As Excel.Worksheet = wb.ActiveSheet a parte), i programmatori devono invocare i relativi metodi
ws.Cells(1, 1) = “Product name” accessori. Per esempio il metodo get_Range sostituisce
ws.Cells(1, 2) = “Unit price” la proprietà Range.
ws.Cells(1, 3) = “Quantity”
ws.Cells(1, 4) = “Discount” Considerate queste differenze, la prima soluzione
ws.Cells(1, 5) = “Total price” (Listato 1) usa il modello a oggetti di Excel per scrivere
ws.Range(“A1:E1”).Font.Bold = True nelle celle del foglio di lavoro come si farebbe attraverso
Dim RowIndex As Int32 = 2 la sua interfaccia grafica. Il codice presuppone di aver
While dr.Read()
ws.Cells(RowIndex, 1) = dr(“ProductName”) aggiunto al progetto un riferimento alla Microsoft Excel
ws.Cells(RowIndex, 2) = dr(“UnitPrice”) 10.0 Object Library (Figura 1).
ws.Cells(RowIndex, 3) = dr(“Quantity”) Prima di tutto si apre il collegamento al database
ws.Cells(RowIndex, 4) = dr(“Discount”)
con il metodo Open dell’oggetto SqlConnection. Poi si
ws.Cells(RowIndex, 5) = dr(“ExtendedPrice”)
RowIndex += 1 esegue la stored procedure con il metodo ExecuteReader
End While dell’oggetto SqlCommand per ottenere un oggetto
ws.Range(“B2:B” & RowIndex & “;E2:E” & SqlDataReader.
RowIndex).NumberFormat = “€ #,##0.00”
A questo punto entra in scena Excel. Il codice seguente
Dim ch As Excel.Chart = NuovoGrafico(ws.Range(“A1:
A26;E1:E26”), Excel.XlChartType.xlColumnClustered, “Cu- avvia Excel, lo rende visibile e crea una nuova cartella
stomer Orders Detail”) di lavoro vuota.
wb.SaveAs(“soluzione1.xls”)
xl.Quit()
Dim xl As Excel.Application = New Excel.Application
dr.Close()
Catch ex As Exception xl.Visible = True
Console.WriteLine(ex)
Finally
cn.Close()
End Try

CATALOG=Northwind;USER ID=sa;PASSWORD=password”)
Dim cm As New SqlCommand(“CustOrdersDetail”, cn)
cm.CommandType = CommandType.StoredProcedure
Dim OrderID As SqlParameter = cm.Parameters.Add(“@OrderID”,
SqlDbType.Int)
OrderID.Value = 11077

Dopo aver assegnato il valore opportuno alla


proprietà CommandType dell’oggetto SqlCommand
(per indicare il tipo di comando che sta per essere
eseguito), il codice crea un oggetto SqlParameter Figura 2 Il risultato del Listato 2
per assegnare al parametro della stored procedure
il numero dell’ordine che contiene il maggior numero

32 VBJ N. 60 - Novembre/Dicembre 2004


BEGINNER

Grafici
Il modello a oggetti di Excel rende semplice anche la
creazione di un grafico. Per esempio il Listato 2 mostra
il codice del metodo NuovoGrafico che restituisce un
oggetto Chart in cambio di tre argomenti. Il primo
argomento r deve essere un oggetto Range, per indicare
le celle contenenti i dati di origine del nuovo grafico.
Il secondo argomento chType deve essere il valore di uno
dei membri dell’enumeration XlChartType, per indicare il
tipo del nuovo grafico.
Il terzo argomento chTitle deve essere una stringa, per
indicare il titolo del nuovo grafico. La Figura 2 mostra
il risultato del metodo NuovoGrafico applicato alle celle
A1:A26;E1:E26 del foglio di lavoro creato dal Listato 1,
Figura 3 Il risultato del Listato 4 per ottenere un grafico di tipo “istogramma non in pila”
intitolato “Customer Orders Detail”. In pratica mostra il
risultato della seguente istruzione.

Dim wb As Excel.Workbook = xl.Workbooks.Add() Dim ch As Excel.Chart = NuovoGrafico(ws.Range(“A1:A26;E1:E26”),


Dim ws As Excel.Worksheet = wb.ActiveSheet Excel.XlChartType.xlColumnClustered, “Customer Orders Detail”)

Per creare una nuova cartella di lavoro vuota, si invoca il Per creare un grafico a partire dalle celle contenenti i
metodo Add dell’oggetto Workbooks senza assegnare un dati di origine, il metodo NuovoGrafico deve risalire al
valore al suo unico argomento facoltativo Template (che foglio di lavoro che contiene le celle e da qui alla cartella
serve a creare una nuova cartella di lavoro partendo da di lavoro che contiene il foglio.
un modello). Il metodo restituisce un oggetto Workbook,
la cui proprietà ActiveSheet contiene un riferimento al Dim ws As Excel.Worksheet = r.Worksheet
foglio di lavoro attivo, ovvero il primo dei tre fogli della Dim wb As Excel.Workbook = ws.Parent
cartella di lavoro vuota. Dim ch As Excel.Chart = wb.Charts.Add()
Per lavorare con le celle del foglio di lavoro si usa un
oggetto Range, che rappresenta una singola cella o un Prima di tutto legge il valore della proprietà Worksheet
intervallo di celle. dell’oggetto Range per risalire all’oggetto Worksheet,
Sia la proprietà Range sia la proprietà Cells restituiscono
un oggetto Range. La proprietà Range permette di
riferirsi a un intervallo di celle con la sintassi usata
Listato 2 Creare un grafico
normalmente da Excel. La proprietà Cells permette di
riferirsi a una singola cella come a un elemento di un array
bidimensionale, indicando gli indici (numerati a partire da
1) di riga e di colonna. La proprietà Range accetta due Function NuovoGrafico(ByVal r As Excel.Range, ByVal
chType As Excel.XlChartType, ByVal chTitle As String) As
argomenti: i riferimenti alle due celle agli estremi opposti
Excel.Chart
dell’intervallo. Dim ws As Excel.Worksheet = r.Worksheet
Si possono anche indicare i due riferimenti nel primo Dim wb As Excel.Workbook = ws.Parent
argomento separati dai due punti. In questo modo si Dim ch As Excel.Chart = wb.Charts.Add()
ch.SetSourceData(r)
possono anche definire intervalli di celle non adiacenti.
ch.ChartType = chType
Il codice seguente usa solo il primo argomento della ch.HasLegend = False
proprietà Range per applicare un formato a un intervallo ch.HasTitle = True
di celle non adiacenti. ch.ChartTitle.Text = chTitle
ch.PlotArea.Border.LineStyle = Excel.XlLineStyle.
xlLineStyleNone
ws.Range(“B2:B” & RowIndex & “;E2:E” & RowIndex).NumberFormat ch.PlotArea.Interior.ColorIndex = Excel.XlColorIndex.
= “€ #,##0.00” xlColorIndexNone
ch.Location(Excel.XlChartLocation.xlLocationAsObject,
ws.Name)
La soluzione usa sistematicamente la proprietà Range Return ch
per applicare formati a intervalli di celle e la proprietà End Function
Cells per scrivere dati nelle singole celle.

N. 60 - Novembre/Dicembre 2004 VBJ 33


BEGINNER

poi legge il valore della proprietà Parent dell’oggetto ch.HasTitle = True


Worksheet per risalire all’oggetto Workbook, infine ch.ChartTitle.Text = chTitle
invoca il metodo Add della collection Charts dell’oggetto
Workbook per creare un nuovo oggetto Chart. Infine, dopo aver reso trasparente bordo e sfondo
Creato il grafico, il codice usa il metodo SetSourceData dell’area del tracciato, usa il metodo Location dell’oggetto
per indicare le celle contenenti i dati di origine assegnando Chart al fine di rendere il grafico un oggetto sul foglio
al suo unico argomento il valore di r, ovvero un oggetto di lavoro.
Range.
ch.Location(Excel.XlChartLocation.xlLocationAsObject, ws.Name)
ch.SetSourceData(r)
Il metodo Location richiede due argomenti: il primo deve
Il codice assegna poi un valore ad alcune proprietà essere un membro dell’enumeration XlChartLocation (in
dell’oggetto Chart. questo caso xlLocationAsObject) e il secondo il nome
Anzitutto imposta il tipo di grafico assegnando alla del foglio di lavoro.
proprietà ChartType il valore di chType, ovvero uno dei
membri dell’enumeration XlChartType. Creare un file di testo
Excel permette di importare dati da un file di testo
ch.ChartType = chType separato da tabulazioni (e non solo) in un foglio di lavoro
per mezzo del Text Import Wizard.
Nasconde la legenda e mostra il titolo usando Se poi il nome del file termina con estensione xls,
rispettivamente le proprietà HasLegend e HasTitle e allora Excel lo apre come se fosse una cartella di lavoro
imposta il titolo assegnando la stringa chTitle alla proprietà senza nemmeno chiamare in causa il wizard. (Allo stesso
Text dell’oggetto ChartTitle. modo si potrebbe anche creare un file di testo separato
da virgole - CSV, un formato standard - ma il “trucco”
ch.HasLegend = False dell’estensione xls non funzionerebbe.)
La seconda soluzione (Listato 3) parte da questa
osservazione per creare un file di testo chiamato
Listato 3 Creare un file di testo soluzione2.xls che contenga nella prima riga i nomi dei
campi separati da una tabulazione e poi i dati strutturati,

Dim cn As New SqlConnection(“DATA SOURCE=(local)\


INSTANCE1;INITIAL CATALOG=Northwind;USER ID=sa;PASSWORD Listato 4 Creare un XML Spreadsheet
=password”)
Dim cm As New SqlCommand(“CustOrdersDetail”, cn)
cm.CommandType = CommandType.StoredProcedure
Dim OrderID As SqlParameter = cm.Parameters.Add(“@OrderI Dim cn As New SqlConnection(“DATA SOURCE=(local)\
D”, SqlDbType.Int) INSTANCE1;INITIAL CATALOG=Northwind;USER ID=sa;PASSWORD
OrderID.Value = 11077 =password”)
Try Dim cm As New SqlCommand(“CustOrdersDetail”, cn)
cn.Open() cm.CommandType = CommandType.StoredProcedure
Dim dr As SqlDataReader = cm.ExecuteReader() Dim OrderID As SqlParameter = cm.Parameters.Add(“@Order
Dim sw As StreamWriter = New StreamWriter(“soluzione2 ID”, SqlDbType.Int)
.xls”, False, System.Text.Encoding.Unicode) OrderID.Value = 11077
sw.WriteLine(“Product name” & vbTab & “UnitPrice” & Try
vbTab & “Quantity” & vbTab & “Discount” & vbTab & “Total cn.Open()
price”) Dim da As SqlDataAdapter = New SqlDataAdapter(cm)
While dr.Read() Dim ds As DataSet = New DataSet
sw.WriteLine(dr(“ProductName”) & vbTab & da.Fill(ds)
dr(“UnitPrice”) & vbTab & dr(“Quantity”) & vbTab & ds.WriteXml(“DataSet.xml”)
dr(“Discount”) & vbTab & dr(“ExtendedPrice”)) Dim xslt As XslTransform = New XslTransform
End While xslt.Load(“soluzione3.xslt”)
sw.Close() xslt.Transform(“DataSet.xml”, “soluzione3.xml”,
dr.Close() Nothing)
Catch ex As Exception Catch ex As Exception
Console.WriteLine(ex) Console.WriteLine(ex)
Finally Finally
cn.Close() cn.Close()
End Try End Try

34 VBJ N. 60 - Novembre/Dicembre 2004


BEGINNER

un record per ogni linea con i campi sempre separati


da una tabulazione. Dopo aver ottenuto un oggetto
Listato 5 Parte del DataSet salvato come docu-
mento XML
SqlDataReader come nella prima soluzione, il codice
seguente mostra come creare un oggetto StreamWriter
per scrivere nel file di testo. <?xml version=”1.0” standalone=”yes”?>
<NewDataSet>
<Table>
Dim sw As StreamWriter = New StreamWriter(“soluzione2.xls”,
<ProductName>Chang</ProductName>
False, System.Text.Encoding.Unicode) <UnitPrice>19.0000</UnitPrice>
sw.WriteLine(“Product name” & vbTab & “UnitPrice” & vbTab & <Quantity>24</Quantity>
“Quantity” & vbTab & “Discount” & vbTab & “Total price”) <Discount>20</Discount>
<ExtendedPrice>364.8000</ExtendedPrice>
</Table>
ll metodo WriteLine dell’oggetto StreamWriter scrive <Table>
testo seguito dai caratteri carriage return e line feed <ProductName>Aniseed Syrup</ProductName>
(codici 13 e 10). La costante vbTab concatenata alla <UnitPrice>10.0000</UnitPrice>
<Quantity>4</Quantity>
stringa rappresenta una tabulazione (codice 9). Così la <Discount>0</Discount>
seconda istruzione del codice precedente scrive i nomi <ExtendedPrice>40.0000</ExtendedPrice>
dei campi nella prima riga del file; allo stesso modo </Table>
l’istruzione contenuta nel ciclo While scrive una riga per <Table>
<ProductName>Chef Anton’s Cajun Seasoning</
ogni record letto. ProductName>
<UnitPrice>22.0000</UnitPrice>
Creare un XML Spreadsheet <Quantity>1</Quantity>
Quando Excel versione 2002 (quello di Office XP) o <Discount>0</Discount>
<ExtendedPrice>22.0000</ExtendedPrice>
successiva salva una cartella di lavoro come documento </Table>
XML, rispetta le regole di una grammatica chiamata XML
Spreadsheet. <!-- ... -->
Queste regole, ben descritte nell’articolo “XML
</NewDataSet>
Spreadsheet Reference” [2], sono rispettate anche dalla
terza soluzione (Listato 4) per creare un documento XML
che Excel possa aprire come se fosse una cartella di
lavoro. Diversamente dalle prime due soluzioni che usano La trasformazione coinvolge il documento di origine
un SqlDataReader, questa ultima usa un DataSet (e un (ottenuto salvando il DataSet come documento XML), il
DataAdapter per riempirlo) per sfruttare il suo metodo documento di destinazione (XML Spreadsheet) e il foglio
WriteXml e salvarlo come documento XML con una sola di stile XSL usato per trasformare il primo nel secondo.
istruzione. Il documento di origine (Listato 5) ha un elemento
radice con lo stesso nome del DataSet (per assegnare
ds.WriteXml(“DataSet.xml”) un nome al DataSet sarebbe stato sufficiente crearlo con
Dim xslt As XslTransform = New XslTransform un altro costruttore). La radice per ogni record contiene
xslt.Load(“soluzione3.xslt”) un elemento Table, che a sua volta per ogni campo
xslt.Transform(“DataSet.xml”, “soluzione3.xml”, Nothing) contiene un elemento figlio con lo stesso nome del
campo. Per avere una conferma di queste pur semplici
Tra i molti overload del metodo WriteXml, il codice regole grammaticali si potrebbe usare un altro overload
precedente usa quello che richiede solo il nome del file, del metodo WriteXml che permetta di includere nel
percorso incluso. documento il suo schema.
Il resto del codice trasforma il documento ottenuto
in un esempio (instance) di XML Spreadsheet con una ds.WriteXml(“DataSet.xml”, XmlWriteMode.WriteSchema)
XSLT (eXtensible Stylesheet Language Transformation).
Per farlo, usa un oggetto XslTransform che carica un foglio Il foglio di stile soluzione3.xslt (Listato 6) permette di
di stile con il metodo Load ed esegue la trasformazione trasformare la grammatica di questo documento in quella
con il metodo Transform. di un XML Spreadsheet. Il codice seguente mostra un
I tre argomenti richiesti da questo overload del metodo esempio di XML Spreadsheet che contiene una cartella
Transform sono due stringhe e un oggetto XmlResolver qui di lavoro e un foglio di lavoro chiamato “Il mio primo XML
non usato. Le due stringhe contengono rispettivamente il Spreadsheet”. Nella cella A1 e nella cella B1 scrive due
nome del documento di origine e il nome del documento numeri e nella cella C1 una formula che somma il valore
di destinazione, percorso incluso. delle altre due.

N. 60 - Novembre/Dicembre 2004 VBJ 35


BEGINNER

Listato 6 Il foglio di stile soluzione3.xslt

<?xml version=”1.0” ?> <ss:Data ss:Type=”String”>Total


<xsl:stylesheet version=”1.0” price</ss:Data>
xmlns:xsl=”http://www.w3.org/1999/XSL/Transform” </ss:Cell>
xmlns:ss=”urn:schemas-microsoft-com:office:sprea </ss:Row>
dsheet”> <xsl:apply-templates />
</ss:Table>
<xsl:template match=”/”> </ss:Worksheet>
<ss:Workbook xmlns:ss=”urn:schemas-microsoft-com: </ss:Workbook>
office:spreadsheet”> </xsl:template>
<ss:Styles>
<ss:Style ss:ID=”Bold”> <xsl:template match=”Table”>
<ss:Font ss:Bold=”1” /> <ss:Row>
</ss:Style> <ss:Cell>
<ss:Style ss:ID=”Currency”> <ss:Data ss:Type=”String”>
<ss:NumberFormat ss:Format=”Euro Currency” /> <xsl:value-of select=”ProductName” />
</ss:Style> </ss:Data>
</ss:Styles> </ss:Cell>
<ss:Worksheet ss:Name=”CustOrdersDetail”> <ss:Cell ss:StyleID=”Currency”>
<ss:Table> <ss:Data ss:Type=”Number”>
<ss:Column ss:Width=”192” /> <xsl:value-of select=”UnitPrice” />
<ss:Column ss:Width=”72” /> </ss:Data>
<ss:Column ss:Width=”72” /> </ss:Cell>
<ss:Column ss:Width=”72” /> <ss:Cell>
<ss:Column ss:Width=”72” /> <ss:Data ss:Type=”Number”>
<ss:Row ss:StyleID=”Bold”> <xsl:value-of select=”Quantity” />
<ss:Cell> </ss:Data>
<ss:Data ss:Type=”String”>Product </ss:Cell>
name</ss:Data> <ss:Cell>
</ss:Cell> <ss:Data ss:Type=”Number”>
<ss:Cell> <xsl:value-of select=”Discount” />
<ss:Data ss:Type=”String”>Unit price</ </ss:Data>
ss:Data> </ss:Cell>
</ss:Cell> <ss:Cell ss:StyleID=”Currency”>
<ss:Cell> <ss:Data ss:Type=”Number”>
<ss:Data ss:Type=”String”>Quantity</ <xsl:value-of select=”ExtendedPrice” />
ss:Data> </ss:Data>
</ss:Cell> </ss:Cell>
<ss:Cell> </ss:Row>
<ss:Data ss:Type=”String”>Discount</ </xsl:template>
ss:Data>
</ss:Cell> </xsl:stylesheet>
<ss:Cell>

<?xml version=”1.0” ?> <ss:Cell>


<ss:Workbook xmlns:ss=”urn:schemas-microsoft-com:office:spread <ss:Data ss:Type=”Number”>2</ss:Data>
sheet”> </ss:Cell>
<ss:Styles> <ss:Cell ss:Formula=”=RC[-2]+RC[-1]” ss:
<ss:Style ss:ID=”evidenziato”> StyleID=”evidenziato” />
<ss:Interior ss:Color=”#ffff00” ss:Pattern=”Solid” /> </ss:Row>
</ss:Style> </ss:Table>
</ss:Styles> </ss:Worksheet>
<ss:Worksheet ss:Name=”Il mio primo XML Spreadsheet”> </ss:Workbook>
<ss:Table>
<ss:Row> Tutti gli elementi e gli attributi appartengono al
<ss:Cell> namespace associato al prefisso ss.
<ss:Data ss:Type=”Number”>1</ss:Data> L’elemento radice Workbook, il cui attributo xmlns indica
</ss:Cell> lo spazio dei nomi, rappresenta la cartella di lavoro e

36 VBJ N. 60 - Novembre/Dicembre 2004


BEGINNER

contiene un elemento Worksheet per ogni foglio di lavoro. Quale approccio scegliere
Ogni elemento Worksheet contiene un elemento Table Sebbene la prima soluzione permetta un controllo assolu-
con un elemento Row per ogni riga e un elemento Cell to sul risultato (il modello a oggetti di Excel permette di la-
per ogni cella. vorare con le celle del foglio di lavoro come si farebbe at-
Per ogni cella che contiene dati, il contenuto di un traverso la sua interfaccia grafica), richiede che Excel sia
elemento figlio Data indica il valore e il suo attributo installato sul computer che esegue il programma. Se il pro-
Type indica il tipo. I tipi possibili sono Number, DateTime, gramma fosse eseguito da un server, Excel potrebbe non
Boolean, String ed Error. essere disponibile. Al contrario la seconda soluzione da
Prima ancora degli elementi Worksheet la radice contiene un lato non permette alcun controllo sul risultato (permet-
un elemento Styles, al cui interno sono definiti gli stili da te solo di scrivere dati “nudi e crudi” nelle celle di un foglio
applicare a singole celle o a intervalli di celle. di lavoro), dall’altro non richiede che Excel sia installato sul
Ogni elemento Style ha un attributo ID che lo identifica computer che esegue il programma. La terza soluzione ha
univocamente. Gli elementi figli ne definiscono il formato. i pregi delle prime due senza difetti. Permette controllo as-
Per applicare uno stile a un elemento, si assegna il valore soluto sul risultato (Figura 3) e non richiede che Excel sia
dell’attributo ID dello stile al suo attributo StyleID. installato sul computer che esegue il programma. Permet-
Per trasformare in un XML Spreadsheet il documento te inoltre di modificare il risultato senza dovere ricompilare,
ottenuto salvando il DataSet (Listato 5), il foglio di stile ma modificando solo il foglio di stile.
soluzione3.xslt (Listato 6) contiene due template.
Il primo trasforma la radice del documento di origine Bibliografia
nella radice del documento di destinazione creando l’ele- [1] Pierpaolo Raguso, Corso ADO.NET, Visual Basic &
mento Workbook, gli stili, gli elementi Worksheet, Table, .NET Journal numero 56 e successivi
e la prima riga con i nomi dei campi.
Il secondo trasforma ogni elemento Table nel docu- Riferimenti
mento di origine in un elemento Row nel documento di [2] http://msdn.microsoft.com/library/en-us/dnexcl2k2/
destinazione. html/odc_xmlss.asp

N. 60 - Novembre/Dicembre 2004 VBJ 37


ENTERPRISE

Servizi NT con
VB .NET Servizi NT2

Caso reale di realizzazione e implementazione di servizi Windows con .NET Seconda parte

di Gianluca Cannalire

N
ella puntata precedente abbiamo esplorato la classe stry: affideremo tale compito ad una
ServiceBase, ovvero la classe dalla quale ereditare specifica classe presente nella libre-
per implementare un servizio NT. Per comprendere ria del .NET Framework.
al meglio l’utilizzo delle classi del .NET Framework dedica- Per l’esattezza, le classi da utilizzare
te alla creazione di servizi, abbiamo iniziato la realizzazione per implementare il codice necessa-
di un progetto reale (Event Notificator) che prevede la no- rio all’installazione di un servizio NT
tifica via email delle informazioni che vengono man mano sono due: la ServiceProcessInstaller
inserite nei vari EventLog di Windows. Naturalmente, que- e la ServiceInstaller.
sto notificatore verrà eseguito come servizio NT. La ServiceProcessInstaller, che a
In questa seconda ed ultima parte dell’articolo comple- sua volta eredita da System.Confi-
teremo la realizzazione del progetto analizzando le classi guration.Install.Installer, è la clas-
che ci serviranno per installare (o rimuovere) il servizio nel se che si occupa dell’interazione
sistema e sarà illustrata una tecnica di debug per questo con le utility di setup quali Win-
genere di applicazioni, che si differenzia, per alcuni parti- dows Installer o installutil.exe (che
colari, dal debug di una classica applicazione desktop. vedremo successivamente) men-
Infine, studieremo come interagire con il servizio nello tre la ServiceInstaller si occupa di
stesso modo in cui lavora il Service Control Manager pre- gestire le informazioni necessarie
sente nel Control Panel di Windows. alla ServiceProcessInstaller, speci-
fiche per un determinato servizio.
Installare un servizio È da notare che all’interno di un sin-
L’utilizzo della classe ServiceBase non è di per sé suf- golo progetto possiamo avere più di
ficiente per poter realizzare un servizio completo. Infat- una classe che eredita da ServiceBa-
ti, per poter informare il sistema operativo della presenza se (ovvero, più di un servizio esegui-
di un eseguibile che dovrà essere eseguito come servizio, bile all’interno di un singolo assem-
è necessario creare una serie di chiavi nel registry ed in bly .NET) e che, per ognuna di que-
particolare nel ramo HKEY_LOCAL_MACHINE\SYSTEM\ ste classi, è necessaria la presenza
CurrentControlSet\Services ([1]). Ovviamente, seppur ciò di una corrispondente istanza di Ser-
sia possibile, non è il caso di provvedere manualmente alla viceInstaller, mentre sarà sufficiente
creazione delle particolari chiavi/valori all’interno del regi- una singola istanza di ServiceProces-
sInstaller che provveda all’installazio-
ne di tutti i servizi.
Cerchiamo di capire bene la funzio-
ne di queste due classi partendo dal-
Gianluca Cannalire è diplomato in Elettronica e Teleco- la ServiceInstaller: è questa la classe
municazioni, si occupa della realizzazione di gestionali in
che mantiene effettivamente le infor-
VB6 e .NET. È fondatore e coordinatore di “Visual Basic
mazioni relative al singolo servizio da
Tips & Tricks” (http://www.visual-basic.it), una community
dedicata completamente a Visual Basic in tutte le sue installare all’interno del sistema ope-
versioni. Da aprile 2003 è stato nominato Microsoft MVP rativo. Nella finestra delle proprietà
(Most Valuable Professional) per Visual Basic. (Figura 1) si nota che ci sono poche

38 VBJ N. 60 - Novembre/Dicembre 2004


ENTERPRISE

Tabella 1 I valori della proprietà Account

Valori proprietà ‘Account’ Descrizione

Account con bassi privilegi sulla macchina locale. Utiliz-


LocalService
za credenziali anonime per dialogare con server remoti.
LocalSystem Account con alti privilegi
Account con privilegi estesi sulla macchina locale. Presen-
NetworkService
za credenziali specifiche per dialogare con server remoti.

Account derivato da uno specifico utente definito nel


sistema. Indicando User, sarà necessario valorizzare
User
anche le proprietà UserName e Password, o fornirle
durante l’installazione del servizio

proprietà pubbliche. Tra queste, spiccano DisplayName È interessante notare che la ServiceInstaller gestisce an-
e ServiceName, le quali corrispondono al testo che ver- che una serie di eventi relativi alle varie fasi di installazio-
rà visualizzato all’interno del Service Control Manager di ne (Before/AfterInstall, Before/AfterUninstall, ecc.) del sin-
Windows e al nome della classe derivata da ServiceBase golo servizio, eventi che permettono allo sviluppatore di
per la quale dovrà provvedere all’installazione. eseguire operazioni particolari (ad esempio, la creazione/
Valorizzeremo DisplayName con “VB.NET Event Noti- rimozione di eventuali chiavi/valori nel registry a supporto
ficator Service” e ServiceName con “Service1” (che nel del servizio stesso) fornendo pertanto un completo con-
nostro progetto corrisponde al nome della classe che trollo sulla fase di installazione e rimozione del compo-
eredita da ServiceBase). nente software. La ServiceProcessInstaller si occupa in-
Ci sono altre due proprietà di cui bisogna tener conto: vece di effettuare l’installazione vera e propria del servi-
ServicesDependsOn e StartType, che indicano rispetti- zio (creando e valorizzando le giuste chiavi nel registry)
vamente un elenco di servizi dai quali dipende il corret- ottenenendo le informazioni dalle varie istanze di Servi-
to funzionamento del servizio (Figura 2) e la modalità di ceInstaller associate. Tramite la ServiceProcessInstaller
esecuzione dello stesso all’avvio del sistema (Automatic, provvederemo a fornire al sistema ulteriori informazioni
Manual, Disabled). Imposteremo il valore di StartType su relative al servizio ed in particolare le credenziali con le
Automatic in modo tale che il nostro servizio venga auto- quali vogliamo che il servizio venga eseguito.
maticamente eseguito all’avvio del sistema operativo. A questo scopo utilizzeremo le proprietà Account, User-
name e Password. Nella Tabella 1 sono illustrati i possi-
bili valori della proprietà Account (di tipo ServiceAccount)
notando che solo nel caso il cui il valore venga imposta-
to su ServiceProcess.ServiceAccount.User sarà neces-
sario impostare uno username ed una password ricono-
sciuti validi per il sistema sul quale stiamo installando il
servizio. Nel caso in cui non si provvedesse a valorizza-
re uno username e la relativa password, durante l’instal-
lazione apparirà una dialog box di login che richiederà le
informazioni mancanti (Figura 3).
Inizialmente, per non incorrere in eventuali problemi le-
gati al contesto di sicurezza, lasciamo il valore di Account
su ServiceProcess.ServiceAccount.LocalSystem avendo
l’accortezza di utilizzare un account con privilegi più bas-
si (se possibile) una volta terminata la prima fase di de-
bug dell’applicazione. Un particolare, di non poco con-
to, è che tutta la procedura di installazione del servizio
viene effettuata in modo transazionale, ovvero, in caso
Figura 1 Proprietà del component ServiceInstaller di errore in uno degli step del processo di installazione
(ad esempio per la mancanza di particolari diritti di ese-
cuzione), tutte le modifiche effettuate dall’installer saran-

N. 60 - Novembre/Dicembre 2004 VBJ 39


ENTERPRISE

buto RunInstallAttribute; ci basterà sapere che, con que-


sta particolare configurazione, sarà l’utility di installazione
ad invocare i metodi Install esposti dalla ServiceProces-
sInstaller e dalle dipendenti ServiceInstaller.
A questo punto, il servizio è pronto all’uso.
Eseguiamo il build del progetto e, dopo aver lanciato il
prompt dei comandi di Visual Studio .NET (vsvars32.bat),
per avere tutte le variabili d’ambiete correttamente im-
postate, digitiamo:

installutil.exe <path assembly>\nomeassembly.exe

Il risultato dell’operazione, qui sotto riportato, confer-


merà che tutta l’operazione è stata eseguita all’interno
di un’unica transazione:

Running a transacted installation.


Figura 2 Dipendenze di un servizio Beginning the Install phase of the installation.
See the contents of the log file for the <assembly
path>
The file is located at <assembly path>\<assembly
no sottomesse a rollback e nel sistema non resteranno name>.InstallLog.
tracce orfane (file, chiavi del registry) della nostra appli-
cazione. Le classi ServiceProcessInstaller e ServiceIn- The Install phase completed successfully, and the
staller dispongono anche di una serie di metodi che nel- Commit phase is beginning.
la maggior parte dei casi non dovranno essere invocati See the contents of the log file for the <assembly
direttamente dallo sviluppatore. Il metodo Install, dispo- path>
nibile in entrambe le classi, è quello che effettivamente The file is located at <assembly path>\<assembly
scatena la scrittura nel registry delle varie chiavi e viene name>.InstallLog.
invocato direttamente dalle utility di installazione qua-
li la installutil.exe. The Commit phase completed successfully.
The transacted install has completed.
Aggiungere l’Installer al progetto
Vediamo ora come aggiungere le classi di installazio- A questo punto, apriamo il Service Control Manager dal
ne al progetto. In Visual Studio.NET, apriamo il proget- pannello di controllo di Windows e noteremo che il no-
to e selezioniamo dal Solution Explorer il componente/ stro servizio compare nella lista (Figura 5), ad ulteriore
classe “Service1”. Se nell’IDE non compare il designer conferma della corretta installazione del componente;
del componente, assicurarsi che non vi sia una “window ovviamente non risulta ancora avviato.
code” aperta sul file Service1.vb. Eventualmente sarà ne-
cessario chiudere questa finestra e, cliccando con il ta-
sto destro su “Service1”, selezionare View Designer. Solo
in questo modo, in fondo alla finestra “Properties” del
componente, apparirà il link “Add Installer” (Figura 4).
Cliccando su “Add Installer”, Visual Studio aggiungerà au-
tomaticamente al progetto un nuovo file (ProjectInstaller.vb)
contenente il codice necessario all’installazione del servi-
zio ovvero le instanze di ServiceProcessInstaller e Servi-
ceInstaller opportunamente configurate.
Tutto il codice (Listato 1) è implementato nella clas-
se ProjectInstaller (che eredita a sua volta System.Confi-
guration.Install.Installer) che verrà chiamata in causa da
InstallUtil.exe grazie all’attributo RunInstaller impostato su Figura 3 Richiesta di Login in fase di installazione
True. Per non uscire troppo dall’argomento dell’articolo, non
illustrerò il comportamento della classe Installer e dell’attri-

40 VBJ N. 60 - Novembre/Dicembre 2004


ENTERPRISE

Tabella2 I valori della proprietà Status

Valori proprietà ‘Status’ Descrizione

ContinuePending Il servizio si sta riavviando

Paused Il servizio è in pausa

PausePending Il servizio si sta ponendo in pausa

Running Il servizio è in esecuzione

StartPending Il servizio si sta avviando

Stopped Il servizio non è in esecuzione

StopPending Il servizio si sta fermando

Manca un piccolo, ma non trascurabile, dettaglio. Nel- bene ricordare che per testare ogni volta le nuove modifi-
la finestra del SCM del vostro computer non apparirà al- che apportate al codice bisognerà disinstallare e succes-
cuna descrizione, a differenza di quanto avviene in Figu- sivamente reinstallare il servizio. Per rimuovere il servizio
ra 5. Per la sostanza del nostro applicativo non cambia è sufficiente utilizzare lo switch /u di InstallUtil.exe
molto, ma fornire una descrizione dello scopo del servi-
zio utile all’utente che interagirà con il SCM rende il tutto Avviare il servizio
un po’ più professionale. Non ci resta che avviare il servizio e testarne l’effetti-
Come fare per inserire tale descrizione? Considerato che vo funzionamento. Pertanto, selezioniamolo dal Service
il testo che appare nella colonna “Description” viene rile- Control Manager di Windows, tramite un click sul tasto
vato dall’omonima chiave Description presente in HKEY_ destro, e scegliamo Start. Dopo pochi istanti, nella colon-
LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ na Status, il servizio risulterà Started. Per verificare che
<nome servizio>, dobbiamo aggiungere tale chiave, con tutto funzioni come da manuale, sarà sufficiente forzare
il relativo testo descrittivo, sfruttando gli eventi esposti dalla la scrittura di un entry qualsiasi all’interno dell’EventLog
classe ServiceInstaller cui abbiamo precedentemente ac- Application. Nei sorgenti allegati all’articolo, disponibili
cennato. Per la precisione, utilizzeremo l’evento AfterIn- sul sito FTP di Infomedia, è compreso un piccolo proget-
stall che viene generato in seguito alla scrittura nel regi- to di test che simula la scrittura di record nell’EventLog.
stry delle coppie chiavi/valori fondamentali (Listato 2). È Lo scopo del servizio era quello di notificare all’ammini-
stratore di un server, tramite email, le informazioni che i
vari applicativi scrivono all’interno del registry. Per invia-
re i vari messaggi di posta elettronica abbiamo fatto uso
della classe MailMessage (namespace System.Web.Mail)
che, se non diversamente specificato tramite la proprietà
SmtpServer di SmtpMail,delega al servizio SMTP di IIS
il delivery del messaggio. Questo non vuol dire che per
effettuare il test dell’applicazione sia necessario avere il
servizio in esecuzione: infatti, sarà sufficiente controlla-
re il contenuto della directory c:\InetPub\Mailroot\Queue
dove saranno creati i file di testo relativi ai messaggi da
spedire (in formato RFC822).

Debug di un servizio
Effettuare il debug di un servizio è un’operazione in parte
differente da quella di una normale applicazione WinFor-
ms. Se si tenta di avviare nell’IDE il nostro servizio, otter-
remo infatti come risposta questo messaggio:
Figura 4 Aggiungere l'installer ad un servizio
“Cannot start service from the command line
or a debugger. A Windows Service must first be

N. 60 - Novembre/Dicembre 2004 VBJ 41


ENTERPRISE

Listato 1 La classe ProjectInstaller

Imports System.ComponentModel ‘Do not modify it using the code editor.


Imports System.Configuration.Install Friend WithEvents ServiceProcessInstaller1 As
System.ServiceProcess.ServiceProcessInstaller
<RunInstaller(True)> Public Class ProjectInstaller Friend WithEvents ServiceInstaller1 As System.Service
Inherits System.Configuration.Install.Installer Process.ServiceInstaller
<System.Diagnostics.DebuggerStepThrough()> Private
#Region “ Component Designer generated code “ Sub InitializeComponent()
Me.ServiceProcessInstaller1 = New System.Service
Public Sub New() Process.ServiceProcessInstaller
MyBase.New() Me.ServiceInstaller1 = New System.ServiceProcess
.ServiceInstaller
‘This call is required by the Component Designer. ‘
InitializeComponent() ‘ServiceProcessInstaller1

‘Add any initialization after the InitializeCom- Me.ServiceProcessInstaller1.Account = System.
ponent() call ServiceProcess.ServiceAccount.LocalSystem
Me.ServiceProcessInstaller1.Password = Nothing
End Sub Me.ServiceProcessInstaller1.Username = Nothing

‘Installer overrides dispose to clean up the compo- ‘ServiceInstaller1
nent list. ‘
Protected Overloads Overrides Sub Dispose(ByVal Me.ServiceInstaller1.DisplayName = “VB.NET Event
disposing As Boolean) Notificator Service”
If disposing Then Me.ServiceInstaller1.ServiceName = “Service1”
If Not (components Is Nothing) Then
components.Dispose() ‘
End If ‘ProjectInstaller
End If ‘
MyBase.Dispose(disposing) Me.Installers.AddRange(New System.Configuration.
End Sub Install.Installer() {Me.ServiceProcessInstaller1,
Me.ServiceInstaller1})
‘Required by the Component Designer
Private components As System.ComponentModel.IContainer End Sub

‘NOTE: The following procedure is required by the #End Region


Component Designer
‘It can be modified using the Component Designer. End Class

installed (using installutil.exe) and then started with progetto e procedere al debug classico. Ci sono ancora
the ServerExplorer, Windows Services Administrative un paio di particolari da tenere in considerazione. Il pri-
tool or the NET START command.” mo è che, per effettuare il debug, il processo deve es-
sere in esecuzione, ovvero che il servizio sia stato av-
Come è possibile quindi procedere al debug step-by- viato. Il secondo è derivante dal primo: come effettuare
step del codice? Utilizzando Visual Studio .NET possia- il debug del metodo OnStart se non possiamo aggan-
mo agganciare il debugger a qualsiasi processo in ese- ciare il debugger prima dell’avvio del servizio? Dobbia-
cuzione sul sistema. Dal menù “Debug -> Process...” si mo trovare un sistema che possa caricare in memoria il
accede alla maschera (Figura 6) dalla quale è possibile nostro processo ancor prima che il metodo OnStart del
selezionare il processo da sottoporre a debug (il proces- servizio venga invocato dal Service Control Manager. E
so deve essere in esecuzione ovviamente). il sistema è tutto sommato banale: basta aggiungere al
Se il servizio è eseguito sotto LocalSystem bisogna se- progetto un altra classe ereditata da ServiceBase (senza
lezionare la checkbox Show System Process per farlo implementare alcun tipo di codice al suo interno). Come
comparire nell’elenco. Una volta selezionato il proces- già anticipato all’inizio dell’articolo, all’interno di un sin-
so (EventNotificator.exe) clicchiamo su Attach e poi su golo assembly possono coesistere più classi che ere-
Common Language Runtime. Da questo momento pos- ditano da ServiceBase e quindi in un singolo processo
siamo impostare gli opportuni breakpoint nel codice del possiamo avere più servizi in esecuzione (i quali non ne-

42 VBJ N. 60 - Novembre/Dicembre 2004


ENTERPRISE

Listato 2 Modificare il registry durante l'installa-


zione del servizio

Private Sub ServiceInstaller1_AfterInstall(ByVal


sender As System.Object, ByVal e As System.Configuration.
Install.InstallEventArgs) Handles ServiceInstaller1.
AfterInstall

Dim regDescription As Microsoft.Win32.Registry


Key
Dim strDescription As String = “”

regDescription = _
Figura 5 Il Service Control Manager di Windows ed il Microsoft.Win32.Registry.LocalMachine.
nostro servizio OpenSubKey( _
“System\CurrentControlSet\Services\” & _
Me.ServiceInstaller1.ServiceName & “\”,
True)
cessariamente devono interagire tra loro od essere tut-
ti in esecuzione). Sfruttando il fatto che il processo vie- If (Not regDescription Is Nothing) Then
regDescription.SetValue(“Description”, _
ne caricato in memoria all’avviamento del primo servizio “Questa è la descrizione del servi-
invocato dal SCM e scaricato quando l’ultimo servizio zio”)
viene fermato, ecco che l’uso di un servizio fittizio per- regDescription.Close()
mette di caricare in memoria l’immagine del nostro pro- End If
cesso ed agganciare il debugger prima di avviare il ser- End Sub
vizio vero e proprio da debuggare. Nonostante tutto c’è
ancora qualcosa di cui dobbiamo tener conto durante il
debug: il SCM quando invoca lo startup di un servizio si lore che dovremo utilizzare nel costruttore della clas-
aspetta che lo stesso risponda in un tempo massimo di se ServiceController. ServiceName rispecchia la chia-
30 secondi, altrimenti genererà l’errore “Could not start ve specifica del servizio creata all’interno di HKEY_LO-
the VB.NET Event Notificator service on Local Compu- CAL_MACHINE\SYSTEM\CurrentControlSet\Services.
ter. Error 1053: The service did not respond to the start DisplayName è invece solo un valore “user friendly” per
or control request in a timely fashion.” identificare facilmente un servizio all’interno del SCM.
Tra i membri della ServiceController ci sono un paio di
Controllare un servizio metodi che vale la pena segnalare: GetServices (shared)
Dopo aver visto come creare, installare ed eseguire il e ExecuteCommand. Il primo restituisce una lista di og-
debug di un servizio, è il momento di capire come possia- getti ServiceController rappresentanti ogni singolo servizio
mo controllare il suo stato al di fuori del Service Control installato sulla macchina locale; per ottenere l’elenco dei
Manager standard di Windows. Come potete immagina-
re ancora una volta l’immensa libreria di .NET ci viene in
aiuto. All’interno del namespace System.ServiceProcess
troviamo il tipo ServiceController, che in sostanza per-
mette di connettersi tramite apposite API ad un servizio
installato nel sistema, fornendo la capacità di controllare
e/o modificare il suo stato. La ServiceController è una
classe abbastanza semplice ed intuitiva da utilizzare: una
volta creata un’istanza, passando come parametro al co-
struttore il nome del servizio per il quale vogliamo otte-
nere il controllo, sarà sufficiente far riferimento ai metodi
Start, Stop, Pause e Continue per modificare lo stato di
attività del servizio e alle proprietà DisplayName, Servi-
ceName, MachineName, ServiceType e Status per otte-
nere informazioni sullo stesso. È bene ribadire che Ser-
viceName e DiplayName sono due cose ben differenti: Figura 6 Aggancio del debugger al processo
ServiceName, che corrisponde al nome della classe che
eredita da System.ServiceProcess.ServiceBase, è il va-

N. 60 - Novembre/Dicembre 2004 VBJ 43


ENTERPRISE

zio) tramite l’invio di un valore numerico (i valori ammessi


Listato 3 Enumerazione dei servizi
vanno da 128 a 255). Pertanto, se vogliamo sfruttare que-
sto metodo per modificare il comportamento del servizio,
all’interno dello stesso sarà necessario prevedere il codi-
Private Sub ListAllServices() ce che reagisca alla ricezione di questi valori (intercettati
Dim mySCMs() As ServiceController dalla ServiceBase tramite l’evento OnCustomCommand.
mySCMs = ServiceController.GetServices()
Nei sorgenti che accompagnano l’articolo è presente un
Dim mySCMTemp As ServiceController esempio di Service Controller personalizzato che mostra
anche l’uso del metodo ExceuteCommand.
ListView1.BeginUpdate()
ListView1.Items.Clear()
Conclusioni
For Each mySCMTemp In mySCMs Come abbiamo potuto vedere, la realizzazione di un servi-
zio, grazie all’infrastruttura offerta dal .NET Framwork, è di-
Dim myItem As System.Windows.Forms.ListView ventata un’operazione banale anche con Visual Basic(.NET).
Item = ListView1.Items.Add(mySCMTemp.ServiceName)
myItem.SubItems.Add(mySCMTemp.DisplayName)
Basterà aggiungere al nostro servizio un sistema di moni-
toraggio del file system (vedi System.IO.FileSystemWatcher)
e magari implementare anche la notifica via SMS ([2],[3])
per ottenere un tool completo per la notifica eventi.
servizi di una macchina remota è sufficiente fornire, come
argomento del metodo GetServices, il nome di un com- Riferimenti
puter remoto. Nel Listato 3 viene illustrato un possibile [1] “CurrentControlSet\Services Subkeys Entries”, http:/
uso del metodo GetServices. Tramite ExecuteCommand /support.microsoft.com/?id=103000
possiamo invece inviare dei “comandi personalizzati” al [2] “Il protocollo AT+ dei telefoni cellulari”, DEV 115, 116,
nostro servizio. Effettivamente non si tratta di comandi 117, 118, 119, 120
veri e propri: la ExecuteCommand ci permette di comu- [3] Vito Vessia , “Programmare il cellulare”, Hoepli,
nicare in modalità ‘one-way’ (ovvero solo verso il servi- 2002

Come fare? Semplice!


Basta inviare la descrizione del proprio articolo a

LoginWantsYou@infomedia.it
specificando

a chi si rivolge, che cosa spiega,


i titoli di paragrafo e i relativi abstract
Se ti piace scrivere e l’informatica è la tua passione,
non perdere questa occasione! Login, la prima rivista italiana dedi-
cata ai professionisti di Internet, sta cercando nuovi collaboratori
e...uno di questi potresti proprio essere tu!

WEB PUBLISHING Per i creativi della rete. HTML, XML, VRML,


ASP, scripting, multimedia
E-COMMERCE Soluzioni per il commercio elettronico Stato
dell’arte, pagamenti sicuri, negozi virtuali, crittografia, tool
di sviluppo, ecc.
NETWORKING Installazione e configurazione di computer in
rete. Protocolli, routing, hub, bridge, router, switch, network
management, ecc.

Scrivi anche tu un articolo!


44 VBJ www.infomedia.it/riviste/login
N. 60 - Novembre/Dicembre 2004
WEB

Grafici dinamici
in ASP .NET
Vale la pena di sprecare tempo per creare grafici da zero? Molto meglio utilizzare una
libreria altamente personalizzata. Vediamo tutti i pregi di .netCHARTING

di Dino Esposito

S
e avete mai avuto a che fare con la programmazio- Usare le classi GDI+ per produrre
ne grafica, in particolare quella dei grafici, nell’era un grafico come quello in Figura 1 è
pre-.NET – vista oggi sembra una sorta di Jurassic sicuramente possibile, ma certamen-
Windows! – potrete solo ringraziare il destino per avervi te non banale. Il codice per piazzare
fatto incontrare questo ramo della programmazione solo i valori al centro delle sezioni richie-
nell’era di .NET. de un po’ di tempo. Lo stile 3D con
Il .NET Framework contiene una libreria avanzata di fun- effetti luce pure. E i piccoli partico-
zioni conosciuta come GDI+, in onore del mitico Windows lari come rendere le etichette visibi-
Graphics Device Interface (GDI), croce e delizia (bé, più cro- li sia sui colori chiari che scuri non
ce) per generazioni di programmatori Windows. è da meno.
I servizi GDI+ rientrano nelle seguenti categorie: grafica Insomma, sono tutte cose che si
vettoriale 2D ed elaborazione delle immagini. La grafica possono ottenere da soli, ma ne vale
vettoriale 2D permette di disegnare figure semplici come la pena in termini di tempo/costo? E
linee, curve e poligoni. Sotto la dicitura “elaborazione im- siamo sicuri di perdere del tempo e
magini” invece ricadono tutte quelle funzioni per visualiz- contemporaneamente soddisfare le
zare, manipolare, salvare e convertire immagini bitmap e aspettative del cliente? Vi dico che,
vettoriali. Infine, può essere definita anche una terza ca- anche se riuscissimo a soddisfare le
tegoria di funzioni, quelle che riguardano il testo, ovvero sue aspettative, avremmo perso l’op-
la sua visualizzazione in tutte le salse, giocando con font, portunità di superarle, allo stesso co-
dimensioni e stili. sto o anche a meno!
Come potete vedere, GDI+ fornisce solo le basi per la Un grafico a torta è ottimo per rap-
programmazione grafica; utilizzando i suoi tool a basso li- presentare i dati. Ma non tutti i tipi di
vello si possono confezionare forme più avanzate, come dati. Il bello è quando abbiamo uno
appunto dei grafici. Fintanto che avete bisogno di visualiz- strumento che permette di cambiare
zare una serie di barre verticali, ci si può tipo di grafico con piccole modifiche.
anche arrangiare da soli. Ma come fare È difficile implementare a mano il co-
quando il cliente chiede di più? dice per il grafico di Figura 2.
Effetti come la trasparenza, lo stile
3D, lo sfondo richiedono codice; e il
codice richiede tempo e denaro. E,
molto importante, quello non è il tipo
di codice per il quale siete pagati.
Dino Esposito è consulente e formatore per Wintellect, Riassumendo, l’aiuto professionale
per cui tiene il corso ADO.NET. Dino collabora con MSDN
che vi può dare una libreria grafica
Magazine e MSDN Voices. È autore di Building Web Solu-
tions with ASP.NET e ADO.NET (Microsoft Press), è anche ben fatta può portare ad un servizio
co-fondatore di www.vb2themax.com. È raggiungibile via di prima classe per il cliente. Dovre-
e-mail all’indirizzo esposito@infomedia.it ste sempre considerarlo.

N. 60 - Novembre/Dicembre 2004 VBJ 45


WEB

Scegliere la giusta libreria


Scegliere la giusta libreria può non essere semplice, e in
qualche modo è anche una questione di preferenze per-
sonali. Comunque, qualsiasi libreria scegliate deve almeno
soddisfare i requisiti basilari, in modo da essere d’aiuto
allo sviluppatore per offrire un buon servizio al cliente.

La mia libreria ideale dovrebbe:

• Essere facile da usare


• Avere un’interfaccia di programmazione .NET “stan-
dard”, tipo quella della FCL
• Fornire una vasta gamma di grafici
• Essere efficace in termini di risultati grafici, sforzi di
programmazione richiesti e costo Figura 2 Effetti 3D, background e trasparenza
• Fornire una ricca interfaccia utente che va oltre la
solita lunga lista di grafici da scegliere e aggiunge-
re supporto per feature come trasparenza, gradienti,
sfondi, legende, ecc. bly del controllo nella pagina e se ne piazza un’istanza
• Essere internamente ottimizzata in velocità e offrire nel sorgente ASPX:
controllo su certe caratteristiche come il caching
<%@ Register TagPrefix=”dotnet” Namespace=”dotnetCHARTING”
Mi sono dimenticato niente? Ma certo, ovviamente non Assembly=”dotnetCHARTING”%>
deve essere complessa e poco maneggevole. Adoro il ...
software potente che permette comunque di iniziare con <dotnet:Chart runat=server id=chart />
un semplice ma significativo esempio.
Credo che la libreria .netCHARTING soddisfi tutti que- Poi bisogna collegare il controllo con qualche dato per
sti requisiti ([1]). generare il grafico. Il modello di .netCHARTING consiste
È eccezionale, per come la vedo io. Tra l’altro è dispo- in “elementi” che insieme formano una “serie”. .netCHAR-
nibile in versione completa e gratuita per scopi di svilup- TING legge i dati da una serie. Una o più serie possono
pi e testing, quindi potrete tranquillamente sperimentare essere raggruppate in una collection e passate al con-
le tecniche illustrate nel seguito dell’articolo. trollo. La classe Element rappresenta un elemento del
grafico ed espone proprietà per contenere differenti tipi
Lavorare con .netCHARTING di dati come i valori X e Y, percentuale di completamen-
Una semplice applicazione ASP.NET con .netCHARTING to per grafici Gantt, e così via. Inoltre fornisce il control-
è, per l’appunto, semplice. Si inizia registrando l’assem- lo su altri attributi come il colore.
La classe Series rappresenta un gruppo di elementi ed
espone le proprietà di default per tutti i suoi elementi in-
terni, come pure le proprietà specifiche per la serie, come
le voci della legenda. Espone dei metodi per manipolare
i dati, ad esempio per ordinare gli elementi ed effettuare
alcuni calcoli per derivare nuovi elementi della serie.
Per associare una serie al controllo si usa la proprietà
SeriesCollection:

Element e = new Element();


e.Name = “My Element”;
e.YValue = 10;
Series s = new Series();
s.Name = “My Series”;
s.Elements.Add(e);
Figura 1 Grafico 3D a torta SeriesCollection sc = new SeriesCollection();
sc.Add(s);
chart.SeriesCollection.Add(sc);

46 VBJ N. 60 - Novembre/Dicembre 2004


WEB

Il codice prima istanzia un nuovo elemento e poi gli as- te la proprietà CacheDuration. Quando impostata, l’im-
segna il valore per l’asse Y. Quindi crea una nuova serie magine è generata solo al primo hit e conservata per un
e vi inserisce l’elemento appena creato. Elements elen- determinato numero di secondi. Tutte le richieste che ar-
ca gli elementi presenti nella collection. Infine, la serie è rivano in questo intervallo di tempo accederanno all’im-
aggiunta in un oggetto SeriesCollection che a sua volta magine in cache senza ulteriore elaborazione da parte
è aggiunto all’omonima proprietà del controllo. del controllo. La proprietà booleana UseFile permette di
Questo pezzo di codice si trova di solito nell’evento indicare se l’immagine generata debba essere salvata su
Page_Load. file oppure spedita direttamente sotto forma di stream al
Anche se è estremamente flessibile, non è proprio rea- browser. Inoltre i file obsoleti vengono automaticamente
listico creare gli elementi individualmente. eliminati, senza accumularsi nel tempo.
Nella maggior parte dei casi infatti i dati arriveranno Un’altra classe che vale la pena di menzionare è la Da-
dai business object che a loro volta li avranno ricava- taEngine. Prima di tutto l’oggetto DataEngine può esse-
ti dal database, documenti Excel, stream XML. I busi- re configurato per raccogliere i dati da interrogazioni su
ness object di solito espongono i dati usando contenitori database oppure da DataSet disconessi.
ADO.NET come i DataSet o interfacce come il DataRea- I dati sono convertiti in una SeriesCollection che è il
der. .netCHARTING accetta dati provenienti dal DataSet, solo tipo che il controllo riconosce. In aggiunta, DataEn-
ma per consistenza il DataSet deve essere impacchetta- gine offre molte comode opzioni di manipolazione, spe-
to in un oggetto Series. cificatamente progettate per le esigenze comuni come
Ecco un esempio: l’aggregazione dei dati.

void Page_Load(object sender, EventArgs e) DataEngine de = new DataEngine();


{ de.StartDate = “1/1/02 8:00:00 AM”;
// Set global properties de.EndDate = “1/1/02 8:00:00 AM”;
chart.Title = “Item sales report”; de.DateGrouping = TimeInterval.Days;
chart.TempDirectory = “temp”; de.SqlStatement = “SELECT names, values FROM myTable “ + “WHERE
chart.Type = ChartType.Pie; start > #StartDate# AND e” + “nd < #EndDate#”;
SeriesCollection sc = de.GetSeries();
// Adding series programatically chart.SeriesCollection.Add(sc);
chart.Series.Name = “Item sales”;
chart.Series.Data = GetDataSet(); Il DataEngine supporta anche il raggruppamento del-
chart.SeriesCollection.Add(); le date ad un desiderato livello di granularità – da anni
} a minuti.

La proprietà Data del-


la classe Series può es-
sere collegata a qualsia-
si oggetto enumerabile
ADO.NET, inclusi i Da-
taReader.
La proprietà TempDi-
rectory controlla la di-
rectory dove le immagi-
ni generate dal controllo
sono temporaneamente
salvate. Dovrete avere i
permessi di scrittura su
tale directory nella mac-
china server. Ogni imma-
gine è salvata in un file
del server per evitare di
penalizzare la memoria.
Per default l’immagine è Figura 3 Le barre del grafico permettono di fare il “drill-down” sui dati
rigenerata ad ogni hit, a
meno che non impostia-

N. 60 - Novembre/Dicembre 2004 VBJ 47


WEB

Dalla versione 2.5 il controllo supporta varie operazio- img.ImageUrl = Chart.FileManager.SaveImage(Chart.GetChart


ni matematiche come la media, il minimo e il massimo. Bitmap());
Precedentemente era supportata solo la somma.
Nella versione 2.5 la legenda può essere salvata in un
Caratteristiche avanzate file separato, per avere un layout flessibile all’interno del-
.netCHARTING possiede varie caratteristiche avanza- la pagina web.
te, In questa sede vorrei brevemente discuterne tre: drill-
down, file manager e le infinite opzioni per allineare il te- leg.ImageUrl = Chart.FileManager.SaveImage(Chart.GetLegend
sto e inserire delle annotazioni (Figura 3). Bitmap());
Il drill-down permette di supportare una catena di gra-
fici logicamente correlati. Una annotazione è un riquadro con un testo, una posi-
L’idea è quella di visualizzare il grafico iniziale e poi clic- zione, una sorgente dati e con funzionalità hotspot. Po-
care su un elemento per ottenere una vista dettagliata dei tete associare un’annotazione ad un elemento del gra-
dati. Il livello di annidamento deve essere impostato dal fico e ottenere un effetto come quello in Figura 4. Ave-
programmatore e sfrutta le capacità di raggruppamento te il completo controllo sull’orientamento, stile, colore e
delle date sopra menzionate. layout del testo.
I riquadri dei tooltip e delle legende possono essere defi-
Ecco un esempio: niti basandosi su un template, come quello in esempio:

Chart.DateGrouping = TimeInterval.Years; chart.LegendBox.Template =”%icon %name”;


Chart.DrillDownChain=”Years,Quarters,Months,Days,Hours,Minutes”;
Chart.DefaultSeries.DefaultElement.ToolTip=”%yvalue”; Si possono definire template utilizzando dei token spe-
ciali predefiniti. Ogni token è preceduto dal simbolo %.
La proprietà DrillDownChain definisce i vari livelli di Nell’esempio viene visualizzata un’icona e il nome del-
dettaglio che si intendono vedere. la voce. L’icona rappresenta un piccolo rettangolo con il
Non è necessario altro codice. Il tooltip visto in Figu- colore di riempimento del corrispondente elemento del
ra 3 visualizza la vista attuale per ogni elemento ogni grafico. Il nome invece è il nome dell’elemento.
volta che ci si sposta col mouse sopra di esso.
Tutti i grafici generati dal controllo possono essere Conclusioni
salvati in un file nel server. In .netCHARTING, la lista dei tipi di grafico supportati
Si può fare usando la classe FileManager. Il suo me- è incredibilmente ricca, ma non infinita: questo significa
todo SaveImage e l’enum ImageFormat permettono che il controllo è ben bilanciato. Non è troppo grande in
di scegliere il nome e il formato dell’immagine. Il co- memoria e non è troppo piccolo per le caratteristiche che
dice seguente salva il grafico e assegna il suo per- ha. Ogni elemento di una serie può essere personalizzato
corso alla proprietà ImageUrl di un controllo Image in base a condizioni note a runtime, ad esempio si può
di ASP.NET. cambiare il colore delle fette della torta in base alla per-
centuale. Un altro aspetto da enfatizzare è che per usa-
re efficacemente il controllo non bisogna essere esperti
di .NET. Alcune caratteristiche come l’aggregazione sul-
le date è resa semplice anche per i non esperti. Tenete
presente che con quattro linee di codice si può costrui-
re un bel grafico associato ai dati:

chart.TempDirectory=”temp”;
chart.DefaultSeries.ConnectionString = “data.mdb”;
chart.Series.SqlStatement= “SELECT Customer, Sales FROM Table”;
chart.SeriesCollection.Add();

Devo dire che questo articolo ha solo mostrato la pun-


ta dell’iceberg .netCHARTING ma credo sia abbastanza
per farne capire le potenzialità. A voi la prossima mos-
Figura 4 Annotazioni nel grafico sa. Enjoy!
Riferimenti
[1] http://www.dotnetcharting.com/

48 VBJ N. 60 - Novembre/Dicembre 2004


ARCHITECT'S CORNER

Applicazioni scalabili
in pratica
“Two is meglio che one” diceva una nota pubblicità. In questa puntata daremo dei consigli
pratici per progettare e implementare un’applicazione scalabile.

di Ingo Rammer

Nella puntata precedente abbiamo parlato della differen- 1. Analizzare i dati


za tra scalabilità e performance. Uno dei modi più semplici per au-
Quando parliamo di performance ci riferiamo solitamen- mentare le performance di un’appli-
te alla velocità con cui una singola operazione può essere cazione è utilizzare una cache.
svolta. Invece la scalabilità si riferisce al grado di paralleliz- Purtroppo le cache sono però il ne-
zazione delle operazioni o di alcune parti dell’applicazione. mico della scalabilità.
Quando si ottimizza un sistema si punta ad entrambe, per È semplice mettere in cache più
migliorare il throughput (capacità di elaborazione). dati possibile fintanto che l’applica-
Immaginiamo che un vostro collega abbia ottimizzato zione rimane sullo stesso server, e
un’applicazione talmente bene da gestire 1000 richieste a volte la velocità migliora anche di
concorrenti su un singolo server. un ordine di grandezza.
Dall’altra parte voi avete una soluzione alternativa, che in Però quando entra in scena il se-
realtà è un po’ più lenta e può gestire solo 500 richieste condo server la situazione cambia
concorrenti. Però la vostra soluzione può essere esegui- radicalmente.
ta su 10 server in parallelo. Grazie alla possibilità di sca- Facciamo un esempio. Supponia-
lare la vostra applicazione può raggiungere un throughput mo che degli ipotetici dati dei clienti
di circa 5000 richieste concorrenti mentre la prima, che a siano memorizzati nella cache ser-
prima vista era più veloce, solo 1000. ver dell’applicazione per 30 minuti
Il problema delle architetture di questo tipo è che di soli- dopo ogni accesso.
to gli sviluppatori sanno benissimo come ottimizzare la ve- Ogni volta che un utente modifica
locità delle applicazioni, ma raramente sanno concentrar- i dati, prima viene eseguita la tran-
si altrettanto bene sulla realizzazione di una applicazione sazione sul database e poi viene
veramente scalabile. aggiornata la cache, in modo che
Ma cosa si può fare per creare un’applicazione scalabile, le letture successive restituiscano i
che può essere eseguita su più server in parallelo per di- dati corretti.
stribuire il carico di lavoro? Nel seguito vedremo tre passi Le strategie di caching come que-
che ci aiuteranno a rispondere alla fatidica domanda. ste possono in alcuni casi ridurre
drasticamente i tempi di risposta e
quindi incrementare il throughput.
Ma se ci fosse bisogno di eseguire
l’applicazione su una seconda mac-
Ingo Rammer è il fondatore di thinktecture, una com- china in un cluster, la cache di una
pagnia che aiuta gli sviluppatori e gli architetti software macchina dopo ogni aggiornamen-
a progettare e implementare applicazioni e Web service to non sarebbe corretta (perché solo
.NET. Partecipa come speaker alle conferenze internazio-
una cache di una macchina è stata
nali dedicate a tali argomenti ed è autore del best-seller
Advanced .NET Remoting (APress). È Microsoft Regional aggiornata).
Director per l’Austria e può essere contattato tramite il sito Senza un’adeguata strategia di ca-
http://www.thinktecture.com/staff/ingo. che invalidation, applicazioni come

50 VBJ N. 60 - Novembre/Dicembre 2004


ARCHITECT'S CORNER

queste semplicemente non scalano su più server. Uno La categoria più complessa in termini di stragia di ca-
dei primi passi per creare un’applicazione scalabile quin- ching è la seconda: infatti ci sono due tipi di dati che
di è quello di analizzare tutti i tipi di dati che sono usa- cambiano raramente:
ti dall’applicazione.
• Le informazioni che sono di solito stabili per un lungo
Può essere utile suddividere le tabelle del database periodo di tempo e che sono modificate ad una data
in tre gruppi: conosciuta a priori (ad esempio “listino prezzi valido
dalla mezzanotte del 1 ottobre 2004“).
• Gruppo 1: dati statici Se si conosce la data, queste informazioni possono
• Gruppo 2: dati semi-statici, che cambiano raramen- essere messe in cache facilmente. Bisogna solo assi-
te o che sono aggiornati solo in determinati momen- curarsi di rimuovere la versione obsoleta al momento
ti (ad esempio ogni giorno a mezzanotte) giusto.
• Gruppo 3: Dati operativi, dinamici • Il secondo tipo di dati è quello più difficile da tratta-
re. Sono i dati che di solito non cambiano, ma quan-
Nel caso di un negozio online, i dati statici sono di so- do cambiano, le modifiche devono diventare effetti-
lito i CAP, le città, la lista dei metodi di pagamenti accet- ve immediatamente.
tati (carta di credito, assegno, bonifico…). Molto spes- Per esempio i permessi per gli utenti. Se questi dati
so rientrano in questa categoria i dati che non possono sono in cache, bisogna assicurarsi di avere una effi-
essere cambiati dall’applicazione stessa, ma solo attra- cace strategia di cache invalidation.
verso strumenti di amministrazione. Si può ad esempio pensare di esporre un web service
Nel secondo gruppo si trovano i dati che di solito non su ogni nodo del cluster per comunicare alla macchi-
cambiano più di una volta al giorno. na esplicitamente di rimuovere alcuni dati dalla me-
Ad esempio la lista dei prodotti, i prezzi, ecc. Questo moria.
gruppo può contenere anche i dati che sono modifica-
ti in precisi intervalli di tempo, come una volta al gior- Le prossime versioni di .NET e SQL Server avranno
no oppure ogni ora. delle nuove caratteristiche che permetteranno di notifi-
L’ultimo gruppo contiene i dati su tutte le vere transa- care alle applicazioni server le modifiche critiche ai dati.
zioni, ovvero il cuore del business. Ad esempio potrete fare il subscribe a query tipo “select
Questi sono i dati che cambiano più frequentemen- userid, locked_out from users” per fare in modo che SQL
te, come le informazioni sui clienti, i livelli di magazzi- Server 2005 automaticamente vi informi quando un re-
no, gli ordini. cord è cambiato.
Vedrete che in pratica molte tabelle apparterranno ai
primi due gruppi, e solo poche conterranno i dati mo- 2. Porsi le giuste domande
dificati dalle transazioni. L’analisi delle strategie di caching che ho appena illu-
Se poi una stessa tabella contiene dati di due grup- strato è in realtà solo il primo passo di un approccio ge-
pi differenti potete modificare lo schema del database nerico per progettare un sistema scalabile.
oppure semplicemente trattare i due tipi di dati diffe- Per assicurare la scalabilità statica e la parallelizzazio-
rentemente. ne dell’applicazione si può essenzialmente lavorare con
Questo ad esempio succede quando in origine si sono un semplice modello mentale. Ogni volta che si sta per
memorizzati nella stessa tabella i livelli di magazzino (che chiamare un metodo su un oggetto server-side, biso-
cambiano sempre) insieme alle informazioni sui prodot- gnerebbe chiedersi “Cosa potrebbe succedere se que-
ti. Dovrebbero essere separati, almeno nel modello ad sto metodo fosse eseguito su una macchina diversa da
oggetti se non nel database, in modo da avere i dati quella su cui è stato eseguito prima?”.
transazionali (livelli di magazzino) separati dalle infor- E una seconda domanda dovrebbe essere “Cosa suc-
mazioni sui prodotti. cederebbe se il server fosse stato riavviato proprio pri-
Seguendo questa classificazione, potrete facilmente ma di questa chiamata?”.
adottare una adeguata strategia di caching. Per illustrare il problema in dettaglio, diamo un’occhia-
La decisione se mettere in cache o no i dati statici è ta al codice seguente:
abbastanza semplice: di solito si memorizzano fin tan-
to che c’è RAM disponibile. void UpdateCustomer(Customer cust)
Sempre semplice il discorso per i dati operativi del ter- {
zo gruppo: non bisognerebbe mai metterli in memoria, ISomeRemoteObject obj = (ISomeRemoteObject) Activator.
ma leggerli e scriverli direttamente dallo storage condi- GetObject(...);
viso, ad esempio il database. obj.Initialize(_username, _password);

N. 60 - Novembre/Dicembre 2004 VBJ 51


ARCHITECT'S CORNER

obj.StoreCustomer(cust); normali lock su database e resource contention. Posso-


} no piantare un sistema in men che non si dica.
Capita spesso che questi colli di bottiglia saltino fuori
e confrontiamolo con questo: quando più di un’operazione accede alla stessa risorse
contemporaneamente.
void UpdateCustomer(Customer cust) Sebbene questi problemi siano molto comuni, ottimiz-
{ zare le strategie di accesso è un compito difficile per-
ISomeRemoteObject obj = (ISomeRemoteObject) Activator. ché non ci sono ricette generiche se non quella di man-
GetObject(...); tenere le transazioni e i lock su database per tempi più
obj.StoreCustomer(_username, _password, cust); brevi possibile.
} A questo proposito raccomando di leggere un arti-
colo di MSDN [3] che fornisce un’introduzione alle dif-
Nel primo caso, dovrebbe suonare una sirena d’al- ferenti modalità di locking e transazioni disponibili in
larme. Per assicurare un comportamento corretto in- SQL Server.
fatti è essenziale che entrambe le chiamate a Initiali- Ricordate che non bisognerebbe basarsi sul taskma-
ze e StoreCustomer siano invocare sulla stesso ogget- nager o comunque sul livello di carico della CPU per
to server-side. identificare i colli di bottiglia.
Altrimenti il load balancing automatico sessionless sa- Infatti il workload della CPU può anche restare al mi-
rebbe impossibile. E se il server fosse riavviato tra le nimo, ad esempio nel caso di lock a livello di tabella in-
due chiamate, la seconda fallirebbe. vece che di riga.
Avrete notato che in generale le applicazioni che sono La CPU rimane in idle, attendendo il rilascio di un lock
state sviluppate con un approccio stateless (senza sta- e senza la possibilità di effettuare altre operazioni. E ag-
to), come nel secondo frammento di codice, permetto- giungere CPU al server o macchine al cluster non risol-
no un alto grado di parallellizzazione. verebbe la situazione. Uno dei tool più utili per tenere
In quel caso infatti ogni richiesta può potenzialmente traccia dei lock è SQL Profiler, che è installato insieme
essere gestita da un server differente in un cluster NLB a SQL Server. Permette di vedere la lista tutti i lock per
(network load balanced). tutti gli utenti attivi in un certo istante.
Potreste chiedervi se il secondo frammento è davvero
conforme alle pratiche di programmazione orientate agli Conclusioni
oggetti: tutto è confinato ad una chiamata a metodo e È ovviamente impossibile coprire in un singolo artico-
l’identità dell’oggetto non conta niente. Avete ragione! lo tutti gli aspetti della progettazione e dell’implemen-
Quando si lavora con oggetti remoti non è una buo- tazione di applicazioni scalabili.
na abitudine continuare ad usare il paradigma orienta- Ma la mia esperienza insegna che i tre passi che ho
to agli oggetti, meglio invece concentrarsi su ogni chia- spiegato nell’articolo aiutano a migliorare la scalabilità
mata a sé stante. per molte applicazioni.
I sistemi ad oggetti distribuiti sui quali potreste fare affi- Per quelli che vogliono approfondire gli argomenti rac-
damento per avere l’identità degli oggetti server-side vi le- comando il libro [4] e i primi capitoli di [5], che con-
gherebbero indissolubilmente ad una macchina, limitando tengono informazioni sui fondamenti della elaborazio-
la capacità di load balancing e failover automatico. ne delle transazioni, condivisione delle risorse e siste-
mi scalabili.
3. Scovare i colli di bottiglia
Nelle applicazioni distribuite di solito si trovano due dif- Bibliografia
ferenti colli di bottiglia: quelli locali e quelli globali.
Un collo di bottiglia locale interessa solo un server e [1] Ingo Rammer, “La velocità non è tutto“, VB & .NET
può essere di solito eliminato con miglioramenti sulla Journal n° 59
performance o aggiungendo una macchina al cluster. [2] Ingo Rammer, “Accesso ai dati più veloce e scalabi-
Questi tipi di blocchi hanno solitamente una criticità le“, VB & .NET Journal n° 56
minore in quanto possono essere risolti successivamen- [3] “Locking Hints”, http://msdn.microsoft.com/library/en-
te (cioè quando si riveleranno). us/acdata/ac_8_con_7a_1hf7.asp
L’identificazione dei colli di bottiglia globali invece è [4] Jim Gray and Andreas Reuter, “Transaction Proces-
molto più importante. sing: Concepts and Techniques”, Morgan Kaufmann.
Si verificano ogni volta che si accedono risorse condi- ISBN 1558601902.
vise, come tabelle di database. Rientrano nella categoria [5] Tim Ewald, “Transactional COM+”, Addison-Wesley,
il deadlock (il classico killer della scalabilità., vedi [2]), i ISBN 0201615940.

52 VBJ N. 60 - Novembre/Dicembre 2004


POSTA mail_vbj@infomedia.it a cura di Alberto Falossi

Questo metodo è sfruttato anche dall’IDE e comporta le diffe-


Gestore globale di eccezioni renze da te notate.

Sto lavorando ad un applicativo WindowsForms, scritto parte ‘ di solito in Form_Load


in VB, parte in C#. AddHandler Application.ThreadException, AddressOf UnhandledExcep-
L’applicativo consta di un Main iniziale che lancia una MDI tionProc
form all’interno della quale si lanciano tutte le varie funzionalità.
Ho implementato un sistema di gestione delle eccezio- Private Sub UnhandledExceptionProc(ByVal sender As Object, ByVal e
ni che, in ogni metodo, intercetta l’eccezione, crea un As System.Threading.ThreadExceptionEventArgs)
oggetto di eccezione (una nostra classe che eredita da
Exception), aggiunge le informazioni necessarie, tra cui la Dim msg As String = StringFormat(“{0}\n\nClick Yes to save current
sequenza dei metodi chiamati, e poi rilancia l’eccezione al data\nClick No to exit without saving\nClick Cancel to ignore
metodo chiamante (se esiste), oppure scrive un log dell’ec- error”, e.Exception.Message)
cezione su file, dando un opportuno messaggio all’utente.
Sto osservando un comportamento differente nella Select Case MessageBox.Show(msg, “Unhandled error”, MessageBox
gestione delle eccezioni, a seconda che l’eccezione si Buttons.YesNoCancel, MessageBoxIcon.Error)
verifichi eseguendo il codice all’interno dell’ambiente di
sviluppo oppure lanciando semplicemente l’eseguibile. Case DialogResult.Cancel
Nel primo caso qualunque eccezione riesce a “risalire” Exit Sub
fino alla gestione eccezioni presente nel Main. Invece,
se si è lanciato semplicemente l’eseguibile, l’eccezio- Case DialogResult.No
ne viene intercettata dal gestore di eccezioni di .NET. Application.Exit()
Credo (ma non ne ho la certezza) che questa dif-
ferenza si verifichi quando si ha un’eccezione in un Case DialogResult.Yes
metodo che gestisce direttamente o indirettamen- ‘ salva i dati dell’applicazione
te un evento (ad esempio il click su un pulsante). ‘ scrive nel log
A questo punto vorrei capire se le mie supposizioni sono Application.Exit()
corrette e se è possibile decidere il comportamento del ge- End Select
store delle eccezioni intervenendo con qualche impostazione.
Sarebbe, infatti, molto comodo poter far risalire tutte le End Sub
eccezioni al Main.
A.F.
Giorgio

Come intercetti le eccezioni? In genere nelle applicazioni Win-


Forms puoi usare un comodo evento per le eccezioni non gestite, Richiamare un DLL C++ da VB6
e quindi centralizzare in un unico punto la gestione delle stesse.
Ho scritto una DLL con Visual C++, e sto cercando di uti-
lizzarla dall’interno di Visual Basic, ma non viene riconosciuta.
Come posso fare?

I compilatori C++ applicano una tecnica nota come name mangling


Alberto Falossi è formatore e consulente per Code Architects
per assegnare nomi differenti a funzioni omonime definite all’interno
(www.codearchitects.com) su .NET e tecnologie correlate. Si
occupa del coordinamento editoriale di VBJ e collabora con
di classi diverse. Anche se la funzione viene definita globalmente,
numerose riviste di programmazione italiane e straniere. È mem- e quindi esternamente alle classi, questa tecnica viene applicata
bro del team di .NET-2-The-Maxwww.dotnet2themax.com).
( egualmente, col risultato di ottenere una funzione con un nome
Può essere contattato tramite il sito www.albertofalossi.it, dove diverso da quello effettivamente impostato. Per evitare questo pro-
mantiene anche il blog personale. blema occorre utilizzare la direttiva extern “C” davanti al nome della

54 VBJ N. 60 - Novembre/Dicembre 2004


POSTA

funzione, in modo da indicare al compilatore di considerarla come If Len(Giorno) = 1 Then


una funzione C e non C++. Per esempio: Giorno = “0” & Giorno
End If
extern “C” __declspec(dllexport) int MyFunc( char *str ) {
… Essendo la variabile in questione definita come String, questa
} correzione garantisce che il codice accodato sarà sempre di 2 ca-
Lorenzo Vandoni ratteri. Si possono, comunque, percorrere anche strade alternative.
Per esempio si può operare sull’interfaccia utilizzata dall’utente per
inserire i dati e fare sì che l’informazione che arriva alla routine sia
sempre di due cifre. Una terza possibilità è rappresentata dall’utiliz-
Calcolo del codice fiscale: zo della funzione Format nell’istruzione che concatena la variabile
errata corrige Giorno al resto del codice fiscale.
Grazie della segnalazione, il sorgente sul server Infomedia è stato
Volevo segnalarvi un errore nell’algoritmo per la generazione aggiornato.
del codice fiscale apparso nel numero 56.
Ho scaricato il sorgente ed ho eseguito il progetto relativo Lorenzo Braidi
inserendo i miei dati anagrafici: il codice fiscale generato era
però più corto di un carattere.
Ho notato che i giorni da 01 a 09 vengono formattati senza
lo zero, cosi nella riga 122 della “Function Compute” ho inse- Scrivere una pagina ASP .NET
rito un Len(giorno) < 2 per il controllo del giorno di nascita con diversi linguaggi
aggiungendo lo zero nella stringa.
Saluti, Nella mia piccola compagnia abbiamo iniziato a sviluppare in
Hansel ASP.NET. Abbiamo discusso su quale linguaggio usare: alla fine
abbiamo preferito VB.NET.
Tra le questioni che sono sorte ve n’è una a cui non siamo stati
È vero. Effettivamente, nel progetto VB allegato all’articolo di capaci di rispondere: è possibile realizzare una pagina Web con
cui parli è presente un piccolo errore che influisce sul calcolo del linguaggi differenti?
codice restituito. Nel senso di mixare linguaggi di scripting? Probabilmente è
L’articolo in questione illustra in dettaglio quale sia la struttura di più una curiosità che una necessità, ma confidiamo in una sua
un codice fiscale ed afferma che i caratteri che vanno dal settimo risposta.
all’undicesimo riportano informazioni relative alla data di nascita
della persona cui si riferisce. Se andiamo a vedere nel codice, Saluti,
troviamo Federico

CF = CF & Right(Anno, 2) Una pagina ASP.NET deve essere scritta in un unico linguaggio
CF = CF & Mesi(CInt(Mese)) di scripting, quello specificato nella direttiva language della pagina.
If Sesso = “F” Then Ad esempio
CF = CF & CStr(CInt(Giorno) + 40)
Else <%@ Page language=”C#“ %>
CF = CF & Mid(Giorno, 1, 2)
End If Tuttavia non tutti sanno che è possibile realizzare una pagina con
linguaggi diversi avvalendosi degli user control. Infatti uno user control
Nel caso in cui il soggetto sia di sesso femminile, si somma 40 può essere scritto in qualsiasi linguaggio ASP.NET, anche differente
al giorno di nascita. In questo modo si può essere assolutamente da quello della pagina che lo ospita.
certi del fatto che verranno concatenati alla variabile CF 2 caratteri. Quindi basta isolare le diverse parti di codice in user control
Se, invece, il soggetto è di sesso maschile, non si effettua alcuna separati e usare il linguaggio preferito.
operazione sul giorno di nascita, ma lo si accoda al codice fin qui Il problema è che questa modalità è supportata dal framework ed
ottenuto. è utilizzabile ad esempio quando si scrivono le pagine con notepad,
L’errore è determinato dal fatto che il giorno di nascita può essere ma non è supportata da Visual Studio, che obbliga a sviluppare uno
composto anche da una sola cifra. Si verifica un’anomalia, quindi, user control nello stesso linguaggio della pagina e del progetto.
nel caso in cui il soggetto sia di sesso maschile e sia nato in uno dei Il discorso vale anche a livello di applicazione: se si usa Visual Studio
primi nove giorni di un mese qualsiasi. Esistono molteplici possibilità e quindi il code-behind, tutte le pagine di una Web application devono
per risolvere il problema. essere scritte nello stesso linguaggio. Se invece si usa la modalità
La più semplice è manipolare opportunamente la variabile che inline, ogni pagina può essere in un linguaggio differente.
contiene il giorno di nascita: A.F.

N. 60 - Novembre/Dicembre 2004 VBJ 55


SOFTWARE ENGINEERING

L'accesso ai dati
nei linguaggi
object-oriented
Tutti i linguaggi object-oriented devono fare i conti con la necessità di gestire dati in
formato relazionale

di Lorenzo Vandoni

I
l paradigma object-oriented si è ormai decisamente im- con la relativa povertà semantica del
posto come standard de-facto nell’ambito dei linguag- modello relazionale.
gi di programmazione. L’ultimo caposaldo di resisten- Tra gli esempi che vengono spes-
za relativamente allo sviluppo su PC, Visual Basic 6, ha so citati per spiegare tale problema
dovuto cedere il passo alla sua versione object-oriented vi è quello relativo ad oggetti com-
Visual Basic .NET, ed anche i linguaggi tipicamente utiliz- plessi, come il disegno tridimensio-
zati in ambienti mini e mainframe, come Cobol, sono stati nale di un’automobile all’interno di un
modificati per permettere la gestione di classi ed oggetti. programma CAD. Utilizzando un lin-
A difendere gli estimatori della programmazione struttura- guaggio di programmazione object-
ta rimane ora solo il C. oriented potremo facilmente definire
Il paradigma object-oriented, però, non è riuscito a impor- una classe Automobile, dotata di me-
si ovunque. I database object-oriented (ODBMS), in parti- todi complessi per la sua gestione,
colare, sono rimasti relegati a campi di applicazione mol- per permettere ad esempio di ruota-
to particolari, e non di rado si è sentito utilizzare il termi- re l’immagine, capovolgerla o stam-
ne “fallimento” nei loro riguardi. Il modello dei dati tuttora parla, e potremo sfruttare l’eredita-
più diffuso rimane quello relazionale, introdotto ormai più rietà per incapsulare in una classe
di 30 anni fa. base Oggetto3D tutte quelle opera-
zioni che possono essere facilmen-
Il problema dell’accesso ai dati te estese ad altri tipi di grafici tridi-
Tutte le applicazioni sviluppate con linguaggi object-orien- mensionali.
ted, nel caso in cui abbiano la necessità di accedere a dati Nel caso in cui molti oggetti di que-
permanenti gestiti da un DBMS, dovranno quindi affron- sto tipo dovessero essere memoriz-
tare un problema concettuale, noto come impedance mi- zati su un DBMS, e se si volessero
smatch, dato dal fatto che gli stessi oggetti dovranno es- permettere interrogazioni del tipo “ri-
sere rappresentati in modi diversi in memoria, dove si potrà cerca tutte le auto con cambio auto-
sfruttare la ricchezza dei costrutti offerti dal linguaggio di matico”, ci troveremmo nella neces-
programmazione, e su disco, dove si dovranno fare i conti sità di scrivere un’algoritmo per tra-
durre la rappresentazione in memo-
ria dell’oggetto in un insieme di righe
Lorenzo Vandoni è laureato in Informatica, ed è uno memorizzate in molte tabelle diverse.
specialista di progettazione e sviluppo con tecniche e
In più, sarà necessario scrivere l’al-
linguaggi object-oriented. Ha collaborato alla realizzazione
di framework, strumenti di sviluppo e software commerciali goritmo inverso, e tradurre in sintas-
in C++, Java e Visual Basic. Può essere contattato tramite si SQL un’interrogazione come quel-
e-mail all’indirizzovandoni@infomedia.it. la precedentemente citata.

56 VBJ N. 60 - Novembre/Dicembre 2004


SOFTWARE ENGINEERING

Il problema dell’impedance mismatch è quindi costituito bile caricandone i dati dal DBMS (una soluzione alterna-
dalla necessità di fornire algoritmi di traduzione per con- tiva, pure corretta, potrebbe essere quella di trasformar-
vertire la rappresentazione di uno stesso oggetto tra due li in costruttori).
formati differenti. La soluzione più naturale per questo Possiamo tralasciare in questa sede i problemi tutt’altro
problema sarebbe quella di utilizzare un unico formato che banali legati alla necessità di disporre di un object
di rappresentazione, come proposto dai sostenitori de- identifier e di un formato opportuno per la rappresenta-
gli ODBMS, ma, come già visto, questi sistemi non han- zione delle interrogazioni, semplicisticamente costituite,
no avuto una sufficiente diffusione. nell’esempio, da un parametro di tipo stringa. Tralascia-
mo anche una possibile discussione sulla definizione di
Uno strato di software per l’accesso ai dati interfacce o classi base che permettano di meglio forma-
Preso atto della necessità di scrivere uno strato di sof- lizzare questo tipo di soluzione, e concentriamoci invece
tware intermedio (o middleware) che si preoccupi di con- sui possibili vantaggi e svantaggi che questa può offrire,
vertire i dati da una rappresentazione object-oriented al in relazione al problema precedentemente esposto.
modello relazionale, e viceversa, occorre trovare il modo Il principale vantaggio è dato da un corretto incapsula-
migliore per farlo. mento del problema. I dettagli relativi alla traduzione dei
Le soluzioni possibili sono sostanzialmente due: la prima dati dell’oggetto tra le due rappresentazioni vengono co-
prende atto della differenza esistente tra i due modelli, e dificati all’interno dei metodi identificati, lasciando il resto
prevede l’introduzione all’interno delle classi dei metodi dell’applicazione all’oscuro del problema. Questo signifi-
necessari per espletare tutte le operazioni necessarie per ca, tra l’altro, che il tipo di rappresentazione dei dati all’in-
il reperimento, il salvataggio e la ricerca dei dati, mentre terno del DBMS potrà essere modificato senza che l’ap-
la seconda tende a considerare il tipo tabella come un plicazione che utilizza la classe ne risenta.
particolare tipo del linguaggio, dotato di caratteristiche e Questa soluzione viene citata all’interno di molti testi, e
limitazioni particolari, e permette di creare uno strato di in alcuni “vecchi” libri scritti con l’obiettivo di spiegare ai
software più generico e facilmente riusabile. programmatori Visual Basic 6 perché mai potesse essere
necessario creare delle classi, invece di limitarsi come in
Accesso object-oriented ai dati passato ad usare form e funzioni, questo veniva addirit-
Il primo tipo di soluzione prevede l’aggiunta all’interno tura indicato come il motivo principale. Si tratta senz’al-
delle classi che costituiscono la rappresentazione object- tro di una soluzione corretta, ma presenta un paio di pro-
oriented del sistema, dei metodi necessari per gestire gli blemi non banali.
oggetti di quella classe all’interno del DBMS. Il primo è dato dalla proliferazione di classi del tutto si-
Tornando all’esempio della classe Automobile, signifi- mili tra loro. Il caso della classe Automobile, ovvero di
ca che dovrà essere creata una classe del tipo (in sin- una classe di oggetti complessi con problemi di Impe-
tassi VB.NET): dance Mismatch non banali, è di fatto piuttosto raro. Mol-
to più spesso, nelle applicazioni gestionali, si utilizzano
Class Automobile oggetti come Cliente, Fornitore o Fattura, che anche al-
‘metodi specifici dell’oggetto l’interno del programma possono essere visti come sem-
Public Sub Ruota(nGradi As Integer) plici aggregati di campi, rappresentabili, a seconda del
... linguaggio utilizzato, con un type o una struttura. Lavo-
Public Sub Capovolgi() rando con oggetti di questo tipo, l’implementazione delle
... classi di livello intermedio diventerebbe banale e ripetiti-
Public Sub Stampa() va, nonché soggetta ad errori e causa di inutili rallenta-
... menti nel codice.
‘metodi per la gestione del DBMS Il secondo problema è dato dalla necessità di accedere
Public Sub Salva() dall’interno del codice ai dati corrispondenti ai campi della
... tabella. Questa necessità porta alla creazione di un insie-
Public Shared Sub Leggi(nObjId As Long) As Automobile me di metodi Get e Set per l’accesso ai dati, in corrispon-
... denza ad ognuno dei campi. Oltre ad enfatizzare i rischi
Public Shared Sub Trova(sCondition As String) As Automobile di ripetitività e rallentamenti precedentemente riscontrati,
... questi metodi introducono anche problemi di manutenzio-
End Class ne, in quanto ad ogni modifica della struttura del database
dovrà corrispondere una modifica del codice della classe.
I due metodi Leggi e Trova devono essere statici (o Questo tipo di soluzione, quindi, dimostra di essere adat-
Shared, secondo la sintassi utilizzata in VB.NET), per- ta per la gestione di oggetti complicati, ma eccessiva e
ché si preoccupano di creare un nuovo oggetto Automo- ridondante per il caso di oggetti più semplici.

N. 60 - Novembre/Dicembre 2004 VBJ 57


SOFTWARE ENGINEERING

Classi generiche di accesso ai dati limitarsi a salvare i dati delle varie colonne, registrerà in
Il secondo approccio prevede la creazione di un’unica modo opportuno anche i dati delle tabelle collegate, pre-
classe Tabella, che possa essere genericamente utilizza- levandoli da strutture dati mantenute in memoria. Analo-
ta per accedere al contenuto di qualsiasi tabella sul data- gamente, il metodo Leggi non si limiterà ad eseguire una
base. Questo approccio è quello adottato dalla maggior sola interrogazione, ma cercherà di reperire, utilizzando
parte delle librerie più diffuse. Un recordset ADO o un da- diverse query, tutte le informazioni necessarie per crea-
taset ADO.NET, nonostante siano notevolmente differenti re l’oggetto Automobile in memoria.
tra loro, possono entrambi essere considerati in questa
categoria. In questo tipo di soluzione, la classe Tabella (o Estendere ADO.NET
Recordset, o Dataset) è concettualmente assimilabile alla La struttura gerarchica delle classi di ADO.NET, con la
rappresentazione in memoria di una tabella relazionale. I separazione di responsabilità fra managed provider (Da-
dati mantenuti al suo interno sono raggruppati in colonne, taReader, DataAdapter) e classi dedicate al mantenimen-
il cui tipo può essere scelto solo all’interno di un insieme to dei dati in memoria (DataTable, DataSet) rende l’im-
di tipi predefiniti, e le operazioni consentite sono quelle di plementazione delle idee precedentemente esposte un
inserimento, modifica e cancellazione di righe. po’ più complicata. L’idea di base, infatti, era quella di
I vantaggi e gli svantaggi di questo approccio sono spe- creare una classe Automobile come estensione di una
culari rispetto alla soluzione prospettata nel paragrafo pre- generica classe Tabella, e di inserire all’interno di que-
cedente. Non è necessario implementare alcuna classe sta classe tutta la logica relativa sia alla manipolazione
aggiuntiva, in quanto per ogni tabella di database verrà dei dati (Ruota, Capovolgi, Stampa), sia quella relativa al
semplicemente creata una nuova istanza della classe Ta- salvataggio e al reperimento dei dati dal database (Sal-
bella, e non si potranno riscontrare quindi problemi legati va, Leggi, Trova). La separazione di responsabilità tra le
a possibili errori di codifica, rallentamenti e necessità di classi base ci costringe ad adottare una soluzione alter-
manutenzione. D’altra parte, questo tipo di approccio non nativa. Le possibilità sono diverse:
risolve il problema dell’impedance mismatch, perché non
permette di creare una classe Automobile che mascheri • definire la classe Automobile come estensione di Da-
il modo in cui i vari componenti, come volante, motore e taset, aggiungendo al suo interno anche un riferimen-
ruote, sono rappresentati all’interno del database. La lo- to ad un DataAdapter, in modo da poter implementa-
gica applicativa dovrà essere implementata in una clas- re la logica relativa ai metodi Salva, Leggi e Trova;
se a parte, che utilizzerà una o più istanze della classe
Tabella per reperire i dati utili a costruire una rappresen- • creare due classi separate, AutomobileDataSet e Au-
tazione in memoria dell’oggetto. tomobileDataAdapter, mantenendo anche nelle clas-
si derivate la stessa distinzione esistente nelle classi
In medio stat virtus base;
L’approccio più conveniente da adottare consiste nel-
l’applicare contemporaneamente le due tecniche prece- • creare una nostra classe base Tabella, che incapsu-
denti, comportandosi in modo diverso a seconda del livel- li al suo interno un DataSet e un DataAdapter, e de-
lo di complessità dell’oggetto rappresentato. Per oggetti finire la classe Automobile come estensione di que-
strutturalmente semplici, come Cliente, Fornitore e Fattu- st’ultima.
ra, potrà essere sufficiente istanziare una classe Tabella
di tipo generico, mentre per oggetti più complessi, come Per ora, limitiamoci a queste considerazioni. Torneremo
Automobile, potrà essere conveniente creare una classe su queste possibilità in un prossimo articolo, in cui pre-
specifica che mascheri la struttura del database. senterò più in dettaglio una possibile soluzione.
Con l’avvento di .NET, questo approccio diventa parti-
colarmente conveniente, grazie all’introduzione di mec- Conclusioni
canismi come ereditarietà e polimorfismo. In pratica, di- Il framework che è stato tratteggiato nei paragrafi prece-
venta possibile fare in modo che la propria classe Auto- denti non tiene conto della possibilità di sfruttare l’eredi-
mobile venga creata come sottoclasse della classe più tarietà multipla. L’unico linguaggio che permette l’utilizzo
generica Tabella, ereditandone in questo modo tutte le dell’ereditarietà multipla, tra quelli più diffusi, è C++, per
funzionalità di base, come l’accesso ai valori dei cam- cui ho preferito non considerare questa ipotesi.
pi elementari. La creazione di un insieme di classi che forniscano una
In questo modo, la classe potrà essere facilmente do- gestione completa dei “business object” utilizzati dall’ap-
tata di funzionalità supplementari, e si potrà anche fare plicazione può essere molto utile per la suddivisione del
in modo di sovrascrivere il comportamento di alcuni me- programma in più strati, o tier, e può semplificare il riuso
todi. Per esempio, il metodo Salva, o Update, invece di della logica applicativa in applicazioni diverse.

58 VBJ N. 60 - Novembre/Dicembre 2004


IN VETRINA VBJ 60
Microsoft Office 2003
Scrivi a CSS Cookbook
for Healthcare book@infomedia.it
Christopher Schmitt
Ahmad Hashem
specificando
nell’oggetto della
e-mail:
608 pp. euro 31,95
ISBN 0789732114
IN VETRINA 270 pp. euro 34,95
ISBN 0596005768
VBJ n. 60
OPPURE
inviaci il coupon
Mobile Applications. Head First Servlets
Architecture, Design, sottostante and JSP
and Development al numero di fax Bryan Basham,
Valentino Lee, Heather 0587/732232 Kathy Sierra, Bert Bates
Schneider, Robbie Schell
Potrai acquistare
368 pp, euro 46.95 886 pp. euro 44,95
ISBN 0131172638 i libri qui riportati con uno ISBN 0596005407
SCONTO
ECCEZIONALE
Linux Shell Scripting Managing Security

del 10% anche se


with Bash with Snort & IDS Tools

Ken O Burtch
acquisti solo un libro Kerry J. Cox,
Christopher Gerg
OPPURE
432 pp. euro 36,95
ISBN 0672326426 del 20% se acquisti 288 pp. euro 39,95
ISBN 0596006616
3 libri

VBJ 60
LIBRI
Writing Add-ins for Adobe Acrobat6
Visual Studio .NET The Professional User’s Guide
Autore Les Smith Autore D. L. Baker, T. Carson
Editore Apress Editore Apress
ISBN 1-59059-026-0 ISBN 1-59059-232-8
Lingua Inglese Lingua Inglese
Anno 2002 Anno 2004
Pagine 520 Pagine 460
Prezzo € 53,45 Prezzo € 42,75

isual Studio .NET è un ottimo ambiente di lavoro integrato per uesto libro non è stato scritto per i novizi, ma è rivolto ad una

V programmatori .NET, sia che usino VB.NET o C#. Anche nello


strumento migliore però qualcuno troverà immancabilmente qual-
che mancanza, e VS.NET non si sottrae certo a questa regola. Tramite
Q utenza professionale, così come testimoniato dal titolo stesso.
La promessa è quella di trarre utilità dall’apprendimento dei
segreti di questa ultima versione di Acrobat e la ragione per cui
il modello ad oggetti esposto un programmatore può però estendere gli autori dicono di aver scritto il testo (e per cui bisognerebbe
l’IDE con nuovi comandi e finestre. Questo libro si propone appunto leggerlo!) è sottolineata da loro stessi: raggiungere l’obiettivo di
come guida allo sviluppo di add-in e macro per VS.NET. Si comincia lavorare di meno facendo lavorare di più le macchine. Un intento
da un’introduzione alle varie parti dell’IDE, per passare velocemente del genere, che ha un che di filosofico, viene perseguito illustrando
all’uso dell’Add-in wizard che genera automaticamente uno scheletro i molti vantaggi di Acrobat 6: già da un veloce sguardo al primo
per un nuovo add-in, a tecniche (semplici a dire il vero) di debug- capitolo si intuisce come le differenze della celeberrima suite rispetto
ging, manipolazione di codice, controlli dell’interfaccia utente (solo alla versione precedente siano sostanziali. Tra le molte funzionalità
di Windows Forms però, non si nomina neanche ASP.NET), progetti illustrate impossibile non ricordare il Binder, un potentissimo tool
e soluzioni. Un capitolo è dedicato anche alle macro. Gli argomenti che consente di combinare in un unico file PDF differenti formati di
trattati sono parecchi, ma nessuno veramente in dettaglio purtroppo. file. Nei primi capitoli si familiarizza con l’interfaccia (sotanzialmente
Moltissime domande che ci si ritrova ad affrontare non appena si nuova) e si impara a creare e manipolare file PDF. Una volta capito
comincia un progetto reale restano senza risposta, dal momento come ottenere il proprio file PDF si entra nello specifico: editing
che il codice di esempio presentato non è certo molto completo o avanzato e strumenti per la “collaboration” vengono descritti nei
professionale. La presenza di alcuni errori nel codice poi non aiuta di dettagli. Ormai non si può prescindere dalla sicurezza ed il libro
certo. Sempre riguardo il codice, sono stampati listati anche di quin- non fa eccezione, illustrando come proteggere da alterazioni i
dici pagine dove ne sarebbe bastata una per il codice interessante propri documenti e come assicurarne e verificarne l’integrità e la
e relativo all’argomento specifico del capitolo in questione. Inoltre, genuinità. Leggendo il libro si ha l’impressione che nulla venga
nonostante in copertina si citi sia VB.NET che C#, a C# sono dedicate tralasciato: un intero capitolo dedicato alla creazione di forms, ad
solo un paio di pagine, e il codice VB.NET sembra in realtà VB6, dato esempio, non lascia al lettore alcun dubbio riguardo al loro utilizzo.
l’uso estensivo di funzioni come MsgBox, Len, Mid, Left, Right ecc. Anche le funzionalità classiche, quali l’indicizzazione e la ricerca,
Addirittura l’addin presentato come progetto finale genera codice in la preparazione dell’output e la stampa vengono opportunamente
stile VB6! Un capitolo che invece ho apprezzato più degli altri è “How descritte con grossa attenzione alla accessibilità dei documenti
do I…”, che presenta una lista di Q&A con frammenti di codici pronti creati. Le sorprese più positive arrivano dalla lettura degli ultimi
da usare (sebbene qualche ritocco sia di solito necessario…), perché capitoli: un “All about ebooks” che non tradisce le aspettative del
va direttamente al punto e riesce a dare effettivamente un aiuto al titolo e un capitolo che descrive funzionalità avanzate. Scorgendo
programmatore in cerca di risposte a problemi tipici. In definitiva, il l’indice potrebbe soprendere un capitolo su JavaScript, ma leg-
libro può essere un’utile introduzione per farsi un’idea di quelle che gendolo si apprende come questo linguaggio estenda in modo
sono le possibilità di estensione di VS.NET, per chi ha già sviluppato sostanziale le potenzialità della Suite che pure non è storicamente
addin in VB6 e a maggior ragione per chi comincia da zero, ma non indirizzata a chi scrive codice. Utilissimo, infine, l’ultimo capitolo
può essere considerato come la guida definitiva sull’argomento. che permette di mettere insieme in maniera pragmatica molti dei
concetti appresi durante la lettura mediante la realizzazione di un
Pro progetto di creazione di una knowledgebase.
La sezione “How do I…?” presenta Q&A e pezzi di codice
che possono tornare utili, con le opportune modifiche, in molte Pro
situazioni. Un testo utilissimo per diverse categorie di professionisti: graphic/web
designer, architetti, ingegneri ed in generale utenza di tipo business.
Contro
Listati troppo lunghi e dispersivi, a volte copiati più volte solo Contro
per cambiare una singola riga. Gli argomenti sono trattati troppo Il testo si rivolge ad un utenza di tipo professionale risultando di
superficialmente, e gli esempi sono troppo semplici per essere conseguenza non molto indicato per un pubblico che si avvicina
usati come base per progetti di qualità commerciale.. alla materia per la prima volta.
Marco Bellinaso Massimiliano Mariconda

N. 60 - Novembre/Dicembre 2004 VBJ 61


.NET TOOLS
a cura di Davide Mauri dmauri@programmers.net

Reflector
Credo che sicuramente abbiate usato tutti, chi per
semplice curiosità chi per necessità professionali, il tool
ILDASM.exe, ossia il disassembler fornito da Microsoft
nel .NET Framework SDK, che permette di visualizzare il
codice MSIL generato dal compilatore dal nostro codice
sorgente e vedere ciò che viene davvero dato in pasto
al CLR. Lutz Roeder deve aver pensato che, se un com-
pilatore può generare MSIL deve essere vero anche il
contrario, e quindi passare da questo a C#, VB.NET, e
così via. Detto, fatto! Nell’ottobre del 2000 nasce la prima
versione di questo ormai popolarissimo tool, che permette
a chiunque di sbirciare all’interno di un assembly .NET
(quindi in qualsiasi programma basato sul framework), di
disassemblarlo e di ricostruirne il codice sorgente (Figura
1). Il codice sorgente così ottenuto ovviamente non è
identico all’originale (tranne per i casi più semplici), ma
è funzionalmente equivalente, ossia produce lo stesso Figura 1 Reflector in azione su un’applicazione di test
risultato. La cosa interessante è che Reflector permette
di decompilare in quattro diversi linguaggi: MSIL, C#,
VB.NET e Delphi.NET. Un esempio pratico è visibile tramite
il Listato 1 ed il Listato 2; il primo è il codice originale
scritto in C#, il secondo è il risultato della decompilazione Listato 1 Il codice originale C# di una semplice
utilizzando come destinazione VB.NET. Proprio tramite applicazione di esempio
i due listati credo si possa capire l’enorme utilità di Re-
flector: grazie a questo è possibile scoprire quello che
using System;
accade davvero durante l’esecuzione di un’applicazione…
che, purtroppo, non sempre è quello che ci aspettiamo namespace SampleApp
o quello che è documentato. {
Nel caso preso in esame è possibile vedere come class SampleClass
dichiarazione, creazione ed inizializzazione del campo {
statico someStrings siano convertite in realtà (come static string[] someStrings = new string[10] { “a”, “b”,
giustamente ci si aspettava) in una dichiarazione pura “c”, “d”, “e”, “f”, “g”, “h”, “i”, “l”};
separata dalla creazione e dall’inizializzazione che invece
[STAThread]
vengono eseguite nel costruttore statico, creato in modo static void Main(string[] args)
automatico dal compilatore. Interessante, vero? Beh, direi {
che curiosi ed assetati di conoscenza sono serviti! Se foreach(string s in someStrings) {
le funzionalità fin qui descritte ancora non vi bastano, Console.WriteLine(s);
niente paura! Reflector supporta l’aggiunta di funzionalità }
}
tramite plugin. Già diversi se ne trovano in giro, e tra i più
}
interessanti segnalo questi: }

Davide Mauri è un consulente freelance che si occupa di  Reflector.VisualStudio: come lascia intendere il nome per-
SQL Server 2000 e di sviluppo di soluzioni Web basate sul mette di integrare Reflector all’interno di Visual Studio, e
.NET Framework. All’attività di consulenza affianca una co- rimpiazzare definitivamente il class browser nativo;
spicua attività di docenza e di formazione presso Mondadori  Reflector.McppLanguage: per ottenere un decompilato
Informatica. Il suo sito personale è www.davidemauri.it. scritto in C++;

62 VBJ N. 60 - Novembre/Dicembre 2004


.NET TOOLS

 Reflector.FileDisassembler: per salvare il codice pro-


dotto da Reflector su file in modo automatico;
 Reflector.OpenRunningAssembly: per caricare in Re-
flector un assembly in esecuzione;
 Reflector.Graph: per visualizzare graficamente collega-
menti e dipendenze del nostro codice. Spettacolare!

Potete scaricarli al terzo indirizzo nella tabella sottostante.


Creare un proprio plugin è relativamente semplice, e su
GotDotNet si trova tutto il necessario: nel caso vi servisse
qualcosa di particolare potete svilupparne uno in auto-
nomia, e ovviamente non mancate di segnalarmelo! Per
concludere il tool è veramente molto semplice da usare,
e, oltre all’utilità intrinseca di un’applicazione di questo
tipo, tutta una serie di tocchi di classe, come la ricerca
integrata su Google o su MSDN dei metodi e delle pro-
prietà dell’assembly in analisi, oppure l’integrazione con la
documentazione prodotta in formato XML, ne hanno fatto
Figura 2 Il completo IDE di The Regulator
un tool indispensabile per molti sviluppatori.

Prodotto lar Expression, oggettini simpatici, estremamente potenti


Reflector (in alcuni casi indispensabili) ma parecchio complessi da
scrivere. Vi ricordate? Ne avevamo già parlato in un numero
Url di riferimento precedente di .NET Tools, [1]. Perché questo tool è così
http://www.aisto.com/roeder/dotnet/ bello? Beh, i motivi sono tanti ma probabilmente il principale
http://www.gotdotnet.com/workspaces/workspace.aspx è l’integrazione con il sito RegExLib.com, tramite il quale
?id=0f5746c3-c7aa-4879-8043-e0f4fc233ade è possibile cercare, direttamente dall’interno dell’editor,
http://www.freewebs.com/csharp/Reflector/Addins/ le regular expression che ci servono. Dovete validare un
Stato Release indirizzo e-mail? Cercate “email”. Vi serve una RegEx per
4.1.3.0 validare un numero di telefono nel formato italiano? Cer-
cate “italian”. Nel caso in cui invece la regular expression
Semplicità d’uso  debba essere scritta ex-novo, avete a disposizione syntax
Semplicissimo! Basta caricare l’assembly desiderato ed highlighting ed intellisense, più la possibilità di comporre
è fatta. l’espressione costruendola tramite un menu contestuale.
Utilità  Una volta in possesso della regular expression desiderata,
Non è un tool che utilizzerete tutti i giorni...ma se non ci questa può essere provata su un testo di esempio, in modo
fosse bisognerebbe inventarlo! da verificarne la correttezza. A questo punto è poi possibile
generare il codice C# o VB.NET da inserire nella nostra
Qualità prodotto  soluzione per applicare l’espressione, oppure un’assem-
Nulla da dire. Ottima, soprattutto per il supporto di plug-in
bly da referenziare nel progetto, già compilato. Un’ultima
esterni.
feature non meno interessante è il “RegEx Analyzer”, che,
Qualità documentazione  leggendo la regular expression digitata, descrive, in inglese,
Di documentazione praticamente non ce n’é, ma non se il comportamento della stessa. Ad esempio, questa porzione
ne sente troppo il bisogno, visto che è tutto molto sem- di espressione:
plice. Molto buona la documentazione e gli esempi per
la scrittura di plugin. (?<Hour>\d{2})

The Regulator viene descritta come:

Se dovessi scrivere in una sola riga che cos’è The Regu- Capture to <Hour> Any Digit Exactly 2 times
lator, mi basterebbe dire “È il Visual Studio delle Regular
Expression”. Per fortuna lo spazio non manca, ma penso utile, soprattutto se siete agli inizi, per decifrare le criptiche
che quanto appena detto dia immediatamente un’idea della espressioni. Come ultima nota, e come ciliegina sulla torta,
potenza e della qualità del tool di cui stiamo parlando. Come viene anche fornito un help che spiega tutte le funzionalità
avrete già potuto intuire The Regulator è un editor di Regu- del programma e che contiene anche diversi articoli (alcuni

N. 60 - Novembre/Dicembre 2004 VBJ 63


.NET TOOLS

provenienti direttamente dal sito MSDN) che mostrano dei  Gestione dei profili
possibili utilizzi (pratici) delle regular expression. Un tool che È possibile memorizzare la configurazione di deploy-
non può mancare alla vostra collezione! ment per un progetto in modo da poter effettuare il
rilascio dello stesso con un solo click.
 Multi Profile Deployment
Prodotto È possibile distribuire i file su più profili contemporanea-
The Regulator mente. Utile quando si rilasciano applicazioni ospitate
su più di un web server.
Url di riferimento  Integrazione con Visual Studio
http://royo.is-a-geek.com/iserializable/regulator/ Cliccando con il tasto destro sulla cartella del progetto,
Stato Release è disponibile una nuova icona che attiva il deployment
2.0.3.0 di UnleashIt.

Semplicità d’uso  Oltre a tutte queste peculiarità è possibile anche ef-
Semplifica enormemente sviluppo e debug di regular ex- fettuare il backup dei file di cui si sta facendo il deploy-
pression. Fantastica la possibilità di effettuare ricerche ment, attivare il logging di tutte le operazioni eseguite,
direttamente sul RegexLib.com e, per una massima personalizzazione, anche definire
Utilità 
Dato che le regular expression sono utili dappertutto,
questo lo è di conseguenza.
Listato 2 Il codice VB.NET generato da Reflector
tramite decompilazione
Qualità prodotto 
Ottima. Non a caso è stato messo tra i top-ten tools da
avere assolutamente. Imports System

Qualità documentazione  Namespace SampleApp


Ottima, con tanto di help in linea. Friend Class SampleClass
‘ Methods
Private Shared Sub New()
Dim textArray1 As String() = New String(10) {}
UnleashIt textArray1(0) = “a”
textArray1(1) = “b”
UnleashIt è un piccolo tool, dalla quale gli sviluppatori di textArray1(2) = “c”
applicazioni web difficilmente si separeranno dopo averlo textArray1(3) = “d”
usato. Il suo scopo è quello di semplificare ed automatizzare textArray1(4) = “e”
al massimo la fase di deploy della soluzione. Se infatti non textArray1(5) = “f”
si utilizzano le FrontPage extensions, in pratica il deploy di textArray1(6) = “g”
textArray1(7) = “h”
un’applicazione web deve essere fatto a mano, a meno di
textArray1(8) = “i”
non voler creare un’applicazione di setup; cosa non sempre textArray1(9) = “l”
possibile, soprattutto se volete solamente trasferire i file sul SampleClass.someStrings = textArray1
server della società che vi fornisce l’hosting. In questo caso End Sub
di solito si utilizzano i soliti metodi di copia via FTP o, se pos-
sibile, via VPN su una cartella condivisa. L’inconveniente di Public Sub New()
End Sub
tale soluzione è generalmente dovuto alle dimensioni dell’ap-
plicazione stessa. Se è abbastanza grossa può essere facile <STAThread> _
dimenticarsi qualche file durante l’upload. Con UnleashIt (che Private Shared Sub Main(ByVal args As String())
prima di giungere alla versione 2.0 si chiamava WebDeploy) Dim textArray1 As String() =
tutto questo non sarà più un problema. Una volta caricato, SampleClass.someStrings
l’interfaccia grafica, visibile in Figura 3, permette di scegliere Dim num1 As Integer = 0
la directory nella quale sono presenti i file sorgenti oppure, Do While (num1 < textArray1.Length)
Dim text1 As String = textArray1(num1)
se preferiamo, il file del progetto generato da Visual Studio.
Console.WriteLine(text1)
Tramite quest’ultima opzione UnleashIt selezionerà in auto- ++num1
matico tutti i file presenti nel progetto. Nel caso si vogliano Loop
personalizzare i file da trasferire, è possibile utilizzare le voci End Sub
visibili sulla destra, in modo da includere od escludere file e/o
directory a seconda delle proprie necessità. Fatto ciò è poi
‘ Fields
necessario specificare il percorso di destinazione, che può
Private Shared someStrings As String()
essere un percorso di rete, un indirizzo ftp oppure un file .zip, End Class
cliccare sul pulsante “Deploy” ed il gioco è fatto. Tra le feature End Namespace
particolarmente interessanti da segnalare troviamo:

64 VBJ N. 60 - Novembre/Dicembre 2004


.NET TOOLS

Prodotto
UnleashIt
Url di riferimento
http://www.eworldui.net/UnleashIt/
Stato Release
2.0
Semplicità d’uso 
Più semplice di così è impossibile.
Utilità 
Ormai non posso più farne a meno. Fantastica l’integra-
zione con Visual Studio!
Qualità prodotto 
Ottima.

Figura 3 La semplice – ma completa – interfaccia Qualità documentazione 


utente di UnleashIt Tutta contestuale, molto semplice e molto pratica.

Riferimenti
dei comandi che devono essere eseguiti prima e dopo
l’operazione di rilascio. [1] Rubrica .NET Tools, Visual Basic & .NET Journal n° 55
ABBONAMENTI
COD. CLIENTE ____________________

INDIRIZZO DI SPEDIZIONE
Nome ___________________________ Cognome ___________________________ Ditta _____________________________
Via ________________________________ C.A.P. _______________ Città _____________________________ Prov. ________
& ARRETRATI

Tel. ____________________________ Fax ____________________________ E-mail _________________________________

Prezzo Prezzo Prezzo Prezzo


Riviste Abbonamento Rinnovo Riviste - Spedizione Abbonamento Rinnovo
POSTA PRIORITARIA
CP € 52,00  € 48,00 
DEV € 52,00  € 48,00  CP P.P. € 70,00  € 66,00 

VBJ € 46,00  € 42,00  DEV P.P. € 70,00  € 66,00 

Login € 46,00  € 42,00  VBJ P.P. € 56,00  € 52,00 

4 riviste € 196,00  € 180,00  Login P.P. € 56,00  € 52,00 


4 riviste P.P. € 252,00  € 236,00 
CP Web € 42,00  € 38,00  4 riv. P.P. + 4 riv. Web € 424,00  € 356,00 
DEV Web € 42,00  € 38,00 
TOTALE € ________________
VBJ Web € 44,00  € 40,00 
Login Web € 44,00  € 40,00  Arretrati
Numero rivista Prezzo cadauno Totale
4 riviste Web € 172,00  € 156,00 
 CP ____________________ € 10,00 € _________
4 riv. + 4 riv. Web € 368,00  € 300,00   DEV ___________________ € 10,00 € _________
TOTALE € ________________  Login _________________ € 14,00 € _________
 VBJ ____________________ € 14,00 € _________
 Gli abbonamenti decorrono dal primo numero raggiungibile. TOTALE € _________
Per attivazioni retroattive contattaci al numero 0587/736460 o + Spese spedizione
invia una e-mail all’indirizzo abbonamenti@gruppoinfomedia.it
 I prezzi degli abbonamenti per l’estero sono maggiorati di
(€ 2,50 per 1 rivista,€ 4.00 per 2 o più riviste) € _________
spese di spedizione. TOTALE € _________

TIPO DI PAGAMENTO VBJ 60


 Contrassegno (+ € 7,00 per spese postali)
 Allego fotocopia della ricevuta del versamento su C/C postale n. 14291561 intestato a “Gruppo Editoriale Infomedia S.r.l. Ponsacco”
 Allego assegno bancario intestato a “Gruppo Editoriale Infomedia S.r.l.” (NON TRASFERIBILE)
 Allego fotocopia del Bonifico Bancario effettuato sul C/C 000010005424 CAB 71120 ABI 6370 CIN “M” - Cassa di Risparmio di Volterra Agenzia di Ponsacco
 Autorizzo l’addebito dell’importo di €_______________ sulla mia CARTA VISA/CARTASì

Numero
Scadenza
Titolare ____________________________________________ nato il ___/___/_______ Firma ___________________________________

 Mi collego al sito www.infomedia.it dove potrò effettuare il pagamento con carta di credito in modalità sicura (Banca SELLA)

L’IVA sul prezzo dell’abbonamento è assolta dall’Editore e non sussiste l’obbligo di emissione della fattura, ai sensi del D.M. 9 aprile 1993, art.1, comma 5; pertanto,
a fini contabili, farà fede la sola ricevuta di pagamento; perciò la fattura verrà emessa solo se esplicitamente richiesta al momento dell’ordine.
Garanzia di riservatezza - Il Gruppo Editoriale Infomedia garantisce la massima riservatezza dei dati da lei forniti e la possibilità di richiederne gratuitamente la rettifica o la cancellazione scrivendo a: Responsabile Dati - Gruppo Editoriale
Infomedia Srl - Via Valdera P. 116 - 56038 Ponsacco (PI). Le informazioni custodite nel nostro archivio elettronico verranno rtattate in conformità alla legge 675/96 sulla tutela dati personali.

V. Valdera P., 116 - 56038 Ponsacco (Pi) - Tel. 0587/736460 - Fax 0587/732232
P.Iva 01474440508 - abbonamenti@gruppoinfomedia.it - www.infomedia.it