Informatica 2 (versione PDF)

MASSIMO UBERTINI
SERVER SIDE
WWW.UBERTINI.IT
MODULO 4
WEB
Applicazioni web
Server DB
Server web
Sicurezza dei server web
DB centrale e DB remoti
RIA
LightSwitch
Server side
um 1 di 243
APPLICAZIONI WEB
Introduzione
Il primo problema da affrontare quando s’inizia a sviluppare un’applicazione web a
contenuto dinamico è che tecnologia utilizzare: le più conosciute sono quattro.
1. La piattaforma .NET di Microsoft, programmabile per applicazioni web con il suo
linguaggio ASP.NET (Active Server Page) e utilizzabile con il server web IIS (Internet
Information Server).
2. La piattaforma Java, programmabile con il linguaggio JSP (JavaServer Pages) e
tramite blocchi di codice Java chiamati Servlet e utilizzabile con il server web Tomcat.
3. La piattaforma AMP (Apache MySQL PHP), programmabile con il linguaggio PHP
(Hypertext PreProcessor) e utilizzabile con il server web Apache.
4. La piattaforma MX, programmabile con un linguaggio a TAG chiamato CFML
(ColdFusion Markup Language) e utilizzabile con il server web ColdFusionMX di
Macromedia.
LINGUAGGI
Il browser invia una richiesta al server web, quest’ultimo si occupa d’interpretare le
richieste contenute all’interno della pagina e scritte con un linguaggio server side e
produce una pagina HTML (HyperText Markup Language) che è rimandata al client.
Il browser da solo non è in grado d’interpretare una pagina scritta in linguaggio server side
ma solo e soltanto puro HTML, con qualche eccezione.
Al contrario, non esiste un modo per il server d’interagire con il browser, ad esempio non
c’è modo per il server di accorgersi che l’utente ha digitato qualcosa in una casella di
testo, oppure se ha ridimensionato la finestra del browser stesso.
Certo, è sempre possibile effettuare dei PostBack, inviando la pagina al server come
quando si compila il modulo e si fa clic sul pulsante Invia ma ciò richiede continui reload e
questo non è certamente possibile e accettabile in molti casi.
Basti pensare all’evento MouseMove, se ad ogni spostamento del mouse, si volesse
informare il server della nuova posizione del puntatore, la pagina sarebbe certamente
bloccata in continui PostBack e non più utilizzabile.
Per questo tipo d’interazione, esistono i linguaggi client side che sono eseguiti nel browser
dell’utente e dunque possono reagire immediatamente alle azioni del mouse.
I linguaggi utilizzati nelle applicazioni sono di due tipi.
Primo Tipo
Alcune operazioni, quali ad esempio l’accesso a DB (DataBase) o scrittura di file, è
possibile effettuarle solo avvalendosi di linguaggi di scripting server side, mentre per
l’interazioni con gli elementi della pagina è più conveniente utilizzare linguaggi client side.
Client side
Permettono d’interagire con gli elementi HTML componenti la pagina senza dover
scambiare i dati con il server.
Questo permette di ridurre i tempi di esecuzione delle istruzioni.
Sito web statico: richiede l’uso di linguaggi client side.
Il funzionamento di un sito statico è semplice: il browser richiede una pagina, il server web
la legge nel file system e la invia in risposta al browser.
 Vantaggio: non si occupano le risorse del server.
 Svantaggi: browser sempre aggiornati, problemi di compatibilità.
Server side
um 2 di 243
Applet Java
Sono classi Java che sono avviate a partire da una pagina HTML, quando il browser
incontra un TAG che richiede la visualizzazione di un’applet ne scarica il codice e lo
esegue visualizzando l’output nella finestra del documento.
Per poter eseguire le applet il browser dev’essere dotato della JVM (Java Virtual
Machine). Le applet sono utilizzate per realizzare grafica, per gestire l’interazione con
l’utente e per creare animazioni, hanno alcune limitazioni per motivi di sicurezza.
 Non possono leggere e scrivere file su disco, per non veicolare virus; possono solo
salvare informazioni sul PC da cui proviene la pagina web.
 Non possono aprire nuove connessioni di rete per stabilire collegamenti con altri PC.
Per eseguire un’applet in una pagina HTML si usa il TAG <applet>.
<applet width="128" height="128" code="prima.class"></applet>
ActiveX
Tecnologia sviluppata da Microsoft su OLE (Object Linking & Embedding) e COM
(Component Object Model), non è un linguaggio di programmazione ma un insieme di
specifiche che consentono la cooperazione tra applicazioni a livello binario, quindi un
ActiveX può essere sviluppato con diversi linguaggi.
DOM (Document Object Model)
Modellizza i documenti HTML e fornisce un’interfaccia di programmazione per accedere,
navigare e manipolare le pagine.
JavaScript/TypeScript
Server side
Sono interpretati dal server che esegue le istruzioni e presenta i dati.
È compito del programmatore manipolare i dati dinamici e presentarli sotto forma di codice
HTML.
Sito web dinamico: richiede l’uso di linguaggi server side.
Si utilizza codice di programmazione all’interno di una pagina HTML nei punti in cui si
desidera interagire con l’utente, con le fonti dati o con il sistema per stabilire cosa sarà
mostrato al client.
Il compito del server in questo contesto è quello di fornire al client la pagina indicata nella
request previa esecuzione, sul server, del codice di scripting.
 Vantaggio: non dipendono dal browser che li richiama, di conseguenza, il codice server
side è del tutto invisibile al client che accede soltanto all’output dello script, in pratica la
pagina generata dalla sua esecuzione.
 Svantaggi: server potente.
CGI (Common Gateway Interface)
ISAPI (Internet Server Application Programming Interface)
Nel periodo iniziale d’Internet le applicazioni web erano implementate con programmi
scritti in C o PERL (Practical Extraction and Report Language) che si appoggiavano ad
un’API (Application Programming Interface) dei server web, la CGI o ISAPI che
richiedevano l’avvio di una nuova istanza di un’applicazione ogni volta che si doveva
elaborare una richiesta: rischi per la sicurezza.
Un browser può, così, inviare una richiesta ad un server il quale, invece di rispondere con
una pagina statica, può eseguire uno script e inviare un flusso di dati HTML creato al
momento.
Nel server web, al di sotto della radice del sito, esiste una cartella di nome CGI-BIN, i file
Server side
um 3 di 243
presenti sono di tipo eseguibile, per esempio EXE.
Lo svantaggio di queste tecnologie risiede nella difficoltà di realizzazione e di gestione
delle applicazioni, perché le applicazioni CGI non sono integrate nei file HTML e
richiedono conoscenze e un processo di sviluppo completamente diversi da quelli
necessari per realizzare pagine HTML.
Inoltre, trattandosi di tecnologie che si basano interamente sul server, il carico su
quest’ultimo aumenta, portando ad un progressivo degrado delle prestazioni.
Servlet Java
Il codice Java non è più eseguito nel browser dei client come nel caso delle applet ma è
eseguito su una JVM residente su un server.
Bisogna separare la business logic dall’UI (User Interface).
JSP
Permette d’includere codice Java direttamente nelle pagine web e supporta componenti
chiamati JavaBeans che nascondono funzionalià complesse al di là di un’interfaccia
semplice.
AJAX (Asynchronous JavaScript And XML [eXtensible Markup Language])
È la tecnologia che sfrutta le capacità dei browser di “capire” l’XML per creare applicazioni
web dinamiche, per esempio permette d’inserire dinamicamente dati all’interno di elementi
della pagina, prelevandoli da origini esterne.
AJAX non è né un nuovo linguaggio di programmazione né una nuova piattaforma
tecnologica per lo sviluppo web, è soltanto il nome di una particolare maniera di usare
insieme una serie di tecnologie web: JavaScript, HTML, CSS (Cascading Style Sheets) e
XML, miscelandole però in una maniera nuova.
ASP.NET
Scripting server side in IIS, possibilità di scrivere le applicazioni usando qualunque
linguaggio di Visual Studio e altri.
PERL
Le estensioni di ActiveState che interpretano PERLScript.
PHP
Il modulo per Apache che implementa il linguaggio PHP.
ColdFusion
Di Macromedia, prima soluzione commerciale.
Secondo tipo
Sono orientati ai componenti.
EJB (Enterprise JavaBeans)
COM+
CORBA (Common Object Request Broker Architecture)
È la specifica di un’architettura standard per ORB, ovvero intermediari di richieste a
oggetti.
.NET Framework
Tecnologia Microsoft per sviluppare applicazioni distribuite in rete tramite server web,
centrate sul server e indipendenti dal browser.
Server side
um 4 di 243
Web Service
Sono componenti S/W in rete in grado di fornire dati e servizi ad altre applicazioni.
CMS (Content Management System)
Applicazioni che organizzano, gestiscono e pubblicano contenuti web.
Anche se è più facile sviluppare e installare siti dinamici con i server basati su tecniche di
scripting, i sistemi di questo tipo uniscono il codice usato per la visualizzazione della
pagina, la presentation logic, con quello che implementa, invece, la business logic che
normalmente preleva o inserisce in un DB le informazioni opportune.
Ciò dà origine a codice molto contorto e a volte impossibile da aggiornare e mantenere in
efficienza.
I server applicativi di fascia più elevata usano, invece, un modello di sviluppo orientato ai
componenti che separa la business logic dalla presentation logic.
Questa divisione in compartimenti consente ai programmatori di ristrutturare rapidamente
anche i siti di più grandi dimensioni: si possono, infatti, aggiungere nuovi componenti ogni
qualvolta se ne presenta la necessità e non è necessario ricostruire l’intero sistema.
I server applicativi sono affidabili, supporto per il clustering, il carico di lavoro è ripartito tra
più macchine e scalabili, gestiscono un aumento del carico.
In molti casi è opportuno che il server s’interfacci con il server di directory aziendale, di
solito basato su LDAP (Lightweight Directory Access Protocol) o su Active Directory di
Microsoft.
Esistono due tipi di applicazioni web.
1. SERVER BASED WEB APPLICATION
Un’applicazione web interagisce con i dati mediante tecnologia server side.
Il client, browser, si limita a richiedere una determinata pagina ma il vero lavoro è svolto
dal server.
1. Interpreta i parametri passati dal client con l’URL (Universal Resource Locator), GET o
con una form, POST.
2. Compie le azioni associate ai parametri.
3. Recupera i dati dal DB.
4. Formatta i dati in HTML dinamicamente.
5. Restituisce i dati già formattati al client.
In pratica, sia il back end sia il front end dell’applicazione sono demandati al server.
Limitazioni: il server è uno, i client sono molti.
Quindi, più sono i client, più sono le risorse richieste al server che deve fare tutto il lavoro.
In questi casi, all’aumentare degli utenti dell’applicazione web si può far fronte solo in un
Server side
um 5 di 243
modo: aumentare connettività e potenza del server.
Il rapporto tra l’utente di un’applicazione web e il server che la ospita è soltanto di tipo
sincrono, perché ogni operazione, prima di cominciare, attende il completamento di quella
che la precede: all’inizio è il server che resta fermo in attesa del client; poi tocca al client
aspettare, visto che dopo aver premuto il tasto INVIO non si può fare altro che attendere
l’esito dell’elaborazione.
2. CLIENT BASED WEB APPLICATION
Chiede al server web una risorsa ASP, JSP, JPG (Joint Photographic Group), una pagina
HTML; il client indica la risorsa voluta attraverso l’URL, il browser prepara la richiesta
secondo le regole del protocollo HTTP (HyperText Transfer Protocol).
Se l’URL contiene www.miosito.it, il browser chiede allo strato rete di risolverlo al fine di
ottenere l’equivalente indirizzo IP.
Il browser inoltra al server web la richiesta formulata precedentemente, per farlo si
appoggia sullo strato di rete, il TCP/IP (Transmission Control Protocol/Internet Protocol).
Se individuato, il server web recepisce la richiesta ed effettua quanto chiesto; per farlo
potrebbe anche fare cose molto complesse: per esempio, accedere ad un DB; prepara la
risposta, codice HTML e lo rimanda indietro al browser che ne ha fatto richiesta.
Anche la risposta è codificata secondo le regole del protocollo HTTP, il browser, una volta
ottenuta la risposta, provvede ad elaborarla facendo il rendering del codice HTML.
Non è rilevante la piattaforma H/W e/o SW su cui gira il browser.
I browser non sono solo viewer di documenti HTML ma sono in grado di aprire immagini,
file TXT, XML, documenti Word e PDF (Portable Document Format).
Per gli altri formati si appoggiano su plugin, per esempio SWF (ShockWave Flash).
Supportano l’interazione del codice JavaScript con gli oggetti HTML.
I browser, con il supporto di JavaScript, la possibilità d’interagire con il DOM di HTML e le
capacità di accedere a dati, sono diventati un soggetto attivo dell’applicazione web, un
vero e proprio front end dell’applicazione.
Questa funzionalità permette di manipolare la pagina attraverso il DOM, modificandone di
volta in volta solo singole parti: è lo scambio “asincrono”, evitando il modello di PostBack
dove la pagina è aggiornata nella sua totalità.
Ciò ha portato a progettare applicazioni che lasciano al server le operazioni di back end e
demandano al browser la costruzione dell’UI e le altre operazioni client.
In un flusso di questo tipo si nota.
1. Il client richiede al server dei dati.
2. Il server recupera i dati e li restituisce in formato XML.
3. Il client elabora questi dati e li utilizza per costruire dinamicamente l’UI.
I benefici che si ottengono sono di due tipi.
1. Si alleggerisce il carico del server esimendolo dal dover costruire la pagina HTML e
Server side
um 6 di 243
quindi risparmiando banda e risorse server.
2. Si possono compiere diverse operazioni anche senza ricaricare l’intera pagina ma
richiedendo solo i dati che servono.
In AJAX queste operazioni sono svolte in maniera asincrona, sfruttando una particolare
funzionalità di JavaScript, è possibile fare in modo che non ci sia sempre bisogno di
caricare nuove pagine all’interno del browser del visitatore.
Il dialogo con il server, infatti, può anche avvenire in sottofondo.
Il documento HTML caricato la prima volta è modificato di continuo, per interagire con
l’utente e mostrargli nuove informazioni.
Le Client Based Web Applications si basano su due pilastri fondamentali.
1. Server side
L’attività di programmazione è veramente minimale, si tratta di fornire al client i dati nel
formato richiesto, generalmente XML.
Il client richiede, ad esempio, i dati di una tabella, nel sito ci sarà una pagina ASP.NET,
PHP o altro che di occupa di leggere i dati dal DB e restituirli nel formato richiesto; ma se
XML è il formato di elezione per questo tipo di colloqui, la tecnologia server side che
“parla” in XML è il web service, oltretutto, utilizzandolo si ha anche il vantaggio di poter
riutilizzare le stesse funzioni di accesso ai dati anche con applicazioni desktop.
2. Client side
Come richiamare e utilizzare i dati con il client e quindi con JavaScript.
Il fulcro della tecnologia è rappresentato da due oggetti.
1. XMLHttpRequest: si occupa di recuperare i dati da un’URL con i metodi GET o POST.
2. XMLDOMParser: si occupa di leggere un documento XML.
MODELLI DI PRESENTAZIONE E DI PROGRAMMAZIONE
In una programmazione in stile classico si è abituati a considerare l’elaborazione, l’output
della pagina HTML, come una parte della definizione del codice di scripting.
Questo ha lo svantaggio d’impedire ad un web designer di lavorare separatamente dal
programmatore.
La sintassi HTML con dei TAG protetti dalle ({}) è gestita anche da chi non ha conoscenza
di tecniche di scripting, utilizzando questa tecnica programmatore e web designer possono
lavorare in modo separato.
Le tecnologie di sviluppo su browser sono CSS/DHTML (Dynamic HTML) nel modello di
presentazione e JavaScript/AJAX/ASP.NET nel modello di sviluppo.
Sul desktop, XAML (eXtensible Application Markup Language) fornisce il modello di
presentazione e il .NET Framework fornisce il modello di sviluppo.
Vi è una sovrapposizione tra queste ed è qui che il browser dotato di Silverlight fornisce il
seguente approccio: “il meglio di entrambi i mondi”.
Server side
um 7 di 243
Microsoft Silverlight
Permette di progettare applicazioni web con la stessa qualità delle applicazioni desktop,
colmando il gap tecnologico tra programmatori e web designer fornendo loro un formato
comune, XAML, con cui lavorare.
L’applicazione può essere progettata come XAML e siccome XAML è un linguaggio
basato su XML e poiché XML è solamente testo, l’applicazione è firewall compatibile e
accessibile ai motori di ricerca.
Il browser riceve il markup XAML e lo visualizza, se combinato con una tecnologia come
AJAX, JavaScript e il .NET Framework: questo processo può essere dinamico.
L’architettura di un’applicazione in esecuzione sul browser è la seguente.
Server side
um 8 di 243
SERVER DB
Introduzione
Quello di rendere accessibili i dati da qualunque parte del mondo in cui ci si trovi è il sogno
di tutti i programmatori ma il compito è sempre risultato improbo.
Problemi di compatibilità tra protocolli e problemi di sicurezza non trascurabili hanno
sempre tarpato le ali a progetti di fruibilità diretta dei dati attraverso un qualsiasi canale.
Con l’avvento d’Internet, il protocollo HTTP si è imposto come standard e insieme a
questo protocollo sono nati anche i server web.
Non si può connettere il browser di un utente web remoto direttamente ad un sistema DB,
anche se ci sono eccezioni a questo, le AppletJava ma nella maggioranza dei casi il
browser dialoga con un’applicazione che gira su un server web che ha funzioni
d’intermediario rispetto al DB.
Quest’applicazione può essere uno script CGI, una servlet Java o una parte di codice che
sta all’interno di un documento ASP.NET o JSP.
L’utente non sa se la pagina è un documento HTML ordinario oppure l’output di un
qualche script che genera l’HTML.
A seconda del tipo di tecnologia che si usa ci sono quattro possibilità.
1. Chiamata ad una pagina PHP: è la soluzione migliore, si può far ritornare alla pagina
un documento XML con le informazioni che servono.
2. Chiamata ad un web service ASP.NET: è la soluzione più semplice.
3. Espressione regolare sulla pagina web: è la soluzione più costosa ma anche la più
instabile, infatti è frequente che le pagine di risultati siano aggiornate sia nel markup
sia nei CSS, inclusi i nomi delle classi, questo significa modificare l’espressione
regolare ad ogni cambio pagina e aggiornare in qualche modo il prodotto distribuito;
inoltre, bisogna anche tener conto del fatto che se si mette la regexpr in un file di
configurazione, un utente potrebbe provare a modificarla.
4. Utilizzare le API del servizio: è la soluzione ottimale, significa interfacciarsi alle API e
richiamarle secondo gli schemi forniti.
L’architettura web/DB si sviluppa verso diverse direzioni.
Soluzione Open Source
LAMP (Linux AMP* si può sostituire con PERL, Python o PHP).
WAMP (Windows AMP*).
Soluzione Microsoft
ASP.NET e ADO.NET.
query SQL
L’esecuzione di una query è una delle attività più importanti per un DB.
Ogni richiesta da parte di un utente che implichi l’interazione con il DB dà il via ad una
query.
1. L’utente compila un form per ricercare in una libreria online i libri scritti da un certo
autore.
2. Ricevuta la richiesta da Internet, un’applicazione sul server estrae i campi del modulo
per costruire una query che è inviata al DB tramite un driver.
3. Una volta ricevuta la query dal server, il DB può applicare svariate tecniche di
ottimizzazione delle prestazioni per recuperare rapidamente i dati richiesti: un indice
organizzato come struttura gerarchica ad albero, tecnica di parallelismo intraquery che
sfrutta più di una CPU per eseguire una singola query, query rewrites, analizzano le
Server side
um 9 di 243
query in arrivo e le riscrivono dinamicamente usando tecniche avanzate.
4. La query è elaborata.
5. Il DB restituisce i risultati della query al server che li riformatta e l’inserisce in una
pagina HTML che poi invia all’utente.
Rendere sicure le applicazioni web
Gli attacchi DOS (Denial Of Service) approfittano del fatto che i router, sprovvisti di
adeguate misure di filtraggio, trasmettono il traffico dati senza controllare adeguatamente
l’indirizzo IP di provenienza, quello di destinazioni o la tipologia dei dati trasmessi.
I socket sono un’API standard che i programmatori usano per stabilire connessioni
Internet.
Un socket standard collega un’applicazione allo strato IP del SO (Sistema Operativo)
tramite il livello di protocollo TCP o UDP (User Datagram Protocol) che predispone i dati in
un formato standard e crea gli opportuni pacchetti di controllo.
I raw socket a tutti gli effetti mettono a disposizione una backdoor per l’accesso diretto al
sistema di rete sottostante, consentendo ai programmatori di creare pacchetti e protocolli
a loro piacimento.
Un’applicazione dannosa potrebbe usare i raw socket per impersonare l’indirizzo di
un’altra macchina, in modo che non sia possibile risalire all’indirizzo effettivo del PC che
sta generando i dati, raw socket sono stati implementati in origine nel SO Unix, dove
risultano accessibili solo alle applicazioni che lavorano con i privilegi di root.
Quando un malintenzionato prende di mira un’applicazione web, generalmente si pone
quattro domande.
1. Posso vedere ciò che gli utenti stanno guardando?
Il metodo per prevenire che altri possano leggere i dati in transito è la cifratura della
connessione fra un sito e i suoi utenti.
2. Posso impersonare un utente?
Come fa un sito web a riconoscere i propri utenti?
La maggior parte dei server web supporta due schemi di autenticazione tramite password.
1. Semplice da implementare ma anche meno sicuro.
2. Robusto, basato sul cosiddetto digest.
Entrambi gli schemi operano mandando una “sfida” al browser: quando il browser la riceve
per la prima volta, fa comparire una finestra di dialogo che richiede il nome utente e la
password.
Usando il metodo di autenticazione più semplice il browser trasmette al server il nome
utente la password sotto forma di testo semplice e in chiaro, in altre parole non cifrato.
Con il secondo metodo di autenticazione il browser trasmette, invece, un particolare testo
cifrato, detto appunto digest, ottenuto a partire dal nome utente e dalla password.
In entrambi i casi il server verifica i dati ricevuti e, se sono corretti, risponde con un
messaggio di approvazione; il browser a sua volta memorizza in cache le informazioni di
logon per tutta la sessione di lavoro in modo che l’utente non debba reinserirle ad ogni
pagina visitata.
Il primo problema riguarda ancora lo spionaggio dei dati in transito: se gli utenti mandano il
nome utente e password in chiaro, un attaccante può catturarli.
Questo problema può essere risolto in modo semplice trasmettendo informazioni
dell’utente usando l’SSL (Secure Sockets Layer).
Il codice seguente mostra come farlo.
<form action = "https://foo.com/login.asp" method = "post ">
User ID:<input type = "text" name = "user">
<br>Password:<input type = "password" name = "password">
Server side
um 10 di 243
<br><input type = "submit" value = "Login">
</form>
Non potendo spiare le comunicazioni, è possibile impersonare un utente.
Il punto debole che rende questo possibile è proprio lo stesso utente.
La maggior parte dei navigatori del web scelgono password non sicure e, ancora peggio,
tendono a usare la stessa coppia nome utente/password per tutti siti che richiedono una
procedura di logon.
3. Posso impersonare il gestore del sito?
Non c’è connessione permanente fra il browser e il server: è stabilita una connessione
separata per ogni pagina richiesta.
Come fa quindi un server web a verificare le credenziali dell’utente dopo il logon iniziale?
Il browser memorizza il nome utente e la password per tutto il tempo in cui la propria
finestra rimane aperta e li ritrasmette al server ogni volta che si ricollega ad esso.
Il server quindi confronta ogni volta le informazioni ricevute con quelle presenti nel suo DB
degli utenti e consente o nega l’accesso a seconda che esista o meno una
corrispondenza.
Il DNS (Domain Name System) è un anello vulnerabile della catena della sicurezza: se un
malintenzionato riuscisse ad accedere al server DNS e ne modificasse i registri facendo in
modo da farli puntare a uno dei propri PC invece che a quelli legittimi, tale PC potrebbe
poi reindirizzare tutte le richieste HTTPS (Hypertext Transfer Protocol over Secure Socket
Layer).
Dato che durante il reindirizzamento il browser mostra di default la parte finale
dell’indirizzo, se quest’ultimo è abbastanza lungo da mettere la porzione fuori dal campo di
vista, la maggior parte degli utenti non noteranno di essere collegati ad un sito dal nome
diverso da quello desiderato.
Se il gestore ottenesse poi un certificato digitale, il browser indicherebbe una connessione
del tutto lecita e non darebbe alcun messaggio di avviso.
Solo facendo clic sull’icona a forma di lucchetto per visionare i dettagli del certificato
digitale l’utente potrebbe rendersi conto dell’inganno.
Dato che è molto facile costruire una pagina web identica a un’altra, il malintenzionato a
questo punto potrebbe realizzare una schermata di accesso simile in tutto e per tutto e
usarla per catturare nomi utente e password, inserite dai visitatori ignari di essere collegati
a un sito di un pirata informatico.
4. Posso usare i PC del sito per eseguire i miei comandi?
Un tipo di attacco molto noto è quello del buffer overflow, letteralmente tracimazione del
buffer che prevede l’invio di una quantità eccessiva di dati al server.
Il seguente codice C è vulnerabile ad un attacco di buffer overflow perché non controlla se
i dati in arrivo superano il limite previsto di 255 caratteri.
void prova(char*pszData)
{ char szBuffer [255 ];
strcpy(szBuffer,pszData );
}
Cosa accade se la funzione strcpy provoca un overflow del buffer basato su stack?
La figura mostra l’aspetto dello stack delle chiamate di sistema dopo che è stata eseguita
la funzione prova: lo stack cresce a partire dalla parte alta della memoria e il buffer si
riempie dal fondo della memoria.
Scrivendo troppi dati all’interno del buffer, un attaccante può arrivare a sovrascrivere il
cosiddetto function call record: si tratta di una struttura di dati che contiene i valori del
registro salvati dal codice della funzione insieme con l’indirizzo di ritorno della funzione
Server side
um 11 di 243
stessa.
Sovrascrivendo quest’ultimo con un altro valore diventa possibile mandare in esecuzione
sul PC attaccato un’applicazione a piacere.
Un pirata informatico naturalmente vorrà mandare in esecuzione il codice da lui stesso
caricato sul sistema ma come può riuscire ad introdurlo sul PC attaccato?
Scrivendolo nel buffer dei dati.
Gli hacker sanno che le funzioni vulnerabili, come quella appena mostrata, sono di solito
richiamate dal codice che elabora l’input dell’utente.
Di conseguenza provano a mandare stringhe d’input lunghissime al server e stanno a
vedere che cosa succede.
Come si può evitare che un’applicazione web sia sfruttata illecitamente?
Bisogna cercare tutto il codice esistente che è stato scritto usando linguaggi che
permettono un accesso diretto alla memoria, come il C, il C++ ed esaminarlo per trovare
eventuali vulnerabilità, per esempio errori di buffer overflow.
Si può evitare completamente il problema usando linguaggi di programmazione che non
consentono accesso diretto alla memoria.
Per esempio meccanismi di scripting come JavaScript e PERL.
Linguaggi interpretati come Java.
Sono altrettanto sicuri i linguaggi della piattaforma .NET, il Visual C# e il Visual Basic.
Server side
um 12 di 243
SERVER Web
INTRODUZIONE
È un S/W residente sul server, più precisamente un processo che gira in background, un
servizio, in grado di evadere richieste HTTP.
I server web sono tipicamente multitask/multithread e quindi in grado di evadere più
richieste contemporaneamente e possono gestire diversi domini.
Inoltre, bisogna determinare quanti browser possono avere accesso al sito
contemporaneamente e con quale velocità otterranno risposta.
All’avvio apre un socket TCP/IP sulla porta 80 (default), sul quale rimane in ascolto delle
richieste dei browser, i server web sono chiamati a svolgere una varietà di ruoli che vanno
oltre la semplice fornitura ai browser di pagine e immagini.
Il lavoro essenziale svolto da un server web è semplice: accetta la richiesta di un agente, il
browser, determina se concedere o meno l’accesso all’elemento desiderato e poi
risponde, a seconda dei casi, inviando un file che risiede nel file system, passando la
richiesta stessa a una routine per la generazione di codice dinamico o restituendo un
messaggio di errore.
I server web sono in grado d’interpretare linguaggi server side in modo da rendere la
pagina web dinamica nel contenuto.
Architettura
Modello Forked
Usa un processo dedicato d’I/O per ogni richiesta di connessione.
Pone, però, un grosso carico sulle risorse del sistema e ha un limite prefissato sul numero
di connessioni per porta.
Modello Select
Chiamato anche modello Event-Driven, azionato dagli eventi, usa un sistema d’I/O non
bloccante nel quale un piccolo numero di processi a thread unico sfruttano la chiamata di
sistema SELECT per gestire un gran numero di connessioni.
Modello Multithread
Ogni processo sfrutta un pool di thread di esecuzione.
Per conservare le risorse del sistema, un algoritmo specializzato distribuisce il tempo di
elaborazione della CPU tra i vari thread.
Il modello d’implementazione del multithreading nel SO usato influisce sulle prestazioni,
usato da IIS.
Il web non conosce orari di chiusura!
Come fare, allora, per tenere aperte le porte virtuali del sito 24 ore al giorno per 7 giorni la
settimana?
La risposta è nei sistemi ad alta disponibilità che si avvicinano al 100% di uptime.
I principi dell’alta disponibilità definiscono livelli precisi di backup e di recovery.
Fino a poco tempo addietro, l’alta disponibilità implicava semplicemente la capacità di
recupero H/W e/o S/W tramite la tecnologia RAID (Redundant Array of Indipendent Disks)
che permette di ottenere una condizione di fault tolerance per i dati ma non risolve il
problema nel caso di un collasso completo del DB.
Per raggiungere un uptime superiore, gli amministratori di DB usano il clustering che
opera associando server che hanno la capacità di condividere un gruppo di unità disco.
Server side
um 13 di 243
Ogni nodo ha nel suo cluster un nodo di backup.
In caso di guasto del nodo uno, il nodo due è in grado di subentrare istantaneamente
prendendosi carico delle risorse, della logica e delle funzioni transazionali del DB in avaria.
Un vantaggio aggiuntivo del clustering è che i nodi non devono necessariamente risiedere
nello stesso luogo ma possono essere distanti anche numerosi chilometri tramite
connessioni in fibra ottica.
Le tecnologie di clustering sono costose, una soluzione alternativa e molto efficace dal
punto di vista economico è quella del log shipping, spedizione dei log che prevede la
sincronizzazione di DB separati tramite l’invio dei log delle transazioni da un server
all’altro.
In caso di guasto, si possono usare i log per ripristinare la situazione fino al momento
dell’avaria.
Altri sistemi prevedono le copie snapshot dei DB, “istantanee” effettuate in momenti
prestabiliti o l’uso di tecnologie di replica.
Come lavora un server.
Server side
um 14 di 243
IIS
IIS 6.0
Architettura a struttura monolitica.
IIS 7.0
Architettura a struttura modulare.
Server side
um 15 di 243
IIS 7.0 utilizza lo stesso processo per diverse request.
FTP: permette FTPS over SSL da non confondere con SFTP over SSH (Secure SHell).
Media Services: gestione contenuti multimediali senza Windows Media Server.
Installazione
IIS comprende il server web, FTP, NNTP (Network News Transfer Protocol) e SMTP solo
per l’invio di posta.
È possibile installare IIS, nonché aggiungere o rimuovere componenti facoltativi di IIS.
Prima d’installare IIS, è necessario installare le utilità Windows per la connettività, il
protocollo TCP/IP, il servizio DNS e le estensioni web per creare e modificare pagine
HTML per il sito web.
1. Start/Pannello di controllo/Programmi/Programmi e funzionalità.
2. Fare clic su Attivazione o disattivazione delle funzionalità di Windows, è
visualizzata la finestra Funzionalità Windows.
Per controllare il funzionamento del server web basta inserire nella barra degli indirizzi del
browser il seguente indirizzo.
http://localhost/iisstart.htm o http://127.0.0.1/iisstart.htm
Essendo il localhost, 127.0.0.1, il nome che identifica il server web nel PC locale.
In output compare la pagina IISSTART.HTM che conferma l’attivazione del server web, è
una home page di default che si trova nella cartella C:\INETPUB\WWWROOT.
IIS permette una gestione integrata tramite lo snapin seguente.
Start/Tutti i programmi/Strumenti di amministrazione/Gestione IIS.
Per avviare il servizio web da console, fare clic su Start/Esegui… cmd.
Server side
um 16 di 243
C:\>net start w3svc <INVIO>
Ulteriori informazioni sono disponibili con i comandi seguenti.
C:\>net helpmsg 2182<INVIO>
C:\>net start<INVIO>
Per far sì che le applicazioni siano gestite correttamente da IIS, i file che le compongono
devono essere correttamente collocati all’interno delle cartelle del server.
Il processo d’installazione crea una cartella INETPUB e, al suo interno, la sotto cartella
WWWROOT per le pagine web.
Estensioni del servizio web
È un tipo di documento o di funzionalità non statica che richiede un’elaborazione speciale.
Le estensioni che possono essere configurate su IIS includono le seguenti caratteristiche.
 ASP: controlla se possono essere usati gli script server side scritti come ASP, questa
estensione è sempre installata.
 ASP.NET: controlla se possono essere usate le applicazioni ASP.NET, questa
estensione è resa disponibile al momento dell’installazione di ASP.NET quale
componente del server applicazioni web.
 Estensioni Server BITS (Background Intelligent Transfer Service): controlla se può
essere usato il trasferimento Internet in background, questa estensione è resa
disponibile quando s’installa l’estensione BITS come componente d’IIS.
 Servizio d’indicizzazione: controlla se il contenuto del server web possa essere
indicizzato e soggetto a ricerche, questa estensione è resa disponibile quando
s’installa il servizio d’indicizzazione come componente di Microsoft Windows.
 Internet Data Connector: controlla se le pagine possono utilizzare Internet Data
Connector, questa estensione è sempre installata.
 Stampa Internet: controlla se il server può essere usato per la stampa Internet, questa
estensione è resa disponibile quando s’installa Stampa Internet come componente
d’IIS. SSI (Server Side Includes): controlla se le pagine possono utilizzare le SSI,
questa estensione è sempre installata.
 WebDAV (Web Distributed Authoring and Versioning): controlla se le pagine possono
utilizzare WebDAV, questa estensione è sempre installata.
Server side
um 17 di 243
Configurazione
Nel file MACHINE.CONFIG sono impostati i parametri relativi a tutto il server su cui sono
in esecuzione i siti web.
Nel file WEB.CONFIG è specificata l’intera configurazione di un sito ASP.NET, dalle
stringhe di connessione fino alle impostazioni di protezione delle risorse.
La sezione <system.webServer> ospita tutte le configurazioni dell’applicazione, trovano
posto tutte le impostazioni che potrebbero essere fatte attraverso la console di gestione
d’IIS che in effetti ora scrive direttamente dentro il file APPLICATIONHOSTING.CONFIG.
All’interno di questo file sono definite le policy globali, così come eventuali application
pool, siti web e impostazioni di quest’ultimo.
Ovviamente il livello cui sono applicati è il medesimo: eventuali impostazioni locali
sovrascrivono quelle dell’APPLICATIONHOSTING.CONFIG.
Il vantaggio di questo approccio basato sulla possibilità di stabilire le impostazioni nel
WEB.CONFIG è soprattutto nella possibilità di poter definire le impostazioni del sito
durante la fase di sviluppo e poi portarle, insieme a tutta l’applicazione, in produzione,
senza dover toccare nient’altro.
Qualsiasi configurazione, dalle pagine di errore alle estensioni personalizzate, passando
per il logging, le impostazione di security per inibire l’accesso ad alcuni IP, sono copiate
insieme al WEB.CONFIG, garantendo dunque che non sia necessario, quando si sposta
un sito, ripeterle tutte.
È un vantaggio, in questo modo è possibile trasferire un sito copiandolo, piuttosto che un
intero server web, per avere meccanismi di fault tolerance facili da applicare.
Esempio, rimuovere il supporto per le CGI.
<configuration>
<system.webServer>
<serverFeatures>
<remove name="Cgi" />
</serverFeatures>
</system.webServer>
</configuration>
Essendo XML è possibile manipolarlo in qualsiasi modo.
Per evitare che il browsing delle cartelle che non hanno una pagina di default sia attivo, ad
esempio, è sufficiente inserire nel WEB.CONFIG locale al sito, oppure all’interno
dell’APPLICATIONHOSTING.CONFIG, una sezione di configurazione seguente.
<configuration>
<system.webServer>
<directoryBrowse enabled="false" />
</system.webServer>
</configuration>
Un APPLICATIONHOSTING.CONFIG che nega la visualizzazione di file ASA e MASTER,
rispettivamente necessari per il GLOBAL.ASA di ASP o le Master Page di ASP.NET.
<configuration>
<system.webServer>
<requestFiltering>
<fileExtensions allowUnlisted="true">
<add fileExtension=".asa" allowed="false" />
<add fileExtension=".master" allowed="false"/>
Server side
um 18 di 243
</fileExtensions>
</system.webServer>
</configuration>
È possibile specificare all’interno di questo file anche gli IP cui negare l’accesso.
<system.webServer>
<security>
<ipSecurity allowUnlisted="true">
<add ipAddress="192.168.10.7"
allowed="false" />
<add ipAddress="192.168.5.111"
allowed="false" />
</ipSecurity>
</security>
</system.webServer>
L’idea alla base d’IIS è quella di fornire una pipeline che integri all’interno della stessa sia
moduli managed, in pratica quelli basati su .NET Framework sia nativi, unificandola.
Questo concetto è già implementato in ASP.NET attraverso gli HttpModule.
Si tratta di classi particolari che si registrano per alcuni eventi dell’applicazione e sono
invocate per eseguire il codice associato.
IIS porta questo modello all’interno del server web stesso, con il vantaggio che un modulo
managed può fare le stesse identiche cose di uno nativo, quindi agire anche su altre
tipologie di risorse, come le pagine ASP.
IIS è distribuito già con tantissimi moduli che hanno praticamente gli usi più disparati, dalla
gestione della pagina di default agli errori, passando per l’autenticazione.
Tutti questi componenti sono registrati globalmente nell’APPLICATIONHOSTING.CONFIG
e possono essere rimossi, se la sezione è sbloccata, anche nei WEB.CONFIG locali.
C’è la possibilità di definire una pagina di errore globale, non solo per le applicazioni
ASP.NET.
<httpErrors>
<error statusCode="404" url="/errors/404.aspx"/>
</httpErrors>
È possibile tracciare l’intera vita della richiesta, così da verificare in quale punto mancano i
permessi o si verifica un errore.
Da questo punto di vista, esiste un meccanismo di tracing automatico per tutte le richieste
con errori, così come uno specifico per quelle che vanno in timeout e ci mettono troppo
tempo per completare, con un errore del tipo “takes too long”.
Grazie alla pipeline unificata gli eventi di ASP.NET e di IIS vanno a finire nello stesso trace
log, con la possibilità di accedere agli stessi nello stesso identico modo.
Per i fornitori di hosting condiviso c’è la possibilità di delegare, da parte
dell’amministratore, parte della configurazione al programmatore, in pratica la persona che
ha fisicamente accesso al WEB.CONFIG.
Ogni nodo può essere delegato e quindi modificato nel WEB.CONFIG, attraverso tre
modalità differenti.
1. L’utilizzo dell’interfaccia di amministrazione.
2. La modifica del file di configurazione.
3. La modifica di un eseguibile da riga di comando.
Nel secondo caso, è possibile modificare un nodo aggiungendo l’attributo seguente che
Server side
um 19 di 243
può assumere il valore true se questa modifica dev’essere ammessa nei CONFIG figli,
false se invece dev’essere bloccata.
<authorization allowOverride="true" />
È anche possibile specificare un’impostazione da ereditare nei CONFIG figli,
semplicemente aggiungendo l’attributo seguente.
<inheritInChildApplications = "true"/>
Operazione analoga è possibile lanciando da riga di comando.
%SYSTEMROOT%\SYSTEM32\INETSRV\APPCMD UNLOCKCONFIG
/SECTION:AUTHORIZATION
IIS nasce con l’esigenza di fornire un’architettura tale da garantire l’hosting non soltanto di
applicazioni web, infatti rappresenta un sistema generalizzato per l’attivazione di processi
e l’health monitoring degli stessi.
Il tutto è possibile grazie a WAS (Windows Activation Service), un componente che si
occupa di garantire che gli application pool girino senza problemi ed è stato esteso per
supportare un modello generico per applicazioni distribuite.
IIS ha già incluso il supporto per HTTP, NET.TCP, NET.PIPE e NET.MSMQ (MicroSoft
Message Queue).
Questo vuol dire che è in grado di far girare applicazioni HTTP e non HTTP side-by-side,
in altre parole contemporaneamente, al punto tale che ASP.NET e WAS possono
utilizzare lo stesso application domain, nello stesso worker process.
Il motivo di questa architettura è quello di favorire un ambiente nel quale gestire i servizi di
WCF (Windows Communication Foundation) per la comunicazione inter process per tipi di
applicazioni differenti.
Il vantaggio principale è che i servizi WCF possono utilizzare funzionalità esistenti in
ASP.NET, come State Service, Globalization, Membership, Roles o Profile.
Sicurezza
In IIS c’è l’utente IUSR che è disponibile direttamente all’interno del SO, si tratta di un
nuovo account con privilegi minimi.
Di default, IIS utilizza l’autenticazione anonima del processo, gira in pratica con l’account
specificato all’interno dell’APPLICATIONHOSTING.CONFIG.
<configuration>
<system.webServer>
<anonymousAuthentication enabled="true"
userName="" defaultLogonDomain="" />
</system.webServer>
</configuration>
OSPITARE PIÙ SITI WEB
Le intestazioni host, anche note come nomi di dominio o nomi host, consentono di
assegnare più siti ad un unico indirizzo IP di un server web, senza assegnare un indirizzo
IP univoco a ogni sito web o definire numeri di porta TCP non standard.
L’utilizzo d’intestazioni host rappresenta la soluzione più comune per ospitare più siti web.
Dopo aver completato i passaggi seguenti, è necessario registrare il nome o i nomi
d’intestazione host con il sistema di risoluzione dei nomi appropriato.
Se il PC si trova in una intranet, registrare il nome o i nomi d’intestazione host con il
Server side
um 20 di 243
sistema di risoluzione dei nomi dell’intranet.
Se il PC si trova in Internet, registrare il nome o i nomi d’intestazione host con DNS.
Per quanto attiene al server web i passi da seguire per la configurazione sono i seguenti.
Creare una cartella principale al cui interno s’inseriscono tante sotto cartelle ciascuna
rappresentante la root del sito web di un dominio.
Editare il file C:\WINDOWS\SYSTEM32\DRIVERS\ETC\HOSTS e associare all’indirizzo IP
di loopback i nomi di dominio specificati.
Aggiungere un sito web
Quando si aggiunge un sito web in IIS, una voce del sito è creata nel file
APPLICATIONHOST.CONFIG, specifica il binding di rete per il sito, esegue il mapping del
sito ad un percorso nel file system e, facoltativamente, specifica le credenziali utente per
l’accesso al contenuto.
1. Interfaccia utente
start/Tutti i programmi/Strumenti di amministrazione/Gestione IIS
Server side
um 21 di 243
2. Riga di comando
CUI: C:\WINDOWS\SYSTEM32\INETSRV\APPCMD.EXE
Strumento di amministrazione generico di IIS per la riga dei comandi.
APPCMD (comando) (tipo-oggetto) <identificatore> </parametro1:valore1 ...>
Tipi di oggetto supportati:
SITE
Amministrazione di siti virtuali
APP
Amministrazione di applicazioni
VDIR
Amministrazione di directory virtuali
APPPOOL Amministrazione di pool di applicazioni
CONFIG Amministrazione di sezioni di configurazione generale
WP
Amministrazione di processi di lavoro
REQUEST Amministrazione di richieste HTTP
MODULE Amministrazione di moduli del server
BACKUP Amministrazione di backup della configurazione del server
TRACE Utilizzo di registri di traccia di richieste non riuscite
(Per elencare i comandi supportati da ogni oggetto utilizzare /?, ad esempio 'ap
pcmd.exe site /?')
Parametri generali:
/?
Visualizza un messaggio della Guida sensibile al contesto.
/text[:valore] Genera l'output in formato testo (predefinito).
/text:* mostra in dettaglio tutte le proprietà degli oggetti.
/text:<attributo> mostra il valore dell'attributo
specificato per ogni oggetto.
/xml
Genera l'output in formato XML.
Usare per produrre output che può essere inviato a un altro
comando in esecuzione nella modalità /in.
/in o Legge e utilizza l'input XML da un input standard.
Usare per un input prodotto da un altro
comando in esecuzione nella modalità /xml.
/config<:*>
Mostra la configurazione per gli oggetti visualizzati.
/config:* include anche la configurazione ereditata.
/metadata
Mostra i metadati di configurazione durante la visualizzazione
della configurazione.
/commit
Imposta il percorso di configurazione quando si salvano modific
he di configurazione.
Può indicare un percorso di configurazione specifico, "site",
"app", "parent" o "url" per salvare la porzione corretta del
percorso modificato dal comando, "apphost", "webroot"
o "machine" per il livello di configurazione corrispondente.
/debug
Mostra le informazioni di debug per l'esecuzione del comando.
-Utilizzare "!" per ignorare i parametri con lo stesso nome di quelli generici,
quali ad esempio "/!debug:value" utilizzato per l'impostazione della proprietà d
i configurazione "debug".
appcmd add site /name:stringa /id:uint /physicalPath:stringa /bindings:stringa
3. WMI
Metodo Site.Create.
Configurare un binding per un sito
1. Interfaccia utente
Aprire Gestione IIS.
Nel riquadro Connessioni espandere il nodo Siti nell’albero, quindi selezionare il sito per
Server side
um 22 di 243
cui si desidera aggiungere un binding.
Nel riquadro Azioni fare clic su Binding….
Nella finestra di dialogo Binding sito fare clic su Aggiungi.
Nella finestra di dialogo Aggiungi binding sito aggiungere le informazioni sul binding,
quindi scegliere OK.
2. Riga di comando
appcmd set site /site.name:str/+bindings.[protocol='str',bindingInformation='str']
3. WMI
Metodo SSLBinding.Create.
Configurare nomi d’intestazione host per un sito
1. Interfaccia utente
Aprire Gestione IIS.
Nel riquadro Connessioni espandere il nodo Siti nell’albero, quindi selezionare il sito per
per il quale si desidera configurare un’intestazione host.
Nel riquadro Azioni fare clic su Binding….
Nella finestra di dialogo Binding sito selezionare il binding per il quale si desidera
aggiungere un’intestazione host, quindi fare clic su Modifica o su Aggiungi per
aggiungere un nuovo binding con un’intestazione host.
Nella casella Nome host: digitare un’intestazione host per il sito.
Fare clic su OK.
Per aggiungere un’ulteriore intestazione host, creare un nuovo binding con gli stessi
indirizzi IP e porta e la nuova intestazione host.
Ripetere l’operazione per ogni intestazione host in cui si desidera che siano utilizzati
l’indirizzo IP e la porta specificata.
2. Riga di comando
appcmd set site /site.name:str/bindings.[protocol='str',bindingInformation
='str'].bindingInformation:str
Server side
um 23 di 243
3. WMI
Proprietà Site.Bindings.
Proprietà BindingElement.BindingInformation.
INSTALLAZIONE DI PHP IN IIS
Può essere fatta in tre modi.
1. Filtro ISAPI: garantisce buone prestazioni nell’esecuzione degli script ma può riservare
spiacevoli sorprese in quanto a stabilità.
2. CGI: attraverso le CGI IIS è in grado di chiamare il PHP ad ogni esecuzione di script,
intercettarne l’output e inviarlo al browser; questa tecnica è stabile, fornisce però
prestazioni mediocri non sufficienti per la realizzazione di un server di produzione.
3. Fast CGI: è la migliore sia sul fronte delle prestazioni sia della stabilità.
Impostazione del PATH
Per evitare di dover spostare le librerie di PHP nelle cartelle di sistema, modificare la
variabile Path in modo che contenga il percorso alla cartella di PHP appena creata.
Aprire il Pannello di controllo, cliccare sull’icona Sistema e nella finestra che appare
selezionare la scheda Avanzate e selezionare Variabili d'ambiente.
Dall’elenco delle Variabili di sistema selezionare Path e cliccare sul tasto Modifica.
A questo punto si deve modificare il valore della variabile aggiungendo in coda la scritta
C:\EasyPHP\php5; attenzione a non dimenticare il (;).
Fatto ciò si deve riavviare Windows per far sì che la modifica effettuata abbia effetto.
Modifica del PHP.INI
Nella cartella C:\EASYPHP\PHP5 rinominare il file PHP.INI-DIST in PHP.INI, è il file di
Server side
um 24 di 243
configurazione di PHP, aprirlo con un editor di testi.
Modificare le direttive seguenti.
 cgi.force_redirect = 0
 doc_root = "C:\Inetpub\wwwroot"
 extension_dir = "C:\EasyPHP\php5\ext"
Togliere il (;) all’inizio delle direttive seguenti.
 extension=php_mbstring.dll, l’estensione mbstring è necessaria al corretto
funzionamento di phpMyAdmin con i set di caratteri multibyte.
 extension=php_gd2.dll per caricare la libreria per la manipolazione delle immagini.
 extension=php_mysql.dll.
L’estensione mysql è necessaria per l'interazione con l’omonimo DB.
Modificare il valore della direttiva session.save_path = "C:\Lavoro\Film\Temp" in modo che
punti ad una cartella di file temporanei del sistema, quindi salvare il file.
Configurazione di IIS
IIS deve usare l’interprete PHP (php-cgi.exe) per l’esecuzione dei file con estensione PHP.
Avviare Gestione IIS espandere la struttura ad albero a sinistra fino a mostrare il Default
Web Site.
Fare clic su questa icona con il tasto destro e selezionare la voce Proprietà del menu
contestuale, nella finestra che compare selezionare la scheda Home directory.
Fare clic sul pulsante Configurazione… per accedere alle impostazioni di mapping.
Per aggiungere il supporto agli script PHP si deve fare clic sul pulsante Aggiungi.
Server side
um 25 di 243
Esempio, verificare l’esito della procedura con la seguente applicazione che permette di
visualizzare i parametri di configurazione di PHP nel server in cui è eseguito il codice.
<html>
<head>
<title>PHP</title>
</head>
<body>
<?php
phpinfo();
?>
</body>
</html>
Salvare il file creato nella cartella C:\INETPUB\WWWROOT con il nome INFO.PHP e
aprire il browser al’indirizzo: http://localhost/info.php.
Server side
um 26 di 243
A volte si verificano problemi di accesso negato durante l'esecuzione di script PHP.
Questi sono riconducibili principalmente a due fattori.
1. Possono dipendere o dalle normali impostazioni sui diritti di accesso dei file in
partizioni NTFS (New Technology File System), tali problemi si risolvono agendo sulle
impostazioni di accesso di Windows relative ai file o alle cartelle coinvolte.
2. Possono essere legate alle politiche di accesso del server IIS, i permessi vanno
modificati dalla console di amministrazione di IIS.
Server side
um 27 di 243
EASYPHP
INTRODUZIONE
Sono avviati Apache e MySQL server.
Start/Tutti i programmi/EasyPHP
La prima volta che si avvia EasyPHP sarà aggiunta un’icona nell’area di notifica, fare clic
su di essa per accedere al menu.
1.
2.
3.
4.
5.
Aiuto.
File di log: riporta ogni errore generato da Apache e MySQL.
Configurazione: un’interfaccia per configurare EasyPHP.
Esplora file F8: apre la cartella C:\EASYPHP\WWW.
Amministrazione CTRL+A: apre l’URL http://127.0.0.1/home/ permette di gestire il DB
e di amministrare gli alias.
6. Sito locale F7: apre l’URL http://127.0.0.1/.
7. Riavvia F5: avvia i server Apache e MySQL.
8. Ferma F3: ferma i server Apache e MySQL.
9. Esci.
Prima di aprire Amministrazione o il Sito Locale, verificare che EASYPHP.EXE sia
avviato e che i server funzionino.
Doppio clic sull’icona di EasyPHP nell’area di notifica: gli stati di Apache e di MySQL
devono essere posizionati sul verde.
Apache nasce nel 1995 grazie al lavoro di una fondazione no profit chiamata “Apache
Software Foundation” e si diffonde in tutto il mondo per la sua affidabilità e l’elevate
Server side
um 28 di 243
performance.
Tra i moduli più utilizzati in Apache, c’è il modulo mod_rewrite che utilizza un motore di
riscrittura basato su un parser di regular expression.
Amministrazione CTRL+A: apre l’URL http://127.0.0.1/home/.
Uso della cartella WWW (World Wide Web)
Per fare in modo che lo script possa essere eseguito, assicurarsi di aver posizionato il file
della cartella WWW.
Il server Apache è configurato automaticamente per aprire un file di nome INDEX.HTML,
quando è digitato l’indirizzo http://127.0.0.1.
Questa è per definizione la pagina di partenza e verifica che EasyPHP è in esecuzione.
È consigliabile creare una cartella per ciascun progetto all’interno della cartella WWW, in
questo modo diviene più semplice gestire diversi progetti.
Esempio, visualizzare la data corrente nel file DATA.PHP.
<html>
<head>
<title>PHP</title>
</head>
<body>
Data Corrente:
<?php
print (Date("l F d, Y"));
?>
Server side
um 29 di 243
</body>
</html>
Creare una nuova cartella all’interno di WWW oppure utilizzare la cartella creata durante
l’installazione: PROJET1.
Salvare la pagina contenente lo script PHP in una delle seguenti estensioni: PHP, PHP3,
PHP e PHP5, queste estensioni sono state settate da EasyPHP.
Le estensioni possono cambiare con la società che offre l’hosting: ricordare di cambiare le
estensioni se necessario.
Azioni da evitare.
Cercare di lanciare lo script facendo doppio clic sul file all’interno della cartella del
progetto: questo genera una pagina di errore.
Azioni corrette.
Lanciare EasyPHP, connettersi tramite il browser a http://127.0.0.1, aprire la cartella del
progetto, quindi cliccare su DATA.PHP.
A questo punto si deve vedere la pagina correttamente interpretata dal server Apache.
PROGRAMMARE IN .NET UTILIZZANDO APACHE
Installare il modulo seguente: MOD_ASPDOTNET-2.0.0.MSI.
Creare una cartella, al di fuori della root di Apache, da usare come contenitore per le
applicazioni ASP.NET, per esempio F:\STORE.
File HTTPD.CONF
Aggiungere le righe seguenti.
LoadModule aspdotnet_module modules/mod_aspdotnet.so
AddHandler asp.net asax ascx ashx asmx aspx axd config cs csproj\licx rem resources
resx soap vb vbproj vsdisco webinfo
Eseguire il mount di una cartella virtuale di Apache su quella fisica creata in precedenza.
AspNetMount /Store"F:/Store"
Creare un alias per la cartella creata.
Alias /Store "F:/Store"
Garantire i permessi di esecuzione alla cartella creata.
<Directory "F:/Store">
Options FollowSymlinks ExecCGI Order allow,deny Allow from all DirectoryIndex
Default.htm Default.aspx
</Directory>
Mappare tutte le richieste delle pagine ASP.NET verso il framework.
AliasMatch/aspnet_client/system_web/(\d+)_(\d+)_(\d+)_(\d+)/(.*) \
"C:/Windows/Microsoft.NET/Framework/v$1.$2.$3/ASP.NETClientFiles/$4"
<Directory \"C:/Windows/Microsoft.NET/Framework/ v*/ ASP.NETClientFiles">
Options FollowSymlinks Order allow,deny Allow from all
</Directory>
Server side
um 30 di 243
XAMPP
INTRODUZIONE
È un acronimo con cui s’indica una piattaforma di sviluppo web/DB che prende il nome
dalle iniziali dei componenti S/W con cui è realizzata.
 X significa cross-platform.
 Apache.
 MySQL.
 PHP.
 PERL.
È una distribuzione “tutto-compreso”, in altre parole s’installa e si configura il server web di
Apache, l’interprete PHP, il DBMS MySQL.
Programmatore: Kai ‘Oswald’ Seidler - Kay Vogelgesang.
Mette a disposizione un pannello di controllo per l’avvio dei componenti configurati.
Server side
um 31 di 243
Configurare Eclipse come ambiente di programmazione
Bisogna installare il plugin PHPEclipse.
Non appena l’installazione è terminata, PHPEclipse dev’essere configurato per agganciare
gli strumenti configurati da XAMPP.
Fare clic su Window/Preferences, per aprire la maschera di configurazione di Eclipse e
specificare il percorso d’installazione di XAMPP.
Server side
um 32 di 243
Eclipse è dotato ora di una nuova prospettiva, per selezionarla fare clic su Window/Open
Perspective/Other…/PHP.
Per create un progetto, fare clic su File/New (ALT+MAIUSC+N)/Project…
Una volta creato, il progetto può essere amministrato nella vista Navigator.
File TEST.PHP
<html>
<head>
<title>Test</title>
</head>
<body>
<?php
for ($i = 0; $i < 10; $i++) {
echo ($i +"<br />");
}
?>
<body>
</html>
Server side
um 33 di 243
Selezionare il nome del progetto e dal menu contestuale la voce Properties.
Nella finestra selezionare PHP Project Settings e nel campo Project URI: inserire la
stringa seguente http://localhost/test e fare clic su OK.
Server side
um 34 di 243
La pagina PHP dev’essere eseguita con Apache, selezionare il nome del progetto e dal
menu contestuale la voce Export….
Nella finestra selezionare General/File System e premere Next.
I file vanno esportati all’intero della cartella HTDOCS di XAMPP.
Server side
um 35 di 243
Selezionare il file TEST.PHP e dal menu contestuale la voce PHP Browser.
Al centro di Eclipse è aperta una scheda con un browser puntato sull’indirizzo della
pagina.
Server side
um 36 di 243
TOMCAT
INTRODUZIONE
Procurarsi l’eseguibile d’installazione rilasciato da Apache dal sito del progetto Jakarta.
Tomcat richiede che sia installato sul sistema il JRE (Java Runtime Enviroment).
Indicare il pathname, fare clic su Start/Pannello di controllo/Prestazioni e
manutenzione/Sistema.
Nella finestra Proprietà del sistema fare clic sulla scheda Avanzate e Variabili
d’ambiente.
Tomcat rappresenta l’implementazione delle tecnologie Java Servlet e JSP.
Crea l’ambiente all’interno del quale le servlet e le pagine JSP sono eseguite.
Il server engine s’integra con IIS e Apache ed estende le loro funzionalità per l’esecuzione
delle servlet.
Il server Tomcat è associato alla porta 8080, questo significa che può funzionare anche se
è attivo IIS o Apache.
Per avviare il server, lanciare il comando seguente da console.
C:\Tomcat\jakarta-tomcat\bin\startup.bat<INVIO>
Server side
um 37 di 243
Per controllare il funzionamento del server basta inserire nella barra degli indirizzi del
browser l’indirizzo seguente.
http://localhost:8080 o http://127.0.0.1:8080
Essendo il localhost, 127.0.0.1, il nome che identifica il server nel PC locale.
È aperta la pagina iniziale del server Tomcat.
1. Administration
1.1. Status
1.2. Tomcat Manager: gestisce le applicazioni create tramite il browser.
2. Documentation
2.1. Release Notes
2.2. Change Log
2.3. Tomcat Documentation
3. Tomcat Online
4. Miscellaneous
4.1. Servlets Examples
4.2. JSP Examples
Tomcat è soprattutto un AS (Application Server) che consente di utilizzare la tecnica delle
servlet o delle JSP per creare applicazioni web con il linguaggio Java a fare da asse
portante.
È anche un server web ma quel che più conta è un container di applicazioni Java.
Per arrestare il server, lanciare il comando seguente da console.
C:\Tomcat\jakarta-tomcat\bin\shutdown.bat<INVIO>
Per far sì che le applicazioni siano gestite correttamente da Tomcat, i file che le
compongono devono essere correttamente collocati all’interno delle cartelle del server.
La cartella che contiene le applicazioni è la seguente.
C:\EASYPHP\APACHE\APACHE-TOMCAT-6.0.18\WEBAPPS\ROOT.
All’interno della ROOT ci saranno tutti i file che compongono l’applicazione, file HTML,
pagine JSP, immagini, suoni, opportunamente distribuiti in cartelle per una più facile
Server side
um 38 di 243
gestione.
Particolare importanza ricopre la cartella WEB-INF contenuta nella ROOT.
Qui si ha, dentro la cartella CLASSES, i file CLASS delle classi Java che comprendono il
motore del sito web, tra cui le servlet e, dentro la cartella LIB, le opportune librerie in file di
tipo JAR (Java ARchive).
Le informazioni sulle applicazioni web del server sono memorizzate nel file WEB.XML che
dev’essere posizionato nella sotto cartella WEB-INF.
Il file WEB.XML si chiama deployment descriptor, descrittore della distribuzione ed è un
descrittore dei componenti utilizzati nell’applicazione web, la sua struttura è la seguente.
<?xml version="1.0" encoding="iso-8859-1"?>
<!-Licensed to the Apache Software Foundation (ASF)
-->
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"version="2.5">
<display-name>Welcome to Tomcat</display-name>
<description>
Welcome to Tomcat
</description>
<servlet>
<servlet-name> Esempio di servlet</servlet-name>
<servlet-class> Prova </servlet-class>
</servlet>
<servlet-mapping>
<servlet-name> Esempio di servlet</servlet-name>
<url-pattern> Prova1 </url-pattern>
</servlet-mapping>
</web-app>
Dove.
<web-app> è il TAG radice che indica l’elenco delle informazioni sulle applicazioni web.
<servlet-name> è il titolo identificativo della servlet.
<servlet-class> è il nome fisico del file CLASS contenente la servlet compilata.
<url-pattern> è l’URL nella casella degli indirizzi del browser per eseguire la servlet.
Per ogni servlet bisogna inserire i due elementi: <servlet> e <servlet-mapping>.
Supponendo di aver creato il file PROVA.CLASS e di averlo memorizzato nella sotto
cartella seguente.
C:\EASYPHP\APACHE\APACHE-TOMCAT-6.0.18\WEBAPPS\ROOT/ESEMPI/WEBINF/CLASSES
Per eseguire la servlet basta inserire nella barra degli indirizzi del browser l’indirizzo.
http://localhost:8080/esempi/Prova1
Server side
um 39 di 243
Il server Tomcat mette a disposizione un’intefaccia grafica, all’interno del Tomcat
Manager, per effettuare la distribuzione degli archivi WAR (Web ARchive).
PYTHON
Per aprire un server, dalla console digitare il comando seguente.
Server side
um 40 di 243
SICUREZZA DEI SERVER WEB
INTRODUZIONE
La sicurezza di un server web costituisce una buona parte della sicurezza di
un’applicazione.
Le informazioni sono uno dei beni più preziosi della società odierna e i DB rappresentano,
in senso virtuale, il luogo nel quale tali informazioni sono custodite in attesa di essere
utilizzate per le finalità più disparate.
I DBMS costituiscono il fondamento di ogni sistema; tuttavia essi non sono
tradizionalmente considerati alla stessa stregua dei SO e delle periferiche di rete almeno
per quanto concerne l’adozione degli standard di sicurezza.
Due sono le ragioni che rendono tali sistemi uno dei target più appetibili per gli hackers.
1. Presenza di dati che molto spesso assumono il carattere di estrema confidenzialità,
numeri di carte di credito, dati finanziari e strategici.
2. La compromissione di un server di DB determina, non di rado, a fronte di una difficoltà
di penetrazione talvolta irrisoria, la possibilità da parte dell’attaccante di acquisire il
completo controllo della macchina se non addirittura della intera infrastruttura di rete.
Cosa rende un server web una risorsa così appetibile ed esposta agli attacchi esterni:
sicuramente la combinazione dei fattori seguenti.
 Rappresentano delle vere e proprie porte di accesso alla LAN (Local Area Network)
nella quale sono custodite le informazioni più svariate.
 La sottovalutazione dei rischi oppure la mancanza di risorse economiche e umane da
dedicare al potenziamento delle politiche di sicurezza e anche la scarsa progettazione
e qualità del S/W possono determinare l’insorgere di una condizione d’intrinseca
vulnerabilità dei servizi web resa ancora più grave dalla loro esposizione al pubblico.
 Condurre con successo un attacco sul web utilizzando le classiche porte del servizio
HTTP 80, 81, 8000 è molto più facile dal momento che nella maggioranza dei casi il
traffico veicolato in questo modo non è bloccato dai dispositivi di controllo degli accessi
router e firewall.
Sfortunatamente non esistono dei rimedi nè delle tecniche tali da poter rendere sicuro al
100% un server contro gli attacchi provenienti dall’esterno ma, ciò nonostante, si può
ancora operare per tenere lontani molti problemi e vulnerabilità.
Per fare ciò occorre comprendere la natura e la portata dei pericoli ai quali ci si espone e
successivamente adottare delle precauzioni di carattere generale dirette a circoscrivere i
rischi suddetti entro limiti accettabili in relazione alla natura degli interessi da proteggere.
modello di sicurezza
I DBMS adottano una architettura di sicurezza basata su tre differenti livelli di protezione.
1. Autenticazione: questa è la fase più delicata, contempla la verifica dell’identità
dell’utente con una password, un sistema può autenticare un utente usando tre fattori.
1.1. Ciò che si conosce: la password.
1.2. Ciò che si possiede: la smart card.
1.3. Ciò che si è: password biometriche, impronte digitali, iride, retina e voce.
2. Autorizzazione: è la fase immediatamente seguente l’autenticazione nella quale il
sistema deve determinare a quali risorse l’utente può avere accesso e con quali
modalità operative, di regola le differenti attività che coinvolgono tale fase sono
raggruppate sotto la terminologia di “amministrazione della sicurezza degli utenti”.
3. Auditing: questa fase si contraddistingue per l’adozione di mezzi idonei a identificare e
riconoscere possibili abusi oltre che ad assicurare l’integrità delle informazioni.
Server side
um 41 di 243
INDIVIDUAZIONE DEI RISCHI
Quando si parla di sicurezza dei DB s’intende fare riferimento alla necessità di garantire
l’accessibilità dei dati, a prescindere dal loro valore intrinseco.
Qualunque attività diretta ad implementare e/o rafforzare la sicurezza di questi sistemi
presuppone il rispetto dei seguenti principi.
1. La definizione di pratiche e procedure di sicurezza chiare e di facile attuazione.
2. La predisposizione di livelli di sicurezza multipli.
3. L’applicazione costante del principio “dei privilegi minori”.
È importante non sottovalutare l’efficacia di questi criteri e, in particolare, di quelli indicati
nei punti due e tre.
In effetti senza la presenza di “strati” di sicurezza multipli diventa estremamente facile
connettersi ad un DB sfruttando la presenza di account noti e con password di default
oppure bypassando la sicurezza del SO e dei vari dispositivi che compongono
l’infrastruttura di rete.
Analogamente il principio dei privilegi minori, in virtù del quale ogni utente deve avere
assegnati soltanto i privilegi strettamente indispensabili al compimento delle sue attività,
evita i danni che possono derivare da un uso improprio oppure da azioni compiute in modo
accidentale.
I pericoli derivanti dalla mancata adozione di adeguati criteri di sicurezza nell’allestimento
e nel mantenimento di un sito web pubblico sono riconducibili alla possibilità di un abuso
del servizio da parte di soggetti malintenzionati.
Questo abuso può essere perpetrato in svariati modi ma molto spesso esso implica uno
sfruttamento degli errori di configurazione o delle vulnerabilità esistenti ai vari livelli.
1. SO.
2. Servizio HTTP o altri servizi di rete SMTP, DB e FTP.
3. Programmi/interpreti e script utilizzati per la generazione del contenuto del sito.
4. Dispositivi di controllo degli accessi router e firewall.
In linea generale il percorso che un aggressore tenta di seguire nell’attacco di un sistema
può essere riassunto nel modo seguente.
 Accesso al sistema attraverso l’esecuzione di exploit, lo sfruttamento di condizioni di
buffer overflow in script e applicazioni, la cattura o l’intercettazione del file delle
password e gli attacchi a forza bruta.
 Scalata dei privilegi e/o impersonificazione degli utenti con privilegi amministrativi
attraverso il crack delle password e/o l’esecuzione di exploit successivi.
 Occultamento delle tracce tramite la cancellazione dei log, l’uso di rootkits e lo
sfruttamento di particolari caratteristiche del SO.
 Installazione di backdoor che permettono all’aggressore un ritorno e una ripresa del
controllo del sistema in qualsiasi momento.
Complessivamente, in conseguenza di queste azioni, l’aggressore può essere portato ad
eseguire delle attività che rientrano in due aree principali.
1. Attività che comportano una manipolazione del server e/o un trafugamento di
informazioni.
1.1. Atti di vandalismo come la modifica dei contenuti delle pagine web o la
cancellazione del contenuto dell’intero sito.
1.2. Trafugamento
d’informazioni
sensibili concernenti
l’organizzazione, la
configurazione di rete oppure la clientela o gli utenti.
1.3. Uso dell’host come base per lanciare attacchi contro altri sistemi, attacchi DDOS
(Distributed Denial of Service).
1.4. Installazione di strumenti per il monitoraggio del traffico di rete e la cattura di
informazioni di autenticazione: sniffing.
2. Attività che producono una situazione d’indisponibiltà del servizio, in altre parole
l’impossibilità per gli utenti di accedere alle risorse messe a disposizione dal server.
Server side
um 42 di 243
standard di sicurezza
L’attuazione dei principi enunciati non può prescindere dalla considerazione di alcuni
aspetti fondamentali tra i quali meritano di essere ricordati i seguenti.
 Segretezza e confidenzialità: i dati devono poter essere consultati e/o modificati
soltanto da parte di chi sia debitamente autorizzato.
 Integrità e autenticità: i dati non devono poter essere manipolati dolosamente o
accidentalmente e la loro provenienza dev’essere verificabile.
 Accessibilità: i dati devono essere sempre disponibili eventualmente anche attraverso
il loro immediato ripristino.
Gli aspetti coinvolti nel processo di hardening di un DBMS sono i seguenti.
 Configurazione iniziale.
 Autenticazione degli utenti.
 Autorizzazione all’uso degli oggetti del DB.
 Amministrazione e l’aggiornamento delle policies.
 Auditing.
 Strategie di backup e di ripristino dei dati.
Il modo migliore di procedere, dopo aver identificato con esattezza i rischi, è quello di
predisporre un piano che individui una serie di misure precauzionali tali da condurre ad un
livello di sicurezza che dev’essere adeguato e proporzionato alla natura e all’importanza
delle risorse da proteggere, un portale di commercio elettronico indubbiamente richiede
livelli e politiche di sicurezza ben maggiori di un sito web di carattere statico.
Si tratta di un processo lungo e ripetitivo che deve partire dalla considerazione degli
aspetti più generali e che comporta una serie di attività e di valutazioni.
DISABILITARE I SERVIZI NON NECESSARI
Rimuovere FTP, disabilitare i linguaggi di scripting e gli script di esempio.
Limitare i servizi di condivisone di file, a singole cartelle e non a tutto il file system, quindi
creare una lista contenente gli indirizzi IP abilitati ad accedere al file sharing.
auditing
La maggior parte dei DB mette a disposizione funzionalità di auditing più o meno estese
che tuttavia non sono attive di default a causa del loro impatto negativo sulle performance
dell’intero sistema.
Nonostante l’inevitabile carico di lavoro aggiuntivo tali funzionalità hanno una importanza
fondamentale ai fini della individuazione di tutte le attività non autorizzate o dolosamente
poste in essere.
Pertanto, data la loro importanza, è sempre consigliabile ricorrere alle stesse cercando di
adottare un giusto compromesso tra prestazioni complessive e quantità di dati raccolti per
effetto del monitoraggio.
autorizzazione all’uso degli oggetti del DB
Generalmente i permessi assegnati agli utenti del DB racchiudono in se stessi il diritto di
accedere ai vari oggetti, tabelle, viste, sinonimi e SP (Stored Procedure), con modalità
operative differenti.
È consigliabile individuare preventivamente, in fase progettuale, i vari utenti del DB e
identificare per essi i ruoli, intesi in termini di raccolte di privilegi, più consoni al rispetto del
principio dei privilegi minimi.
autenticazione degli utenti
L’utilizzo delle risorse di un DB dev’essere sempre subordinato alla preventiva
autenticazione degli utenti che di regola avviene mediante la fornitura di una password.
Data la delicatezza dell’intero processo è opportuno predisporre delle policies che
Server side
um 43 di 243
stabiliscano i seguenti parametri.
 La durata minima delle password.
 La lunghezza minima e il rispetto di determinati criteri quali ad esempio l’uso combinato
di lettere, numeri e simboli.
 La predisposizione di meccanismi di lock degli account dopo un certo numero di
tentativi falliti di login.
 La determinazione del ciclo di vita degli account.
 L’opportunità di verificare la facilità con la quale le password possono essere
indovinate per mezzo di attacchi basati su un dizionario dati oppure condotti con il
metodo della forza bruta.
 La necessità di verificare il fatto che le password siano memorizzate nel DB in forma
crittografata.
amministrazione e aggiornamento delle policies
Nessun processo di hardening può dirsi veramente efficace senza che siano state
sviluppate delle policies adeguate.
Queste infatti rappresentano il framework utilizzato in tutte le attività ed i processi diretti a
rafforzare la sicurezza ed a gestire i rischi ed il loro compito fondamentale è quello di
garantire agli amministratori del DB che le attività compiute siano effettivamente
appropriate per l’organizzazione.
Vista la loro importanza è opportuno quindi che le policies regolamentino aspetti
fondamentali quali i seguenti.
 La creazione di standard relativamente ad account utente, password, oggetti e ruoli.
 I requisiti minimi in termini di esecuzione di attività di auditing e logging.
 Le procedure per la gestione delle patch rilasciate dal produttore del S/W.
 Il controllo degli accessi agli oggetti del DB.
 L’utilizzo dei ruoli predefiniti e la predisposizione di nuovi ruoli.
 Ogni altro aspetto che assuma rilevanza per l’organizzazione ai fini della sicurezza.
SCELTA DEL SO
Non è possibile parlare delle tecniche di protezione dei server web senza fare una breve
considerazione in merito ai criteri di scelta del SO poichè le caratteristiche di affidabilità e
robustezza di quest’ultimo possono avere un impatto significativo nella predisposizione e
nel mantenimento dei giusti livelli di sicurezza.
1. Assenza di vulnerabilità note nei confronti di tipologie conosciute di attacco.
2. Capacità di limitare determinati tipi di attività soltanto ad alcuni utenti.
3. Abilità nel rimuovere e disabilitare servizi e risorse non necessari.
4. Abilità nel controllare l’uso e l’accesso alle risorse e nel registrare la varie attività degli
utenti.
5. Facilità di gestione ma non a discapito della sicurezza.
SEPARARE I DATI PUBBLICI DA QUELLI PRIVATI
Non memorizzare dati riservati su sistemi usati anche come server web, a meno che non
sia assolutamente necessario.
Per un’extranet, adottare una configurazione con un “agnello sacrificale”: ovvero un server
web posto esternamente al firewall in modo da non mettere a rischio i dati aziendali dietro
al firewall.
CONFIGURAZIONE DI RETE
Isolare il server web dalla LAN, nell’ipotesi di una compromissione dell’host questa pratica
è infatti di ausilio nell’impedire il verificarsi di due conseguenze molto gravi.
1. L’accesso agli host della LAN da parte dell’aggressore.
Server side
um 44 di 243
2. Il monitoraggio del traffico proveniente dalla LAN con la conseguente cattura di
eventuali informazioni riservate.
Il raggiungimento di un tale livello d’isolamento diventa possibile attraverso la
configurazione e l’uso di una zona DMZ (DeMilitarized Zone), in pratica di una topologia in
grado di segmentare logicamente la LAN separando i sistemi interni da quelli esterni
accessibili al pubblico che devono rimanere isolati, accompagnata anche dalla presenza di
adeguati dispositivi di controllo degli accessi come router e firewall, i cui compiti sono.
 Bloccare tutto il traffico UDP, ICMP (Internet Control Message Protocol) e TCP non
strettamente necessario.
 Bloccare tutte le connessioni TCP che traggono origine dallo stesso server web.
 Bloccare il traffico tra il server web e la LAN.
 Disabilitare il source routing e scartare i datagrammi IP che abbiano impostata questa
opzione; il source routing è una funzione del meccanismo d’instradamento dei
pacchetti IP che permette alla sorgente di influenzare il percorso che il pacchetto
seguirà nel suo attraversamento delle reti.
Il blocco delle connessioni in uscita dal server HTTP non può comunque essere adottato
nel caso in cui quest’ultimo si avvalga di servizi esterni erogati da altri server, ad esempio
un DB per la generazione dinamica dei contenuti, un server SMTP per la posta in uscita.
Quando ciò accade è tuttavia conveniente collocare anche gli host dei servizi di supporto
all’interno di una sottorete e separare quest’ultima sia dalla LAN che da quella esterna
mediante l’utilizzo di dispositivi di controllo degli accessi.
 Bloccare qualsiasi tipo di traffico tra la rete Internet e questi host.
 Impedire ogni forma di traffico diretto tra gli utenti e i servizi di supporto.
 Disabilitare le funzioni di IP forwarding, inoltro del traffico IP, tra server web e server di
supporto.
Qualora non sia possibile servirsi di una zona DMZ, fermo restando i rischi di un possibile
accesso agli host della LAN, è sempre possibile ricorrere a dispositivi come hub e switch
in grado di suddividere il traffico della rete separando quello del web da quello interno ed,
eventualmente, criptare quest’ultimo così da renderlo comunque incomprensibile
all’aggressore anche in caso di avvenuta compromissione del server.
Sniffing: lettura dei dati in transito perché le applicazioni basate sul TCP/IP, FTP, HTTP,
SMNP, telnet offrono protezione scarsa per le password.
Implementare un protocollo secondario dedicato alla sicurezza come SSH, per esempio
HTTPS.
Quando si amministrano i server e i router da remoto mai usare protocolli telnet, SMNP e
FTP se non dopo aver attivato un protocollo di sicurezza.
CONFIGURAZIONE DEL SERVER
Il server web dovrebbe operare nell’ambito di una configurazione di rete e di sistema
davvero minima.
Il rispetto di questa semplice regola è effettivamente in grado di produrre come risultato un
sensibile miglioramento dei livelli di sicurezza attraverso questi espedienti.
1. La disabilitazione di tutti i servizi di rete non essenziali ed, in particolar modo, di quelli
affetti da vulnerabilità conosciute sotto il profilo della sicurezza.
2. La rimozione dal sistema dei file corrispondenti ai servizi disabilitati.
3. L’eliminazione delle porte TCP e UDP in ascolto superflue.
4. La rimozione o disabilitazione di tutte le risorse non richieste in relazione al ruolo
dell’host, compilatori, interpreti, shell e scripts.
5. La corretta gestione degli utenti e dei loro privilegi.
6. La predisposizione di regole adeguate per l’accesso e l’uso delle risorse.
Queste attività sono importanti non soltanto in un ottica generale di riduzione dei rischi di
compromissione del sistema ma anche in vista di uno snellimento delle attività di
amministrazione e, quindi, della minore probabilità di commettere errori di configurazione
Server side
um 45 di 243
che possono essere prontamente sfruttati da un aggressore.
A tal fine, proprio per evitare di commettere dimenticanze, è conveniente adottare un
approccio del tipo “deny all, then allow” che consiste prima nel disabilitare indistintamente
tutti i servizi e le porte TCP/UDP e poi nel riabilitare, dopo un’attenta valutazione, soltanto
quelle veramente essenziali.
Anche per quanto concerne la gestione degli utenti e dei privilegi vanno prefissate delle
regole improntate a criteri restrittivi.
 Impedire che il servizio HTTP sia lanciato da un utente con privilegi amministrativi
perchè questo può comportare l’acquisizione del controllo completo del sistema in caso
di exploit eseguito con successo.
 Disabilitare o rimuovere tutti gli account inutili, installati dal SO, per ridurre il rischio di
una impersonificazione o scalata dei privilegi nel caso d’intrusione.
 Modificare il nome dell’account di amministratore.
 Eliminare gli account non necessari, per esempio guest; disabilitare automaticamente
un account dopo un numero predefinito di tentativi di accesso falliti.
 Adottare criteri di robustezza delle password sotto il profilo della lunghezza, almeno
otto caratteri, complessità, alfanumerica con un mix di caratteri maiuscoli e minuscoli e
l’uso di caratteri non stampabili, riutilizzo da evitare e durata, cambiarla ogni sei
settimane.
 Verificare direttamente le password, preferibilmente mediante gli stessi strumenti usati
dagli hackers, per accertare che esse rispondano ai criteri voluti.
 Impostare il blocco degli utenti dopo un certo numero di tentativi falliti di login.
Il blocco degli utenti è una misura da adottare con cautela poichè costituisce un’arma a
doppio taglio che può spingere l’aggressore a provocare una situazione di DOS per
l’utente attraverso una serie di tentativi di connessione falliti.
I singoli processi coinvolti nella gestione del servizio HTTP devono comunque avere
accesso soltanto ai file e alle cartelle necessarie al loro funzionamento per i quali occorre
specificare delle regole di accesso ACL (Access Control List) che, oltre ad offrire una
maggiore granularità nel controllo dell’uso delle risorse, sono in grado di scongiurare o
mitigare gli effetti derivanti da un eventuale attacco DOS diretto a provocare una
situazione d’indisponibilità dell’intero sistema proprio attraverso un esaurimento delle sue
risorse.
In questa prospettiva per ridurre significativamente gli effetti derivanti da attacchi di questo
genere, è sempre consigliato il ricorso ai seguenti interventi correttivi.
 Creare una singola cartella radice e da essa far derivare una gerarchia di sotto cartelle
nelle quali suddividere le risorse che costituiscono il contenuto del web.
 Limitare ad una sola cartella, opportunamente configurata e protetta, tutte le
applicazioni esterne eseguite come parte integrante del servizio web.
 Limitare l’uso dei file temporanei da parte dei singoli processi all’interno di apposite
cartelle opportunamente protette e consentirne l’accesso soltanto ai processi stessi.
 Impedire che file e risorse esterne alla gerarchia di cartelle del server possano essere
forniti in risposta alle richieste degli utenti.
 Disabilitare l’uso dei link simbolici per evitare che risorse facenti parte del contenuto del
web possano puntare a file di sistema o ad altre risorse all’interno della LAN.
 Aggiustare le priorità dei vari processi di sistema.
USO DI APPLICAZIONI E DI SCRIPT
L’installazione e l’uso di applicazioni esterne, plugin e script può aprire una breccia nei
livelli di protezione di qualsiasi server web.
Anche gli host più inviolabili possono infatti cadere a causa di un banale exploit che sfrutta
un semplice script CGI per eseguire localmente sul server comandi diretti ad ottenere
l’accesso al sistema.
La preoccupazione principale deve sempre rimanere quella di ridurre i rischi.
Server side
um 46 di 243
 Evitare, se possibile, l’uso di script di terze parti oppure accertarne l’esatta provenienza
e autenticità del codice.
 Fare uso soltanto di applicazioni e degli script indispensabili disabilitando tutti gli altri.
 Impiegare tecniche di programmazione nella scrittura del codice e prestare la massima





attenzione ad aspetti quali la lunghezza e la complessità finale, la presenza di
opportuni controlli per la validazione dell’input e l’interazione con altre applicazioni
esterne o l’accesso in lettura e/o scrittura al file system.
Valutare la presenza di queste stesse caratteristiche anche negli script di terze parti.
Usare una macchina di test per verificare il funzionamento di tutte le applicazioni e
degli script prima ancora di impiegarli in una macchina di produzione.
Evitare di collocare le applicazioni e gli interpreti all’interno della stessa cartella dove
risiedono gli script, ad esempio la CGI-BIN e posizionarli invece in una cartella
separata opportunamente protetta e accessibile soltanto agli utenti amministratori.
Circoscrivere l’accesso di applicazioni e interpreti ai soli file e cartelle indispensabili al
loro funzionamento e comunque soltanto a quelli all’interno del contenuto pubblico del
web.
Verificare costantemente l’integrità degli eseguibili relativi ad applicazioni ed interpreti
nonchè degli script.
PROGETTAZIONE WEB DI QUALITÀ
L’uso di script può diminuire il livello di sicurezza di un server web poichè introduce
molteplici aspetti e variabili nel flusso di esecuzione del codice che possono essere
sfruttate da un aggressore per tentare di ottenere un accesso non autorizzato.
Non a caso una delle tipologie più note di aggressione si basa sull’invio al server di dati
inattesi mediante l’URL.
Generalmente questo avviene inviando una quantità eccessiva di dati oppure combinando
tecniche che consistono in un abuso di metacaratteri e nell’encoding della stringa al fine di
provocare tre effetti differenti.
1. Buffer overflow: si verifica quando un buffer d’input, ad esempio una variabile
all’interno di un’applicazione, è saturata con un valore più grande di quello che essa
riesce a gestire, di regola il verificarsi di questa condizione è sfruttato per tentare di
eseguire una porzione di codice arbitrario forzandolo all’interno dello stack di
esecuzione della CPU.
2. Alterazione della logica applicativa: può consistere nell’alterazione dei meccanismi di
autenticazione o nell’accesso a funzionalità riservate dell’applicativo.
3. Invocazione di funzioni di sistema o di altre applicazioni oppure accesso a file e risorse
che non fanno parte del contenuto del web.
L’approccio migliore per cercare di scongiurare questi effetti è rappresentato dall’adozione
di tecniche incentrate sulla qualità della programmazione, sull’implementazione di una
logica applicativa robusta e sul controllo del flusso.
 Usare meccanismi di controllo e di filtro dei dati d’input.
 Utilizzare tutte le caratteristiche di sicurezza messe a disposizione dai linguaggi.
 Evitare l’utilizzo di meccanismi come SSI (Server Side Include).
 Usare con attenzione e cautela i TAG nascosti all’interno delle pagine HTML.
Quando non si ha certezza sulla natura dell’input ricevuto è necessario ricorrere al
filtraggio dei dati attenendosi ad una regola elementare: identificare con esattezza la
natura e il tipo delle informazioni da gestire ed eliminare tutti i caratteri non necessari e
inutili avvalendosi di funzioni proprie o di quelle messe a disposizione dai linguaggi di
scripting.
Per quanto concerne l’utilizzo delle caratteristiche di sicurezza va ricordato che sia il PERL
sia il PHP implementano un meccanismo che evita il verificarsi di condizioni di overflow del
buffer d’input aggiustando automaticamente la dimensione di questo per supportare
un’allocazione di memoria consona alla quantità di dati effettivamente ricevuta.
Server side
um 47 di 243
Inoltre, i linguaggi offrono anche altre funzionalità.
 PERL può girare in una modalità detta “taint” abilitata da linea di comando mediante
l’opzione -T che avvisa nell’eventualità in cui i dati d’input siano passati ad alcune
funzioni di sistema tra le quali chmod, chown, exec, connect.
 CFML mette a disposizione una vera e propria sandbox che può essere sfruttata per
limitare l’invocazione delle funzioni di sistema oppure l’uso di certi TAG proprietari.
 PHP racchiude una modalità detta “safe_mode” che limita l’accesso di alcune funzioni
fopen, link, chmod ai soli file di cui è proprietario l’utente di PHP che generalmente
coincide con l’utente del server web.
 ASP consente di disabilitare le funzioni di sistema de-registrando l’oggetto file system
del motore di scripting, SCRRUN.DLL.
La disabilitazione degli SSI è un’altra misura precauzionale opportuna perchè questi
meccanismi possono rivelarsi un’arma a doppio taglio particolarmente insidiosa in quanto
se da un lato mettono a disposizione funzionalità interattive utili dall’altro hanno un
funzionamento fin troppo elementare da sovvertire per un aggressore poichè si basano
sull’impiego di TAG tra i quali “cmd” ed “email” che possono essere inseriti ovunque
all’interno di un documento HTML per forzare l’esecuzione di comandi in locale sul server.
Considerazioni analoghe spingono a evitare, se possibile, l’uso di TAG nascosti, specie
all’interno di form, per raccogliere informazioni sensibili che possono essere alterate con
estrema facilità.
IDENTIFICAZIONE E USO DI MECCANISMI DI LOGGING E AUDITING
La raccolta dei dati relativi al sistema, al traffico di rete, alle attività degli utenti e al server
web è essenziale poichè collezionando e analizzando queste informazioni diventa
possibile non soltanto scoprire i segni di eventuali intrusioni e determinare la portata delle
azioni compiute dall’aggressore ma anche individuare tutte quelle operazioni di “probing”
che, pur non rappresentando dei veri e propri attacchi, sono sintomi di un sicuro interesse
di qualcuno verso il sistema e in particolare verso le sue vulnerabilità.
L’approccio ideale per riconoscere in qualsiasi momento i segni di probabili intrusioni o di
altre attività anomale consiste nel paragonare le informazioni relative al funzionamento del
sistema in quel dato momento con le analoghe informazioni catturate in un momento
anteriore generalmente in fase di prima installazione od operatività che, in quanto tali,
costituiscono un’impronta affidabile e caratteristica del funzionamento del sistema stesso.
Di regola questo genere d’indicazioni è fornito dal SO, dal S/W che gestisce il server web
e da altri meccanismi di terze parti.
1. Monitorare e analizzare la natura e la portata del traffico di rete attraverso la raccolta di
questi dati.
1.1. Il numero dei pacchetti, il numero dei byte e delle connessioni in entrata e uscita
suddivisi per protocollo, indirizzi IP sorgenti e destinazione e porte.
1.2. Le intestazioni e il contenuto dei pacchetti ricevuti.
1.3. Il numero dei socket aperti.
1.4. Gli errori che si verificano sulle interfacce di rete e lo stato di queste ultime.
1.5. Le connessioni effettuate e i tentativi di connessione falliti suddivisi per protocollo,
nome dell’host/utente, porte, indirizzi, data e ora.
1.6. La durata e il flusso di ciascuna delle connessioni.
2. Monitorare l’utilizzo del sistema attraverso la raccolta di questi dati.
2.1. L’ammontare totale delle risorse in uso CPU, memoria e dischi.
2.2. Lo stato del file system per ciascuna partizione in termini di spazio libero, numero
dei file aperti e statistiche d’I/O.
2.3. I cambiamenti nello stato del sistema shutdown e riavvii.
2.4. La data e l’ora di avvio dei vari processi, la loro durata nonchè la percentuale di
risorse, le periferiche e il numero dei file che ciascuno di essi adopera.
2.5. Gli errori e i warning segnalati dal sistema.
Server side
um 48 di 243
3. Monitorare gli utenti e le attività di questi attraverso la raccolta di dati.
3.1. Login data e ora, numero di tentativi falliti, tentativi di accesso come utenti
privilegiati e logout.
3.2. I cambiamenti e le modifiche riguardanti i privilegi degli utenti e l’uso dei privilegi
stessi.
3.3. L’esecuzione di azioni che richiedono particolari privilegi.
3.4. Il numero dei processi avviato.
4. Monitorare e verificare l’integrità dei file attraverso la raccolta di questi dati.
4.1. Il numero e il timestamp di file e/o cartelle e i loro attributi.
4.2. Il checksum per tutti i file e le cartelle più importanti, file di sistema e di
configurazione, applicazioni e strumenti per la sicurezza, file contenenti dati
rilevanti.
4.3. I cambiamenti nelle dimensioni, nel contenuto e nella protezione dei file.
4.4. L’aggiunta, la cancellazione e la modifica di file e/o cartelle.
4.5. La presenza di eventuali “alternate data streaming” all’interno dei file.
4.6. I risultati delle scansioni antivirus.
5. Raccogliere e analizzare i file di log per i vari servizi di rete web, mail e FTP.
Naturalmente la mole d’informazioni che deriva da simili operazioni di monitoraggio può
essere veramente considerevole per cui è sempre opportuno effettuare un giusto
bilanciamento tra l’importanza della attività di raccolta dei dati e le risorse disponibili per
memorizzarli.
Qualunque sia la quantità d’informazioni che si decide di catturare è essenziale che
questa fotografia del funzionamento del sistema sia ripetuta in relazione ai vari
aggiornamenti che sono apportati al sistema stesso, installazione di nuovo S/W,
aggiornamento dei file del SO, applicazioni delle patches di sicurezza, in modo da
garantire l’attendibilità dei risultati che scaturiscono dal raffronto tra i dati.
Per non rischiare di vanificare inutilmente i meccanismi di logging e auditing è conveniente
adottare le seguenti precauzioni.
 Posizionare i log su un host separato dedicato esclusivamente a questa finalità e posto
all’interno di una sottorete protetta da firewall.
 Configurare questo host in modo da scongiurare o limitare fortemente gli effetti di un
possibile attacco di tipo DOS che può verificarsi se l’aggressore cerca di saturare le
risorse impiegate per il salvataggio dei dati in modo da far cessare il logging.
 Proteggere i log in modo tale da consentire l’accesso a essi e agli strumenti utilizzati
per la loro configurazione soltanto agli utenti debitamente autorizzati.
 Criptare i log contenenti informazioni sensibili nel momento stesso della loro
registrazione.
 Eliminare la possibilità che i dati una volta scritti possano essere modificati, usando per
la registrazione supporti di tipo DVD (Digital Versatile Disk).
 Predisporre regole per l’archiviazione dei log e la loro dislocazione in luoghi e su
supporti fisicamente sicuri.
 Analizzare i log con cadenza periodica avvalendosi degli strumenti esistenti a tal fine.
Per diminuire il volume dei dati da analizzare periodicamente e quindi favorire un riscontro
più puntuale dei dati possono essere impiegate tecniche cosiddette di rotazione che
consistono nel creare copie dei log online a intervalli regolari, rinominare queste copie e
analizzare i dati in esse contenuti in modo da poter contare sempre su una collezione di
log relativi a ben precisi momenti temporali.
MANTENIMENTO DELL’INTEGRITÀ DELLE RISORSE
È determinante per scongiurare gli effetti delle azioni che l’aggressore può compiere in
caso di penetrazione e che generalmente consistono nei seguenti modi.
 Nella sostituzione dei file di sistema con analoghi file, modificati e alterati nelle loro
funzionalità e nella modifica dei file di log per cercare di cancellare le proprie tracce.
Server side
um 49 di 243
 Nell’installazione di strumenti, backdoor che consentono di rientrare nel sistema in
qualsiasi momento per riprenderne il controllo.
 Nella modifica delle pagine web in modo che riproducano informazioni fuorvianti o
offensive e/o addirittura nella cancellazione dell’intero sito.
Per tutelarsi nei confronti di questi abusi è innanzitutto necessario predisporre una serie di
meccanismi idonei a monitorare lo stato, le modifiche e l’integrità del file system e
individuare i seguenti fattori.
 Le modifiche del file system come la creazione di nuovi file/cartelle e/o la modifica e
cancellazione di file esistenti.
 I cambiamenti nella dimensione, nel contenuto, negli attributi e nelle regole di accesso
ai file.
 Le alterazioni della consistenza dei log, variazioni nella dimensione e buchi temporali
nella registrazione degli eventi.
 La presenza di virus, backdoor e cavalli di troia.
 Le alterazioni del file delle password.
Inoltre, è importante predisporre delle misure idonee a consentire il ripristino di tutti i file e
applicazioni in caso di compromissione dell’integrità degli stessi.
 La creazione di copie di backup.
 Il salvataggio di queste copie in forma criptata su supporti di memorizzazione a sola
lettura o su un altro host posto in una sottorete protetta attraverso l’uso di firewall.
 La restrizione dell’accesso e dell’uso delle copie ai soli utenti debitamente autorizzati.
 La predisposizione di procedure da seguire per il ripristino dello stato dei file alterati o
modificati.
VULNERABILITÀ D’INTERPRETI E SCRIPT
Una delle caratteristiche più interessanti dei server web è rappresentata dalla loro capacità
d’interagire con gli utenti attraverso l’elaborazione dell’input per mezzo di appositi script
CGI, ASP, PHP che, a loro volta, sono interpretati da altre applicazioni esterne.
Purtroppo il prezzo da pagare a fronte dell’esistenza di queste funzionalità aggiuntive è
una diminuzione intrinseca dei livelli di sicurezza del server derivante dall’introduzione di
meccanismi il cui funzionamento s’inserisce all’interno dei normali processi che gestiscono
il servizio HTTP.
Infatti, la presenza di malfunzionamenti, generalmente imputabile a imperfezioni del
codice, introduce dei punti deboli nel funzionamento di questi meccanismi che possono
essere sfruttati da un aggressore per tentare di eseguire localmente sul server determinati
comandi.
Il risultato di queste azioni è in genere molto variabile da caso a caso ma in alcuni ipotesi è
addirittura costituito dalla fuoriuscita all’esterno d’informazioni sensibili, dall’invio tramite
email del file delle password, dalla modifica o dalla cancellazione d’informazioni del
registro di Windows, fino ad arrivare, nei casi più gravi, all’installazione di vere e proprie
backdoor e all’acquisizione del controllo completo dell’host da parte dell’aggressore.
Di regola la gravità delle conseguenze che scaturiscono da queste anomalie è tanto più
grave quanto più elevati sono i privilegi nel contesto dei quali avviene l’esecuzione di
questi script o dei processi S/W che l’interpretano.
In ogni caso non è corretto pensare che questo tipo di attacchi possa essere evitato dalla
semplice circostanza che i parametri per l’invocazione degli script sono normalmente
veicolati da una form HTML sotto forma di una sequenza del tipo seguente.
parametro1=valore1&parametro2=valore2
Poiché questa rappresenta un’ipotesi di corretto utilizzo che, peraltro, non esclude affatto
la possibilità di abusi.
Nulla vieta, infatti, ad un aggressore di costruirsi manualmente una stringa URL che tenti
Server side
um 50 di 243
di alterare il normale flusso di esecuzione dello script o dell’interprete sfruttando alcune
tecniche particolari.
 L’abuso dei metacaratteri e/o delle sequenze di escape con conseguente encoding
della URL, peraltro questa tecnica è anche utile per bypassare quei meccanismi di
scoperta delle intrusioni basati sulle cosiddette “signatures”.
 L’overflow del buffer d’input e l’induzione all’esecuzione di porzioni di codice arbitrario
attraverso tecniche cosiddette di “code injection”.
 L’esecuzione e/o l’invocazione non controllata di particolari funzioni di sistema.
Gli exploit si possono suddividere in due categorie fondamentali.
1. Exploit severi: espongono il sistema ad un elevato rischio di compromissione.
2. Exploit minori: producono conseguenze molto meno negative dei primi, come ad
esempio una eccessiva fuga d’informazioni all’esterno.
Vulnerabilità
Presuppone l’esistenza di uno o più punti deboli che rappresentano un potenziale fattore
di rischio per qualsiasi sistema poiché consentono a chiunque d’introdursi all’interno dello
stesso e danneggiarlo in qualche modo.
Exploit
È una tecnica che, facendo leva sulle vulnerabilità di un sistema, di un protocollo, cerca di
causare un comportamento anomalo e imprevisto, di regola, anche se non sempre, gli
exploit hanno un campo di applicazione limitato poiché sono strettamente legati alla
presenza di un determinato SO e/o servizio di rete o di particolari configurazioni.
DDOS
Produce come risultato la completa paralisi dell’attività del server.
Per provocare una situazione di questo genere è sufficiente inoltrare in modo ripetitivo un
numero considerevole di richieste di connessione HTTP ciascuna seguita dall’invio all’host
di un buffer di 200 caratteri.
L’elevato numero delle richieste può causare sul server un incremento della memoria di
sistema impegnata con conseguente saturazione delle risorse.
Non è facile eseguire con successo questo tipo di attacco, specie se proviene da una
fonte soltanto, poichè spesso esiste una considerevole differenza tra le risorse del sistema
attaccante e quelle del target che potrebbe benissimo essere in grado di far fronte a
centinaia di richieste senza per questo vedere degradare le proprie prestazioni.
Backup e ripristino dei dati
La cancellazione o l’alterazione delle informazioni a causa di malfunzionamenti di
carattere generale o per l’esecuzione di operazioni dannose può comportare delle ingenti
perdite, non soltanto di carattere economico, qualora non siano predisposte delle
adeguate strategie di backup periodico dei dati.
Inoltre, queste procedure non soltanto devono essere previste ma devono altresì essere
sottoposte a continui test in modo da assicurare una elevata probabilità di ripristino dei dati
in qualsiasi momento.
Server side
um 51 di 243
DB CENTRALE E DB REMOTI
INTRODUZIONE
Dato un sistema composto da un DB centrale, localizzato su un server e uno o più DB
remoti che non sono sempre connessi con quello centrale, nasce il problema di
sincronizzazione dei dati.
Il DB centrale conterrà i dati di tutti i clienti, di tutti i prodotti, gli ordini e i fornitori, mentre
quelli remoti, installati su smartphone o notebook degli agenti, conterranno solo una parte
dei dati: quelli che servono all’agente per il suo lavoro.
I dati dovranno essere sincronizzati: quelli nuovi presenti sul DB centrale, come nuovi
prodotti o aggiornamenti di prezzi, dovranno essere scaricati sui DB locali e gli ordini o
eventuali modifiche alle anagrafiche, dovranno essere inviati dal client al server centrale.
S’individuano due importanti problematiche.
1. L’accesso al DB centrale da parte del dispositivo, la sicurezza e i conflitti sui dati; infatti
è buona norma non esporre il DB centrale su Internet, non è infatti detto che i client
sincronizzino i dati dall’interno della LAN.
2. L’integrità dei dati, quello che può accadere, infatti, è che due o più sistemi remoti,
quando sono disconnessi, modifichino lo stesso dato.
Due rappresentanti, la mattina, sincronizzano i loro client scaricando l’anagrafica clienti.
Il rappresentante RA si reca dal suo cliente CA per prendere un ordine e, mentre è dal
cliente, quest’ultimo gli comunica che il numero di telefono è errato.
RA aggiorna l’anagrafica di CA sul suo client e fa l’ordine.
Per un errore di organizzazione, il rappresentante RB si reca da CA il quale, dopo avergli
confermato che è già passato il suo collega, si ricorda di aver dato a RA un numero di
telefono errato e comunica ad RB quello corretto.
RB aggiorna l’anagrafica di CA sul suo client.
La sera, quando RA e RB rientrano in sede e aggiornano i dati sul server centrale, i dati di
CA saranno stati modificati su ambedue i client.
Qual è il dato che si troverà sul server?
Per la corretta gestione di questa problematica, esistono diverse strade.
1. Parzializzazione dei dati: la più sicura ed economica, consiste nel fare in modo che
due client non possano modificare lo stesso dato, parzializzando appunto i dati che
ogni client gestisce, nel caso dell’esempio, ogni agente dovrebbe avere sul proprio
client solo i clienti di competenza; in questo modo, RB non potrà mai aggiornare i dati
di CA perchè il dato non è presente sul proprio dispositivo.
2. Sincronizzazione dei dati: si usa Service Broker di SQL Server.
3. Gestione autonoma dei conflitti sui dati: si usano opportuni campi delle tabelle, si
può sapere quando un record è stato modificato e se ci si trova di fronte ad un conflitto
ci si comporta di conseguenza, è evidente che tale sistema presuppone un grosso
lavoro di progettazione e d’implementazione.
SINCRONIZZAZIONE
SQL Server Mobile Edition permette di stabilire una connessione e scambiare dati con un
DB di SQL Server in tre modi.
Merge replication
È la metodologia più adatta da utilizzare nei client poiché permette di aggiornare i dati in
modo autonomo e indipendente sul dispositivo portatile e sul server.
Quando il dispositivo è connesso al server, è possibile sincronizzare i dati su entrambi, sia
per inviare le modifiche dal client al server sia per ricevere le nuove modifiche dal server.
Server side
um 52 di 243
Le merge replication sono molto potenti e consentono una dettagliata gestione dei conflitti,
cosa frequente quando si lavora con utenti disconnessi.
Hanno però lo svantaggio di essere complesse da configurare e, in alcuni casi, da gestire.
WS (Web Service)
Lascia ai programmatori il compito di gestire l’intero processo di sincronizzazione nonché
di gestione dei conflitti ma ha il vantaggio di non dipendere dal DB.
RDA (Remote Data Access)
È un sistema che consente di accedere e scambiare dati tra un dispositivo mobile e un
server centrale, per la connessione al server si usa IIS.
È evidente come solo il server web può essere esposto su Internet attraverso il firewall,
lasciando il server DB in una sotto rete separata e non esposta.
Internamente, RDA è strutturato in due moduli.
1. Uno sul client, per gestire la comunicazione con il DB locale.
2. Un modulo server il cui scopo è quello di gestire le richieste del client.
Lato client, l’agente locale si occupa di tracciare le modifiche ai dati delle tabelle che
partecipano alla sincronizzazione.
Quando uno dei metodi di RDA è richiamato, l’agente locale contatta, attraverso IIS del
Server side
um 53 di 243
server web, l’agente server che si occupa, attrraverso il data provider, di comunicare con il
server DB.
La funzionalità RDA permette ad un’applicazione, di accedere ai dati da una tabella di DB
remota di SQL Server e di archiviarli in una tabella di DB locale di SQL Server Mobile.
Dopo che i dati sono stati archiviati nella tabella locale di SQL Server Mobile,
l’applicazione potrà accedere alla tabella locale e quindi leggere e aggiornare i dati in essa
contenuti.
Una volta che l’applicazione termina di aggiornare i dati locali, può aggiornare nuovamente
i record modificati dalla tabella locale nella tabella remota di SQL Server.
La funzionalità RDA, si può utilizzare quando non è necessario impiegare tutte le
funzionalità messe a disposizione dalla replica di tipo merge come, ad esempio, la
risoluzione di conflitti.
RDA supporta tre tipi di comandi.
1. Pull: le tabelle e i dati da sincronizzare sono scaricati dal server, i dati da scaricare sul
client possono essere filtrati attraverso la clausola WHERE della query da inviare al
server, si possono così parzializzare i dati e fare in modo che ogni client ottenga solo
quelli di sua competenza.
2. Push: i dati modificati sul client sono inviati al server e inseriti nella tabella corretta.
3. SubmitSql: dà la possibilità di eseguire query SQL direttamente sul server DB, usando
l’architettura RDA.
Non è possibile richiamare il comando Push su una tabella di cui non è stato fatto prima il
Pull e questo perchè, senza aver eseguito il Pull, l’agente client non potrà tracciare le
modifiche eseguite su una tabella.
L’ordine di esecuzione da seguire quando si usa RDA è il seguente.
Se l’ordine non è rispettato, si avranno degli errori nel momento in cui si cercherà di
sincronizzare i dati con il server.
Se si hanno delle tabelle locali non presenti sul server, per cui non si ha la possibilità di
eseguirne il Pull, torna comodo il comando SubmitSql.
Prima d’iniziare ad usare RDA si deve installarne la parte server e configurarla.
Esempio, progettare un’applicazione per la creazione di ordini usata dai rappresentanti.
L’applicazione fa uso di un DB SQL Server Mobile Edition locale per la memorizzazione
dei dati che poi dovrà essere sincronizzato con un DB centrale.
Come prima operazione, si deve aggiungere al progetto, un riferimento alla libreria
SYSTEM.DATA.SQLSERVERCE.
Nella finestra del codice scrivere, come prima istruzione.
using System.Data.SqlServerCe;
Per aggiungere una connessione dati al DB, selezionare il menu Dati/Aggiungi nuova
origine dei dati… scegliere il DB Microsoft SQL Server Mobile Edition.
Server side
um 54 di 243
La prima operazione da fare è il Pull dei dati dal server verso il DB del dispositivo mobile.
Essendo un’operazione che potrebbe richiedere del tempo, per evitare di lasciare
l’interfaccia bloccata, è meglio far eseguire la sincronizzazione in un thread separato e
notificare, mediante dei messaggi in una casella di testo, lo stato di avanzamento della
sincronizzazione.
private void PullData() {
// Pull delle Tabelle
InvokeDelegate del = new InvokeDelegate(InvokeMethod);
SqlCeRemoteDataAccess rda = null;
try { foreach (String table in _tablesName) {
this.Invoke(del, new object[]{"Inizio drop tabella " + table});
DBHelper.DropTable(table);
this.Invoke(del, new object[]{"Drop tabella " + table + " eseguito"});
rda = new
SqlCeRemoteDataAccess(_ServerUrl, DBHelper.ConnString);
this.Invoke(del, new object[] { "Inizio Pull tabella " + table });
rda.Pull(table, "SELECT * FROM " + table, _rdaOleDbConnectString,
RdaTrackOption.TrackingOn);
this.Invoke(del, new object[] { "Pull tabella " + table + " eseguito" });
}
this.Invoke(del, new object[] { "Procedura di Pull completata" });
} catch (SqlCeException sqlCeEx) {
MessageBox.Show("Si è verificato un errore durante la sincronizzazione dei dati.
Ripetere l'operazione", "Mobile Order", MessageBoxButtons.OK,
Server side
um 55 di 243
MessageBoxIcon.Exclamation,MessageBoxDefaultButton.Button1);
} finally
{ rda.Dispose(); }
}
_tableName è un array di stringhe contenente i nomi delle tabelle da sincronizzare.
foreach richiama per primo il metodo DBHelper che esegue il Drop della tabella.
È successivamente creata un’istanza dell’oggetto RD cui si passa l’URL del sito web e la
stringa di connessione del DB locale.
L’ultima operazione è quella di eseguire il Pull vero e proprio dei dati specificando i
seguenti elementi.
1. Il nome della tabella di cui eseguire il Pull.
2. La stringa SQL per decidere quali dati della tabella scaricare sul client, in questa fase è
possibile far scaricare sul PDA (Personal Digital Assistant) solo i dati di competenza di
uno specifico agente.
3. La stringa di connessione al DB remoto.
4. Il tipo di tracking che si desidera eseguire sulla tabella.
Il primo passo è completo, il device può essere scollegato e i dati possono essere
modificati.
L’operazione opposta al Pull dei dati è il Push degli stessi verso il server centrale.
private void PushData() {
// Push delle tabelle
InvokeDelegate del = new InvokeDelegate(InvokeMethod);
SqlCeRemoteDataAccess rda = null;
try { foreach (String table in _tablesName) {
this.Invoke(del, new object[] { "Inizio Push tabella " + table });
rda = new SqlCeRemoteDataAccess(_ServerUrl,DBHelper.ConnString);
rda.Push(table, _rdaOleDbConnectString);
this.Invoke(del, new object[] { "Push tabella " + table + " eseguito" });
}
this.Invoke(del, new object[] { "Procedura di Push completata" });
} catch (SqlCeException sqlCeex) {
MessageBox.Show("Si è verificato un errore durante la sincronizzazione dei dati.
Ripetere l'operazione", "Mobile Order", MessageBoxButtons.OK,
MessageBoxIcon.Exclamation,MessageBoxDefaultButton.Button1);
} finally
{ rda.Dispose(); }
}
Dopo aver creato un’istanza di RDA, si richiama il metodo Push passando come
argomenti il nome della tabella e la stringa di connessione del server DB.
L’agente client di RDA si occuperà d’inviare al server solo i record modificati dall’ultimo
Pull della stessa tabella.
Esempio, sul notebook dell’agente è installato SQL Server Express, sul server remoto è
installato un SQL Server.
Quando l’agente salverà i dati, in realtà li “ingloberà” in un messaggio XML che sarà
conservato in una coda nel DB interno.
Alla prima disponibilità di connessione, il messaggio contenente il dato da salvare sarà
inviato al server centrale che lo riceverà e lo elaborerà inserendo il dato.
Tutte le modalità per lo scambio di messaggi sono implementate nel Service Broker.
Server side
um 56 di 243
RIA (RICH INTERNET APPLICATION)
INTRODUZIONE
In Internet c’è sempre più bisogno di servizi applicativi di tipo classico, come i gestionali, la
logistica e la produzione, rivisti però in un’ottica web.
Per rispondere a queste esigenze si sono sviluppate nel tempo due metodologie.
1. Applicazioni basate sulle architetture web.
2. Tecnologie AJAX.
Non si è riusciti, però, a cambiare la percezione degli utenti finali: l’usabilità e l’interattività
era migliore quando si usavano le versioni client/server.
Oggi si parla del nuovo modello applicativo: RIA, applicazioni web che possiedono
usabilità e interattività pari o migliori alle tradizionali applicazioni desktop.
Sono disponibili due tecnologie e ambienti di sviluppo.
1. Adobe Flex.
2. Microsoft Silverlight.
Sono punti di riferimento per realizzare RIA attraverso VM (Virtual Machine) grafiche che
dovrebbero sostituire i browser, ritenuti datati e incompatibili fra loro.
La difficoltà nell’utilizzo di questi strumenti non è solo quella di dover apprendere nuovi
linguaggi e nuove architetture ma soprattutto quella di dover suddividere la logica
applicativa in due contesti separati.
1. Server side: tanti servizi applicativi che svolgono operazioni atomiche.
2. Client side: la logica di controllo dell’UI che utilizzerà questi servizi.
Questo rende più difficile la realizzazione di applicazioni sicure e il controllo
dell’applicazione stessa, perché nel lato client è semplice alterare il funzionamento
modificando la coordinazione e l’uso dei servizi server; inoltre anche la distribuzione delle
versioni successive è più complessa e costosa.
Infine, un grave problema è che realizzare applicazioni così frammentate richiede molto
tempo e quindi costi elevati per cui la realizzazione di RIA resta un’attività decisamente più
onerosa in confronto allo sviluppo di applicazioni tradizionali.
Proprio per superare queste difficoltà e rendere possibile a tutti la creazione di RIA, si
stanno progettando sistemi che non sono semplicemente dei CASE (Computer Aided
Software Engineering) o framework ma veri e propri sistemi di sviluppo che contengono gli
strumenti necessari alla creazione di applicazioni RIA di qualunque grado di complessità.
PROGRAMMAZIONE RELAZIONALE
I componenti del S/W non sono più descritti in tanti file di testo, le classi, senza legami di
coerenza intrinseca ma attraverso una struttura relazionale, un grafo che nativamente
scopre e memorizza le relazioni fra i vari componenti dell’applicazione.
Il tutto avviene automaticamente mentre i programmatori continuano a lavorare con le
stesse dinamiche cui sono abituati e con il vantaggio ulteriore di poter utilizzare un solo
strumento per tutto il ciclo di vita del S/W, dal disegno del DB, al disegno dell’UI, alla
scrittura della business logic, alle definizioni delle stampe e alla creazione di componenti
aggiuntivi quali ad esempio i WS.
Le comunicazioni fra browser e server non sono più basate su HTML ma su XML
compresso e questo rende possibile ottenere l’interattività richiesta dalle RIA.
In conclusione, è un unico strumento per gestire tutto il ciclo di vita del S/W.
 La progettazione e la creazione degli schemi E/R (Entity/Relationship) nel DB.
 L’implementazione degli oggetti di business tramite la DO (Document Orientation).
Server side
um 57 di 243






La creazione del presentation manager di tipo RIA, dai form ai report.
Il debug e il test delle applicazioni.
La personalizzazione a run-time delle applicazioni, compreso il multilingua.
La creazione della documentazione utente e tecnica.
La gestione delle problematiche di assistenza agli utenti dell’applicazione.
La gestione del versioning e dei gruppi di lavoro.
SILVERLIGHT
Silverlight è un’implementazione ridotta del .NET Framework e del suo motore grafico.
Le capacità di WPF (Windows Presentation Foundation) sbarcano anche sul web.
Tutto ciò con la stessa possibilità di utilizzo di codice gestito e linguaggi dedicati e che
quindi offrono la loro produttività notevolmente maggiore rispetto ad un linguaggio per
esempio di scripting, possibilmente dedicato al solo web.
Caratteristiche a disposizione del programmatore di applicazioni web.
 Applicazioni cross-browser e cross-platform, senza alcuna differenza di
visualizzazione ed esecuzione, con caratteristiche di sicurezza e affidabilità proprie
della piattaforma.
 L’applicazione può sfruttare l’IS (Isolated Storage) per memorizzare dati locali e
consentirne l’utilizzo anche in scenari disconnessi.
 Applicazioni RIA, in altre parole applicazioni utilizzabili attraverso la rete e un browser.
 Fornisce la possibilità di audio e video streaming, scalandoli in base alla piattaforma
H/W di destinazione, passando per esempio da uno schermo di smartphone a monitor
di grandi dimensioni, mantenendo al massimo la qualità.
 Permette lo zoom, la rotazione, il drag & drop di elementi grafici all’interno del browser.
 Aggiorna una parte della pagina web senza necessità di refresh completo e quindi
d’interruzione dell’UX (User eXperience).
 È supportato tramite un plugin.
Server side
um 58 di 243
Architettura
È pervasa di componenti .NET classici: CLR (Common Language Runtime), LINQ
(Language INtegratedQuery) e XAML.
Ci sono diverse differenze tecniche rispetto a Flash.
 Testi e UI sono codificati secondo lo standard XAML e poiché i file XAML sono file di
testo, i contenuti e servizi Silverlight sono analizzabili e indicizzabili dai motori di ricerca
molto più velocemente di quelli binari di Flash.
 Programmazione delle animazioni: Flash si basa su sequenze di fotogrammi che
l’autore dell’applicazione, deve definire una per una proprio come quando si disegna
un cartone animato; in Silverlight, si possono creare sequenze temporali in cui è
sufficiente definire le posizioni iniziali e finali di un oggetto, al resto pensa il
compilatore.
Silverlight è destinato soprattutto all’interazione dell’utente con l’applicazione.
Ad esempio, è possibile interagire con la webcam, stampare contenuti, sentire la
pressione del tasto destro del mouse, eseguire operazioni di drag & drop dal file system, il
pieno supporto alla tastiera durante la visualizzazione in full-screen e la possibilità di
firmare digitalmente il file XAP di distribuzione.
Una delle caratteristiche più interessanti riguarda le Trusted Application, in altre parole
applicazioni out-of-browser che ricevono maggiori diritti per l’esecuzione di operazioni
quali l’interoperabilità con il mondo COM, per esempio Office.
Esiste anche la possibilità di visualizzare notifiche “toast” e ospitare il controllo web
browser all’interno di applicazioni out-of-browser.
Struttura di un’applicazione
Il contenuto di una pagina che contiene elementi Silverlight può essere creato utilizzando
differenti tecniche.
1. Inline XAML e codice JavaScript.
2. File XAML esterni e file JavaScript.
3. Package compressi che contengono XAML, codice gestito, immagini e media.
Per
creare
un
nuovo
progetto, fare
clic su
File/Nuovo
Progetto…
(CTRL+MAIUSC+N)/Modelli/Visual C#/Silverlight/Applicazione Silverlight.
Server side
um 59 di 243
I template contengono una configurazione di base di un’applicazione Silverlight, inclusa
un’applicazione web già corredata dei file necessari per l’integrazione del plugin nelle
pagine web, sia HTML sia ASP.NET.
Il primo passo del wizard propone di selezionare il CheckBox Ospita l’applicazione
Silverlight in un nuovo sito Web, l’opzione, abilitata di default, consente di creare,
contestualmente al progetto Silverlight, una applicazione ASP.NET con l’infrastruttura
necessaria per ospitare l’applicazione Silverlight stessa.
Quindi, chiede se per ospitare l’applicazione Silverlight si desideri utilizzare un Progetto
Applicazione Web ASP.NET o un Sito Web ASP.NET.
Server side
um 60 di 243
Scegliere la versione del run-time di Silverlight da utilizzare.
Non occorre selezionare Abilita servizi RIA WCF, in quanto non si utilizzano le
caratteristiche di questo componente.
Scegliendo la prima opzione, la Soluzione creata è composta di due progetti.
1. Il primo è un’applicazione web che contiene due file XAML e rappresenta il progetto
Silverlight.
2. Il secondo, con il suffisso web, è il progetto server che propone due pagine che
consentono di testare la soluzione, una pagina ha l’estensione ASPX, mentre l’altra,
indipendentemente dalla piattaforma server, è una pagina HTML.
Fare clic su Visualizza/Esplora soluzioni (CTRL+ALT+L), presenta l’organizzazione
gerarchica dei componenti del progetto con nome, finestre, codice e moduli.
Compilare la Soluzione per capire l’interazione fra i due progetti: la compilazione del
progetto Silverlight produce un file con estensione XAP che sarà copiato automaticamente
nella cartella CLIENTBIN del progetto web per permettere di testare immediatamente il
componente Silverlight nell’applicazione che lo ospita.
File SILVERLIGHTAPPLICATION1TESTPAGE.ASPX
Il plugin Silverlight è eseguito all’interno del browser come un modulo aggiuntivo ed è
istanziato nel codice di una pagina ASPX o HTML attraverso un elemento di tipo object.
<body>
<form id="form1" runat="server" style="height:100%">
<div id="silverlightControlHost">
<object data="data:application/x-silverlight-2," type="application/x-silverlight-2"
width="100%" height="100%">
<param name="source" value="ClientBin/SilverlightApplication1.xap"/>
<param name="onError" value="onSilverlightError" />
<param name="background" value="white" />
<param name="minRuntimeVersion" value="5.0.61118.0" />
<param name="autoUpgrade" value="true" />
<a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=5.0.61118.0"
style="text-decoration:none">
<img src="http://go.microsoft.com/fwlink/?LinkId=161376"
alt="Scarica Microsoft Silverlight" style="border-style:none"/>
Server side
um 61 di 243
</a>
</object><iframe id="_sl_historyFrame"
style="visibility:hidden;height:0px;width:0px;border:0px"></iframe></div>
</form>
</body>
File SILVERLIGHTAPPLICATION1TESTPAGE.HTML
<object data="data:application/x-silverlight-2," type="application/x-silverlight-2"
width="100%" height="100%">
<param name="source" value="ClientBin/SilverlightApplication1.xap"/>
<param name="onError" value="onSilverlightError" />
<param name="background" value="white" />
<param name="minRuntimeVersion" value="5.0.61118.0" />
<param name="autoUpgrade" value="true" />
<a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=5.0.61118.0"
style="text-decoration:none">
<img src="http://go.microsoft.com/fwlink/?LinkId=161376"
alt="Scarica Microsoft Silverlight" style="border-style:none"/>
</a>
</object>
Il TAG object specifica il tipo di oggetto Silverlight definendo le proprietà data e type
rispettivamente con i valori data:application/x-silverlight-2 e application/x-silverlight-2;
attraverso la collezione di oggetti param è possibile specificare una serie d’informazioni
utili all’applicazione stessa.
Il param source specifica il path del file XAP contenente l’applicazione Silverlight, tale file è
il risultato della compilazione del progetto e per consuetudine è posizionato all’interno
della cartella CLIENTBIN.
L’oggetto accetta molti parametri tra i più utili c’è il param OnError e la sua funzione
onSilverlightError.
Attraverso questo parametro si specifica il metodo che dev’essere eseguito qualora
occorrano errori imprevisti nell’esecuzione del codice.
Questo evento è proprio utile durante la fase di sviluppo per identificare quelle eccezioni
che possono verificarsi a run-time.
Il codice intercetta il tipo di errore e più informazioni possibili sull’eccezione, per poi
visualizzarle al programmatore in una finestra di alert.
Il param InitParameters consente di passare all’applicazione una serie d’informazioni che
possono provenire dalla pagina HTML.
Tali informazioni sono definite nella proprietà value attraverso una stringa di coppie
nome=valore separata da virgole.
<param name="initParameters" value="parameter1=value1,parameter2=value2 " />
Con questa definizione, tali variabili entrano a far parte dell’applicazione e possono essere
recuperate subito dopo lo startup.
Il metodo d’inserimento di un oggetto Silverlight può essere utilizzato su qualunque tipo di
server web, trattandosi di codice HTML.
Usando IIS e il supporto ASP.NET, è possibile inglobare un progetto Silverlight nella
pagina utilizzando il webcontrol Silverlight.
Selezionare con il tasto destro del mouse il progetto Silverlight e fare clic sulla voce
Proprietà.
Visual Studio permette di gestire gli aspetti principali dell’applicazione; oltre al nome
dell’assembly nel quale saranno compilati i file si può specificare il nome del file XAP nel
quale sono “impacchettate” in un file unico tutte le risorse da cui l’applicazione dipende per
Server side
um 62 di 243
funzionare.
Il file XAP è un comune file ZIP con diversa estensione nel quale sono compressi tutti gli
assembly referenziati nel progetto e tutte le risorse che si desiderano distribuire insieme al
progetto stesso.
Il file XAP è quello che dev’essere specificato nel param source del TAG object ed è
quello che dev’essere distribuito nel sito web.
Utilizzando Visual Studio il processo di pubblicazione è automatizzato insieme alla
compilazione attraverso la configurazione del pannello Silverlight Applicazione,
accessibile dalla voce Proprietà dell’applicazione web.
In questa maschera si specificano le applicazioni Silverlight che sono utilizzate nel sito
web; a seguito della compilazione della soluzione, il file XAP di ciascun progetto è copiato
all’interno della cartella specificata nella voce Percorso nel Web, il suo valore predefinito
è CLIENTBIN.
File APPMANIFEST.XML
Specifica l’elenco delle risorse contenute nel file XAP stesso, la versione del run-time di
Silverlight richiesto per l’esecuzione e, soprattutto, l’assembly e la classe di EntryPoint.
<Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
EntryPointAssembly="SilverlightItalia"
EntryPointType="SilverlightItalia.App"
RuntimeVersion="5.0.31005.0">
<Deployment.Parts>
</Deployment.Parts>
<AssemblyPart
x:Name="Silverlight"
Source="Silverlight.dll" />
</Deployment>
Questo file è utile al plugin per l’esecuzione del progetto ma in particolare è importante per
la definizione della classe di startup come punto d’inizio nell’esecuzione del codice.
Questa classe dev’essere di tipo Application e Visual Studio, nel template predispone
proprio due file per lo scopo: APP.XAML e APP.XAML.CS.
I suddetti file contengono proprio il codice di una classe di tipo Application: seguendo il
pattern di code behind, i due file contengono separatamente markup XAML e codice
applicativo, per poi essere riuniti in un’unica classe in fase di compil-time.
Attraverso essi è possibile gestire il ciclo di vita dell’applicazione, nella fattispecie
dell’evento Application_Startup è istanziata e utilizzata quella classe che rappresenta
concretamente il vero progetto: la classe MainPage.
Il progetto Silverlight contiene due file.
Server side
um 63 di 243
File APP.XAML
Definisce l’applicazione.
<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SilverlightApplication1.App"
>
<Application.Resources>
</Application.Resources>
</Application>
File MAINPAGE.XAML
È la pagina di default che è caricata all’avvio dell’applicazione.
La classe MainPage è l’UserControl principale che contiene la grafica del menu e la logica
che gestisce l’UI.
In Silverlight le UI si definiscono attraverso gli oggetti di tipo UserControl che possono
contenere sia l’interfaccia grafica sia la logica applicativa.
Uno UserControl può essere definito come un raggruppamento di più controlli in modo da
creare una funzionalità complessa e specifica per l’applicazione.
L’attributo x:Class deve corrispondere al nome della classe del code behind associato alla
pagina.
<UserControl x:Class="SilverlightApplication1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
</Grid>
</UserControl>
La definizione di DesignHeight e DesignWidth imposta la grandezza dell’area occupata dal
plugin al 100% dell’area disponibile nel browser, tuttavia la zona utilizzabile per la
presentazione dell’UI è definita proprio con le dimensioni dell’UserControl principale.
Esempio, utilizzare come controllo principale un pannello Grid, capace di sistemare gli
elementi figli in righe e colonne e che occuperà il 100% dello spazio disponibile.
<UserControl x:Class="SilverlightApplication1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="Aquamarine">
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Header Area-->
Server side
um 64 di 243
<Border Grid.Row="0" Height="50" VerticalAlignment="Top" BorderBrush="White"
BorderThickness="0,0,0,4">
<TextBlock Text="Esempio Silverlight" FontSize="24" Foreground="Black"
VerticalAlignment="Bottom" Margin="5,0,0,5" />
</Border>
<Grid Grid.Row="1" >
<!-- Master/Details Area -->
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="300"/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0" x:Name="MasterControl" Background="Yellow"/>
<Border Grid.Column="1" x:Name="DetailsControl" />
</Grid>
</Grid>
</Grid>
</UserControl>
La griglia definisce due righe, la prima delle quali ha un’altezza fissa di DIP (Device
Independent Pixels), mentre la seconda occuperà lo spazio rimanente.
Immediatamente sotto la definizione delle righe, si trova il TAG Border che è posizionato
nella prima riga grazie all’impostazione Grid.Row="0".
Questa tipologia di proprietà è chiamata attached property, in altre parole è una proprietà
esposta dal contenitore, in questo caso Grid che è agganciata (attaccata) ai controlli figli
per semplicità di sviluppo.
Border è un controllo figlio e non una proprietà, infatti, è un oggetto che rappresenta una
cornice e propone una serie di proprietà, per esempio BorderThickness rappresenta la
dimensione di ogni lato della cornice partendo dal lato sinistro in senso orario.
Nell’esempio, quindi, l’unico lato a essere riempito di bianco, tramite la proprietà
BorderBrush, è il lato inferiore.
Il controllo Border è un controllo che può contenere un solo elemento figlio: nell’esempio è
rappresentato da un’etichetta testuale identificato da un controllo TextBlock che propone
una serie di proprietà, per esempio Margin che rispetta le stesse regole della proprietà
BorderThickness.
Grid.Row="1", definisce nella seconda riga, un’ulteriore griglia che consente di suddividere
il contenuto in due colonne per creare un’interfaccia di tipo Master/Detail.
Eseguire l’applicazione e provare a modificare la dimensione della finestra del browser per
apprezzare che la colonna si adatta alla dimensione della finestra, mentre il titolo e la
parte di destra restano fisse.
Server side
um 65 di 243
Il programmatore deve dare la possibilità all’utente di decidere la dimensione delle
colonne.
Per questo scopo c’è il controllo GridSplitter, per utilizzarlo occorre aggiungere un
riferimento, nel progetto Silverlight, alla libreria SYSTEM.WINDOWS.CONTROLS.
Il parser XAML di Silverlight conosce solo i controlli prestabiliti, quindi per utilizzare
elementi esterni come il controllo GridSplitter, si deve dichiarare il namespace
SYSTEM.WINDOWS.CONTROLS, definito nell’assembly omonimo e assegnare un alias
al namespace XML.
Nel codice seguente, nel TAG UserControl si definisce come xmlns:controls il mapping
verso il namespace .NET che contiene il controllo GridSplitter.
xmlns:controls="clr-namespace:System.Windows.Controls;assembly =
System.Windows.Controls"
Dopo l’operazione di mapping si può referenziare il controllo nella pagina tramite la
sintassi seguente.
<controls:GridSplitter Grid.Column="0" HorizontalAlignment="Right" Width="5" />
Il controllo è stato poi posizionato all’interno della griglia allineato a destra nella prima
colonna.
Oggetto di avvio
Le applicazioni Silverlight hanno un’unica “pagina” di partenza nella quale dovranno
essere presenti tutti i controlli di cui l’applicazione necessita.
Infatti, per cambiare questa pagina iniziale, non è disponibile un metodo strutturato ma si
dovrà modificare manualmente una proprietà del file APP.XAML che rappresenta
l’applicazione Silverlight, è un po’ come il form di partenza delle WinForms che è unico.
La proprietà da modificare per cambiare pagina iniziale si chiama RootVisual ed è esposta
dalla classe base Application da cui deriva la classe App del file APP.XAML.
Affinché al prossimo avvio dell’applicazione sia mostrato il nuovo file al posto del
precedente PAGE.XAML, si deve aprire il file APP.XAML.CS e individuare il metodo
Server side
um 66 di 243
Application_Startup nel quale è assegnata la proprietà RootVisual.
private void Application_Startup(object sender, StartupEventArgs e)
{ //this.RootVisual = new DeepZoomDemo();
this.RootVisual = new ProgressBarDemo();
}
Deep Zoom Composer
Permette di visualizzare sul web immagini a risoluzione molto alta senza che questo
rallenti la navigazione.
In pratica, l’immagine ad alta risoluzione di partenza è spezzettata in immagini di
dimensioni inferiori, in modo da creare una specie di “piramide” costituita dalla stessa
immagine a risoluzioni differenti via via sempre più alte.
In questo modo è possibile caricare immediatamente l’immagine alla sua risoluzione più
bassa, per passare poi progressivamente e solo in seguito alla richiesta dell’utente, a
visualizzare le risoluzioni più alte che saranno caricate in maniera sequenziale.
Permette anche di comporre una vera e propria “scena” formata da diverse immagini
opportunamente sovrapposte o allineate tra loro in modo da creare un’immagine più
grande che sarà poi possibile “navigare” grazie alla funzionalità DeepZoom.
Esempio, creare le immagini con Deep Zoom Composer per poi passare al codice
Silverlight per ottenere l’effetto desiderato.
Al termine della procedura di composizione delle immagini, copiare la cartella generata dal
tool, all’interno della cartella CLIENTBIN dell’applicazione web che si utilizza per
richiamare l’applicazione Silverlight.
Il controllo MultiScaleImage contiene l’immagine da visualizzare, espone la proprietà
Source che va impostata con il percorso del file generato dal tool.
Oltre a questo, si devono gestire i vari eventi necessari affinché l’immagine si possa
navigare con il mouse oltre a permetterne lo zoom attraverso la rotellina.
File DEEPZOOMDEMO.XAML
<UserControl x:Class="SilverlightTipsAndTricks.DeepZoomDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="White">
<MultiScaleImage x:Name="dzImage"
Source="F:/Esercizi/Silverlight/SilverlightTipsAndTricks/SilverlightTipsAndTricks.Web/Clie
ntBin/fiore/dzc_output.xml"
MouseLeftButtonDown="dzImage_MouseLeftButtonDown"
MouseLeftButtonUp="dzImage_MouseLeftButtonUp"
MouseMove="dzImage_MouseMove"></MultiScaleImage>
</Grid>
</UserControl>
File DEEPZOOMDEMO.XAML.CS
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
Server side
um 67 di 243
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace SilverlightTipsAndTricks {
public partial class DeepZoomDemo : UserControl {
Point currentMousePos = new Point();
Point mousePos = new Point();
Point mousePoint = new Point();
bool dragging = false;
double zoomFactor = 1;
public DeepZoomDemo()
{ InitializeComponent();
MouseMove += new MouseEventHandler(DeepZoomDemo_MouseMove);
new MouseWheelHelper(this).Moved += new
EventHandler<MouseWheelEventArgs>(DeepZoomDemo_Moved);
}
private void DeepZoomDemo_Moved(object sender, MouseWheelEventArgs e)
{ double newzoom = zoomFactor;
newzoom = ((e.Delta > 0) ? newzoom /= 1.2 : newzoom *= 1.2);
Point logicalPoint = dzImage.ElementToLogicalPoint(currentMousePos);
dzImage.ZoomAboutLogicalPoint(zoomFactor/newzoom,logicalPoint.X,logicalPoint.Y);
zoomFactor = newzoom;
}
private void DeepZoomDemo_MouseMove(object sender, MouseEventArgs e)
{ currentMousePos = e.GetPosition(dzImage); }
private void dzImage_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{ mousePos = e.GetPosition(dzImage);
mousePoint = dzImage.ViewportOrigin;
dragging = true;
}
private void dzImage_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{ dragging = false; }
private void dzImage_MouseMove(object sender, MouseEventArgs e)
{ if (dragging) {
Point newPoint = mousePoint;
Point mousePosition = e.GetPosition(dzImage);
newPoint.X += (mousePos.X - mousePosition.X) / dzImage.ActualWidth *
dzImage.ViewportWidth;
newPoint.Y += (mousePos.Y - mousePosition.Y) / dzImage.ActualWidth *
dzImage.ViewportWidth;
dzImage.ViewportOrigin = newPoint;
}
}
}
}
Anche in Silverlight è possibile eseguire Unit Test utilizzando due specifiche librerie.
MICROSOFT.SILVERLIGHT.TESTING.DLL.
MICROSOFT.VISUALSTUDIO.QUALITYTOOLS.UNITTESTING.SILVERLIGHT.DLL.
Server side
um 68 di 243
LIGHTSWITCH
INTRODUZIONE
È una piattaforma di sviluppo che permette di creare applicazioni data-driven sia per il
cloud sia per il desktop secondo il modello three-tier, in altre parole un’applicazione LOB
(Line Of Business), basate sui dati, con pochi clic e in modo semplice come premere un
interruttore della luce: da cui il nome LightSwitch.
C’è anche la possibilità d’installare un’applicazione in Windows Azure, con l’automatica
migrazione dei dati in un DB SQL Azure.
Si creano le tabelle, si creano le maschere e LightSwitch prepara l’infrastruttura.
Si esegue l’applicazione funzionante senza scrivere codice.
 Le applicazioni gestionali, anche se si tratta di applicazioni “verticali”, fanno un certo
numero di attività che sono comuni a tutti gli altri gestionali.
 I programmatori progettano applicazioni gestionali seguendo una sequenza di azioni
sempre uguali.
Creare un DB o connettersi ad un DB esistente, creare l’interfaccia utente con varie
modalità griglia, master-detail, scheda singola, modulo di ricerca con selezione dati,
associare i controlli dell’interfaccia all’origine dati, eseguire le operazioni CRUD, esportare
una tabella di dati verso Excel, sono tutte abilità che devono essere fornite
all’applicazione.
Non può sostituire strumenti professionali come Visual Studio ma può essere utile in vari
contesti, nascondendo all’utente molti dettagli dell’architettura, evitandogli di dover
conoscere il linguaggio di programmazione, almeno per i progetti più semplici.
Le applicazioni LightSwitch sono però completamente configurabili e si può accedere
all’editor di codice per aggiungere il codice che rappresenta le regole di business che si
vogliono introdurre nell’applicazione.
STRUMENTI
Le applicazioni LightSwitch utilizzano tecnologie e pattern d’avanguardia.
 Silverlight e WCF.
 RIA Services e l’Office Automation per l’integrazione con Office.
 SQL Server e SQL Azure.
 SharePoint.
 Pattern MV-VM (Model View-View Model).
TIPI DI DATI
Ci sono due nuovi tipi di dato specifici per EmailAddress e PhoneNumber, sono importanti
perché incorporano funzionalità di validazione dei dati.
Binary
Boolean
Date, DateTime
Decimal, Money
Double
EmailAddress, PhoneNumber, String
Int16
Server side
byte[]
bool
DateTime
decimal
double
string
short
um 69 di 243
Int32
Int64
Sbyte
Single
TimeSpan
Guid
int
long
SByte
float
TimeSpan
Guid
ARCHITETTURA
Una LOB è organizzata in tre livelli.
1. Livello di presentazione: Client Tier si occupa dell’interfaccia utente, recuperando i
dati dagli altri livelli e inviando le modifiche.
2. Livello relativo alla logica di business: Middle Tier è il livello che smista le richieste
del livello di presentazione al livello dati, gestisce la sicurezza per garantire che l’utente
abbia i permessi per visualizzare e/o modificare determinati dati e effettua le
elaborazioni secondo le regole di business.
3. Livello dati: Data Access è costituito dal DBMS o da un’applicazione che si occupa di
gestire la persistenza dei dati e dei documenti archiviati.
Questi tre livelli sono tra loro interconnessi, perché ciascuno dei livelli fornisce servizi che
servono agli altri livelli.
Creare un’applicazione gestionale a tre livelli non è un compito semplice, perché per ogni
livello ci sono innumerevoli scelte da fare, sia dal punto di vista della tecnologia da
utilizzare, sia da quello delle tecniche da adottare, per esempio il problema della
sicurezza.
TIPOLOGIE DI APPLICAZIONE
Sta iniziando una nuova “era di rottura” sulla divisione tra applicazioni desktop e web,
perché ormai è possibile trasformare un’applicazione desktop in un’applicazione web o per
il cloud e viceversa con un semplice clic.
Questo era impensabile, fino a oggi, per le nette differenze delle piattaforme.
In LightSwitch si può passare da un’applicazione desktop ad un’applicazione web, con un
clic del mouse; è sufficiente aprire la finestra delle proprietà dell’applicazione, doppio clic
sulla voce Properties, nella finestra Esplora Soluzioni e spostarsi alla scheda
Application Type.
In questa scheda è possibile scegliere tre tipi di applicazione ma più precisamente tre
architetture diverse.
Server side
um 70 di 243
La scheda Access Control permette d’impostare il livello di sicurezza dell’applicazione.
Inoltre, è possibile definire i ruoli per esempio Utente, Superutente, Amministratore, gli
utenti appartenenti a ciascun ruolo e i permessi da assegnare a ciascuno di essi o a
ciascun ruolo.
APPLICAZIONE DESKTOP
L’ambiente di sviluppo s’integra in Visual Studio, aggiungendo ai template di progetto
disponibili l’applicazione LightSwitch, per la quale è possibile utilizzare sia il linguaggio
Visual C# sia Visual Basic.
I programmatori si trovano di fronte ad un problema che è costituito dalla necessità di
collegare un DB di SQL Server ad un’istanza di SQL Server già installata sul PC.
Se l’applicazione non è installata da programmatore ma dall’utente, come fa a collegare il
DB a SQL Server, se esiste già un DB con lo stesso nome, se SQL Server non è installato
nel PC di destinazione o se ha un nome d’istanza diverso.
Con Visual Studio LightSwitch si ha la possibilità di creare un DB locale, basato su file di
SQL Server, definendo le tabelle e le relazioni che servono all’applicazione.
In questo modo si risolve il problema dell’installazione, pur mantenendo alcune importanti
caratteristiche dei file di DB di SQL Server: l’accesso protetto ai dati, la robustezza e la
Server side
um 71 di 243
stabilità della struttura dei file.
Esempio, progettare un DB e definire tabelle e relazioni per una struttura master-detail
come può essere quella delle fatture.
La parte master corrisponde all’intestazione della fattura: numero e data fattura, dati del
cliente, condizioni di pagamento.
La parte detail è formata dalle singole righe di ciascun prodotto o servizio fatturato: codice,
descrizione, prezzo unitario, quantità, importo totale, aliquota IVA.
Creare un nuovo progetto, fare clic su File/Nuovo progetto… (CTRL+N), selezionare
nella finestra Nuovo progetto e in Modelli installati LightSwitch.
Usare il template per Visual Basic e chiamarlo LS_masterdetail.
Creazione delle tabelle
Nella prima schermata, si può scegliere di creare una nuova tabella Create new table
oppure di aprire una connessione ad un DB esterno Attach to external database.
S’inizia da Create new table per creare una nuova tabella, selezionare l’intestazione
Table1ItemSet e modificarla in Fatture_.
Quando si sposta il cursore dall’intestazione, si vede che nella finestra Esplora Soluzioni
sarà modificato il nome della fonte dati in Fatture_Set.
A questo punto, inserire i campi della tabella.
Server side
um 72 di 243
In ogni tabella è inserito di default un campo ID di tipo Int32, è la PK.
Creare la seconda tabella, con i dati delle righe di dettaglio della fattura.
Per avviare la creazione di una nuova tabella, in Esplora Soluzioni fare clic con il
pulsante destro del mouse sul nodo ApplicationData e selezionate Add Table.
Cambiare il nome della tabella in Dettagli_.
A questo punto, inserire i campi della tabella.
Server side
um 73 di 243
Creare la tabella relativa ai dati dei clienti, cambiare il nome della tabella in Clienti_.
A questo punto, inserire i campi della tabella.
Creazione delle relazioni tra tabelle
Nella parte superiore della finestra di definizione delle tabelle ci sono alcuni pulsanti.
Per definire una nuova relazione, fare clic sul secondo pulsante Relationship….
Le relazioni da creare sono due.
1. Clienti e Fatture.
2. Fatture e Dettagli.
In entrambi i casi, alla prima tabella è assegnata la proprietà Multiplicity pari a One,
mentre la seconda tabella ha la proprietà impostata a Many, in altre parole la classica
relazione uno-a-molti, indicato anche più sinteticamente con (1:N).
La proprietà On Delete Behavior è la proprietà che definisce il comportamento da
adottare in caso di cancellazione di un record: l’opzione preimpostata è Restricted ma se
Server side
um 74 di 243
si vuole è possibile impostarla con l’opzione Cascade delete (cancellazione in cascata).
In pratica, con questa ultima opzione, se si cancella un record cliente, sono cancellate
tutte le fatture associate a tale cliente e, ancora in cascata, tutti i record di dettaglio di
ciascuna fattura.
Nel caso di un gestionale, in genere è meglio controllare in modo puntuale la
cancellazione, prima di effettuare una cancellazione a cascata.
Nella figura si può osservare la struttura delle relazioni di tabella, focalizzata sulla tabella
Fatture.
Per navigare tra le tabelle, è sufficiente fare un doppio clic sulla tabella desiderata e subito
si vede cambiare la visualizzazione, con il focus su tale tabella.
Notare che le tabelle, dopo la definizione delle relazioni, sono state modificate: infatti, sono
stati aggiunti automaticamente i campi necessari per inserire il riferimento al record
associato nella tabella correlata: chiave esterna.
Le chiavi esterne sono implicite, poiché non sono mai visualizzate nelle schermate ma
sono gestite in modo totalmente trasparente all’utente.
Creazione delle schermate per la gestione dei dati
Per definire un nuovo screen, una visualizzazione, una schermata, fare clic sul quinto
pulsante Screen…, è possibile selezionare cinque tipi di schermate.
1. New Data Screen per l’inserimento di nuovi record.
2. Search Data Screen per la ricerca di dati.
3. Details Screen di tipo master-detail.
4. Editable Grid Screen una griglia per la visualizzazione e modifica di dati in forma
tabellare, utilizzata per la visualizzazione di un cliente, nella casella Screen Name:
inserire Clienti.
5. List and Details Screen, di tipo master-detail espresso però come una lista, per la
visualizzazione di una fattura.
Server side
um 75 di 243
Anche se l’applicazione non è terminata, se si esegue si può vedere che questa parte è
già funzionante, dato che ora è possibile inserire nuove righe nella tabella Clienti,
modificarle e cancellarle.
Dopo aver inserito le righe di dati, ricordarsi sempre di cliccare sul pulsante Save, per
memorizzare i dati nel DB locale.
Durante lo sviluppo dell’applicazione, si può controllare se uno screen potrà essere
visualizzato nel menu laterale e quindi essere disponibile nell’applicazione in run-time,
evitando così di avviare più volte l’applicazione per verificarne il corretto funzionamento.
È sufficiente aprire la finestra delle proprietà dell’applicazione, doppio clic sulla voce
Properties, nella finestra Esplora Soluzioni e spostarsi alla scheda Screen Navigation,
nel nodo Tasks, sono presenti entrambi gli Screen.
Server side
um 76 di 243
In ogni screen ci sono dei pulsanti già predefiniti e funzionanti, tra cui anche un pulsante
per l’esportazione del set di dati verso un foglio Excel.
Il designer mostra la composizione della maschera, elencando i controlli di comando e
quelli data-bound, fare doppio su Fatture.
DB locale
Nella finestra Esplora Soluzioni, i dati sono definiti all’interno del nodo Data Sources, nel
DB chiamato ApplicationData.
In quest’ultimo nodo sono contenute le tabelle, se si va a vedere all’interno dei file
contenuti nel progetto, si scopre che gli oggetti di DB sono mappati nel file
APPLICATIONDEFINITION.LSML (LightSwitch Markup Language), contenuto nella
cartella Data.
Questo però non è il file che contiene i dati inseriti dall’utente ma è solamente il file che
contiene la definizione della struttura dei dati: tabelle, campi, relazioni, vincoli.
I dati veri e propri si trovano nella sotto cartella BIN\DATA dove ci sono due file,
rispettivamente con estensione MDF e LDF.
Il DB locale non è altro che un file di DB di SQL Server, scollegato da qualsiasi istanza di
Server side
um 77 di 243
SQL Server eventualmente installata sul PC.
Esaminare la struttura del DB: creare una nuova connessione al DB, dalla finestra
Esplora Server, fare clic sulla terza icona Connetti al database.
Usare il provider dati File di database Microsoft SQL Server.
Una volta aperta la connessione, si vede che il DB contiene le seguenti tabelle.
Server side
um 78 di 243
Il DB include non soltanto le tabelle create nel corso dello sviluppo dell’applicazione ma
anche una serie di altre tabelle accessorie per la definizione di profili, ruoli, utenti,
permessi.
Inoltre, c’è la presenza di numerose Visualizzazioni e Stored procedure, definite
automaticamente durante la creazione del DB.
Creare il diagramma delle relazioni tra le tre tabelle, fare clic nella finestra Esplora Server
sul pulsante Diagrammi di database.
Aprire la finestra delle proprietà dell’applicazione, doppio clic sulla voce Properties, nella
finestra Esplora Soluzioni e spostarsi alla scheda General.
Questa scheda è dedicata alle proprietà generali dell’applicazione, si può dare il nome
all’applicazione, assegnare un’immagine per il logo e un’icona, indicare la “cultura” da
utilizzare, per esempio per le impostazioni relative ai numeri, alle valute e alle date, il
numero di versione distinto in major version e minor version.
Server side
um 79 di 243
Esecuzione
Salvare, compilare e eseguire l’applicazione.
Nella finestra si notano i seguenti elementi.
 Un controllo ribbon con i comandi principali.
 Una scheda Task con i comandi per mostrare le maschere.
 La validazione automatica dei dati, senza scrivere codice.
Sul lato sinistro c’è l’elenco degli screen inseriti nell’applicazione.
Nella parte alta è presente un controllo ribbon, con alcuni pulsanti per salvare le modifiche
e per aggiornare la visualizzazione.
Infine, all’interno della finestra di visualizzazione, sono inseriti i pulsanti per aggiungere,
modificare o cancellare i record, la casella di ricerca e perfino un pulsante già predisposto
per esportare i dati dell’intera griglia in un foglio Excel.
Per esempio, se si vuole aggiungere un record alla tabella, basta cliccare sul pulsante
Add….
Appare una finestra di dialogo con tutti i controlli già predisposti per l’inserimento dei dati.
L’applicazione include anche già delle regole per la validazione dei dati, anche se non può
certo prevedere tutte le regole di validazione che possono essere definite in contesti
specifici.
L’applicazione, dopo la sua creazione attraverso i wizard, può essere completamente
personalizzata e modificata, sia nell’aspetto grafico, sia nelle regole di business che
devono essere definite dietro le quinte, sia aggiungendo funzionalità che possono essere
implementate solamente attraverso il codice Visual Basic o Visual C#.
Server side
um 80 di 243
APPLICAZIONE WEB
Aprire la finestra delle proprietà dell’applicazione, doppio clic sulla voce Properties, nella
finestra Esplora Soluzioni e spostarsi alla scheda Application Type.
Fare clic sulla terza opzione, per selezionare il tipo di applicazione Browser client, 3-tier
deployment.
Dopo aver salvato le modifiche, eseguire l’applicazione.
Si apre il browser con l’applicazione nella pagina web che ha lo stesso aspetto e le stesse
funzionalità dell’applicazione per desktop.
Server side
um 81 di 243
CONNESSIONE A UN DB ESISTENTE
Fare clic sulla voce Attach to external database, apparirà una finestra di dialogo relativa
ad un wizard, un’autocomposizione, per la definizione della connessione all’origine dati.
È possibile creare una connessione a un Database, ad un sito SharePoint o anche a un
WCF RIA Service, selezionare Database e fare clic sul pulsante Next.
Server side
um 82 di 243
Il passo successivo definisce le proprietà della connessione, con la finestra di dialogo
seguente.
Lasciare invariato il provider dati Microsoft SQL Server (SqlClient), perché si ha a
disposizione proprio un DB di questo tipo.
Dopo aver selezionato il nome del server, del tipo di autenticazione e il nome del DB che
interessa, fare clic sul pulsante Test connessione.
Server side
um 83 di 243
Avuta conferma della correttezza di tutte le proprietà di connessione, il passaggio
successivo richiede la scelta delle tabelle che si vogliono inserire nel Data Source.
Selezionare la tabella dati e modificare, se si desidera, il nome del Data Source, da quello
proposto automaticamente C_APPO_DATI_MDFData dovuto a una ridenominazione del
DB collegato all’istanza di SQL Server e fare clic sul pulsante Finish.
Sono visualizzate le tabelle e loro relazione, nell’esempio è una sola.
Definire uno screen per la visualizzazione della tabella.
Server side
um 84 di 243
Salvare, compilare e eseguire l’applicazione.
QUERY
Per avviare la creazione di una nuova query, in Esplora Soluzioni fare clic con il pulsante
destro del mouse all’interno del nodo Data Sources/C_APPO_DATI_MDFData/dati/Add
Query.
Definire uno screen per la visualizzazione della query.
Server side
um 85 di 243
Salvare, compilare e eseguire l’applicazione.
La localizzazione è la possibilità di creare delle versioni dell’applicazione con lingue
diverse ma con una limitazione: bisogna creare distribuzioni distinte, una per ogni lingua.
Per il cambiamento della lingua nell’interfaccia utente, per gli elementi standard, è
sufficiente cambiare la selezione della casella a discesa Culture, nelle proprietà
dell’applicazione.
A questo punto, riavviando l’applicazione, si vede che le voci standard saranno
visualizzate nella lingua selezionata.
Tutte le parti non standard dell’applicazione dovranno essere tradotte manualmente.
Server side
um 86 di 243
MODULO 5
ASP.NET
Introduzione
Visual Studio
Web Form
Passaggio d’informazioni
Master Page
Temi
Web User Control
Web Control Library
Convalida
Applicazioni multilingua
Rilevazione del browser
SEO
Server side
um 87 di 243
INTRODUZIONE
ASP
Le pagine ASP utilizzano un modello di threading chiamato STA (Single Threaded
Apartment) che stabilisce che tra tutti gli oggetti dati in un determinato thread, solo uno
può essere eseguito in un determinato momento; se due o tre oggetti sono pronti per
l’esecuzione, prima che il secondo possa iniziare deve terminare il primo e così via.
Le pagine ASP.NET usano il modello di threading MTA (Multiple TA), se due o più oggetti
sono pronti per l’esecuzione, ASP.NET inizia simultaneamente l’esecuzione di entrambi,
per default, dispone di 25 thread per ogni CPU multicore per processare tutte le richieste
HTTP relative alle applicazioni ospitate nello stesso processo, questo numero si può
alzare da configurazione.
Questa capacità migliora le prestazioni in generale ma richiede particolari funzionalità
nell’implementazione di ogni oggetto.
In STA, un oggetto non deve mai preoccuparsi che un altro possa assumere il controllo
esclusivo su una risorsa o che possa aggiornare informazioni in modo inaspettato.
In MTA, ogni oggetto deve prendere le precauzioni del caso, altrimenti uno degli oggetti
produrrà risultati non corretti.
Il .NET Framework fornisce i seguenti strumenti.
 ASP.NET: permette di scrivere pagine web dinamiche, compilate, eseguite sul server.
 IIS Express: server web su cui pubblicare le applicazioni web.
 SQL (Structured Query Language) Server Express LocalDB: è il RDBMS
(Relational DataBase Management System) locale su cui ospitare i DB utilizzati dalle
applicazioni web.
ASP.NET supporta due modalità per creare l’UI.
1. ASP.NET WebForms: è il modello classico, dove ogni pagina è chiamata Web Form,
offre un approccio basato su controlli ed eventi, simile alle applicazioni Windows.
2. ASP.NET MVC: è l’implementazione del pattern MVC (Model View Controller) per
applicazioni ASP.NET, consente un controllo maggiore in fase di definizione del
markup e garantisce la possibilità di testare il codice.
ASP.NET CORE
È il run-time di ASP.NET, condiviso sia da ASP.NET WebForms sia da ASP.NET MVC.
Supporto all’async sia negli HttpHandler sia negli HttpModule.
La compilazione e il JIT (Just In Time) del .NET Framework sfruttano al meglio le
architetture H/W, parallelizzando il carico, con evidenti benefici in termini di performance.
Server side
um 88 di 243
Le funzionalità di compilazione multicore sono attivate automaticamente, senza che debba
essere fatto nulla da parte del programmatore.
PROFILE API
ASP.NET ha un supporto fisico per aree protette, fornito attraverso l’uso di alcune
funzionalità.
Per quanto riguarda la protezione, sono supportati due scenari.
1. Autenticazione integrata di Windows: a carico del server web.
2. Autenticazione tramite form: a carico del programmatore via codice.
Per evitare tutto questo, ASP.NET supporta il meccanismo di Membership API che
consente di definire un provider che esegue tutto il lavoro.
Per quanto riguarda i ruoli sono sfruttate le Roles API.
In entrambi i casi si tratta di funzionalità che si basano sul provider Model Design Pattern
che prevede la definizione di un provider che implementa concretamente la strategia e di
una serie di provider che possono essere definiti nel file WEB.CONFIG.
I provider, basati su una classe astratta in comune, possono essere scambiati tra loro,
modificando il funzionamento interno di queste due funzionalità.
Il provider Model rappresenta un vantaggio in termini di flessibilità, specie nella sua
applicazione principale con Membership, Roles e Profile API: consente di scrivere codice
usando un’API che, poi, attraverso la dependency injection, attiva un provider opportuno
che contiene l’implementazione concreta.
Questo consente di scrivere una volta il codice, ad esempio per gestire l’autenticazione e
decidere, dal WEB.CONFIG, quale sia l’implementazione e quindi il DB da utilizzare.
ASP.NET supporta, inoltre, una serie di controlli chiamati security control che offrono un
supporto nativo alle funzionalità di login, creazione utente e recupero password.
Con gli Universal Provider, inclusi in ASP.NET e contenuti all’interno del namespace
System.Web.Providers, è offerta maggior flessibilità, funzionano anche con SQL Server
Compact e SQL Azure.
Creando un nuovo progetto, saranno registrati di default.
Esempio, Membership provider.
<membership defaultprovider="DefaultMembershipProvider">
<providers>
<add type="System.Web.Providers.DefaultMembershipProvider"
name="DefaultMembershipProvider" ...="" />
</providers>
</membership>
WEBSOCKET
ASP.NET aggiunge una nuova proprietà IsWebSocketRequest all’HttpContext, oltre ad
una serie di oggetti tramite i quali gestire questo tipo di comunicazioni.
Per sfruttare WebSocket, si deve realizzare un HttpHandler all’interno del quale verificare
se si è in presenza di una richiesta di tipo WebSocket.
public class WebSocketHandler : IhttpHandler {
public void ProcessRequest(HttpContext context)
{ if (context.IsWebSocketRequest)
context.AcceptWebSocketRequest(x => HandleRequest(x));
}
private async Task HandleRequest(AspNetWebSocketContext context)
{ WebSocket socket = context.WebSocket;
// ... codice
Server side
um 89 di 243
}
}
In caso positivo, è invocato il metodo HandleRequest passando come parametro un
AspNetWebSocketContext che si può considerare come l’analogo di HttpContext per
questo protocollo e che, nello specifico, si può utilizzare per recuperare un’istanza
dell’oggetto WebSocket, tramite il quale si possono ricevere e inviare dati al browser.
Esempio, il server risponde con un pingback a ogni messaggio ricevuto dal browser.
private async Task HandleRequest(AspNetWebSocketContext context)
{ WebSocket socket = context.WebSocket;
while (true) {
var buffer = new ArraySegment<byte>(new byte[1024]);
var result = await socket.ReceiveAsync(buffer, CancellationToken.None);
if (socket.State == WebSocketState.Open) {
string message = Encoding.UTF8.GetString(buffer.Array, 0, buffer.Array.Length);
var reply = "Pingback: " + message;
buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(reply));
await socket.SendAsync(buffer, WebSocketMessageType.Text,true,
CancellationToken.None);
}
else
break;
}
}
Il primo passo è attendere un messaggio da parte del WebSocket remoto con il metodo
ReceiveAsync che, alla ricezione, ne memorizza il contenuto binario all’interno di un buffer
di byte.
A questo punto, se il socket è ancora aperto, si può costruire il messaggio di risposta e
inviarlo tramite SendAsync.
Nell’esempio si è implementata una comunicazione di tipo richiesta/risposta ma questo
non è necessario e quindi si possono inviare messaggi in push dal server al browser in
maniera del tutto autonoma.
Dal punto di vista del client si può interagire con questo handler creando da JavaScript un
oggetto di tipo WebSocket.
<script type="text/ecmascript">
$(function () {
var socket = new WebSocket("ws://localhost:19534/websocketdemo.ashx");
socket.onmessage = function (msg) {
alert(msg.data);
};
$('#btnSend').click(function () {
socket.send($('#message').val());
});
});
</script>
Il protocollo non è più http:// ma ws://; se si sta utilizzando IIS 8 (Internet Information
Services) il supporto a questo protocollo è nativo.
L’oggetto WebSocket espone un membro onmessage al quale si può agganciare un
handler che sarà eseguito alla ricezione di ogni messaggio.
Server side
um 90 di 243
Nell’esempio, si visualizza il contenuto tramite un alert.
L’invio, invece, avviene tramite la funzione send che accetta l’oggetto da inviare al server.
SERVIZI
L’architettura più innovativa nell’ambito delle applicazioni web è sicuramente quella delle
SPA (Single Page Application).
Questa tipologia di applicazioni e, ovviamente, anche quelle più “tradizionali” che fanno
però un uso massiccio di AJAX si basano sulla possibilità d’invocare una serie di servizi
esposti dal server per manipolare i dati e aggiornare i contenuti delle pagine.
In un tale contesto, avere a disposizione un’infrastruttura che renda agevole e veloce la
realizzazione di questi servizi server side costituisce indubbiamente un enorme valore
aggiunto ed è proprio questa la direzione in cui si muove ASP.NET Web API.
Esempio, realizzare una serie di servizi per gestire la classe seguente.
public class Customer {
public int Id
{ get; set; }
public string Name
{ get; set; }
public string Region
{ get; set; }
}
Per sfruttare ASP.NET Web API tutto ciò che si deve fare è aggiungere un nuovo
controller chiamato CustomersController, è possibile sfruttare anche uno dei template di
API Controller e che per esempio conterrà una coppia di action, GetAllCustomers e
GetCustomerById.
public class CustomersController : ApiController {
public IEnumerable<Customer> GetAllCustomers()
{ return _customers; }
public Customer GetCustomerById(int id)
{ var result = _customers.SingleOrDefault(x => x.Id == id);
if (result == null)
throw new HttpResponseException(HttpStatusCode.NotFound);
return result;
}
}
Questo oggetto presenta alcune differenze rispetto ad un controller tradizionale.
 La classe base è ApiController, invece che Controller.
 Le action restituiscono oggetti, invece che istanze di ActionResult.
 Eventuali errori sono gestiti con status code HTML.
Con queste semplicissime righe di codice, il servizio è già pronto e funzionante.
Per testarlo, è sufficiente aprire dal browser l’URL (Uniform Resource Locator) seguente.
http://localhost:.../api/customers
E ottenere in questo modo il risultato di GetAllCustomers o accedere all’URL seguente.
http://localhost:.../api/customers/1
Server side
um 91 di 243
Per recuperare il customer di il cui ID è 1.
È ASP.NET Web API a occuparsi di tutto il resto, per esempio serializzando il risultato in
XML o JSON (JavaScript Object Notation) in base alla particolare request che è pervenuta
al server e, soprattutto, integrando questo controller con l’infrastruttura di routing in base a
delle semplici convenzioni sui nomi.
Nelle impostazioni di default, il pattern di base dell’indirizzo è /api/{controller}/{id};.
L’action è cercata in base al verbo HTML della request.
Se s’invoca il servizio in GET, saranno prese in considerazione le action che iniziano per
Get- come GetAllCustomers e GetCustomerById.
Se si usa POST sarà cercata un’action con il prefisso Post- e così via.
Tra queste action, sarà poi selezionata quella i cui parametri corrispondono all’URL della
richiesta: /api/customers non ha alcun parametro, quindi sarà invocata GetCustomers,
mentre se si specifica un ID sarà utilizzata GetCustomerById, visto che il metodo ha un
argomento che si chiama proprio in questo modo.
ASYNC/AWAIT
Si hanno a disposizione delle estensioni per i controller che consentono di sfruttare queste
parole chiave per l’invocazione di metodi asincroni.
Per realizzare un’action asincrona è sufficiente marcarla come async e restituire un
oggetto di tipo Task.
public async Task<ActionResult> Index()
{ using (var client = new WebClient())
{ var result = await client.DownloadStringTaskAsync("http://www.miosito.com");
ViewBag.Content = result;
}
return View();
}
Il codice dell’action è analogo a quello dell’implementazione sincrona, sebbene questa
forma consenta di sfruttare al massimo il server e migliorare quindi le prestazioni e la
scalabilità dell’applicazione: durante la chiamata al server remoto, infatti, il thread
assegnato da IIS alla gestione della REQUEST non resterà in attesa della risposta ma
ritornerà a disposizione del thread pool del server e potrà essere sfruttato per processare
un’ulteriore richiesta.
BUNDLING
È la capacità di unire insieme una serie di file, per formarne uno solo: il vantaggio di
questa tecnica è che i browser, per via di come funziona il meccanismo di richiesta di una
risorsa tra resolve dei DNS, latenza e numero massimo di richieste contemporanee
preferiscono scaricare un solo file di dimensioni maggiori che un numero elevato di file di
piccole dimensioni.
MINIFICATION
È la tecnica di ridurre al minimo possibile un file, per risparmiare banda e rendere più
veloce ed efficiente il trasferimento dei file, per esempio CSS e JavaScript sono pieni di
caratteri non necessari, spazi, TAB e commenti.
In entrambi i casi, queste tecniche sono applicate a run-time con meccanismi di cache, per
evitare d’impattare sul server, senza essere obbligati a scrivere file senza commenti o
senza spazi o ritorni a capo.
In questo caso le istruzioni per avere questo comportamento sono molto semplici e si
trovano nel file APP_START\BUNDLECONFIG.CS, aggiunto in automatico ai progetti.
Server side
um 92 di 243
File APP_START\BUNDLECONFIG.CS
using System.Web.Optimization;
namespace WebApplication1 {
public class BundleConfig {
public static void RegisterBundles(BundleCollection bundles)
{ bundles.Add(new ScriptBundle("~/bundles/WebFormsJs").Include(
"~/Scripts/WebForms/WebForms.js",
"~/Scripts/WebForms/WebUIValidation.js",
"~/Scripts/WebForms/MenuStandards.js",
"~/Scripts/WebForms/Focus.js",
"~/Scripts/WebForms/GridView.js",
"~/Scripts/WebForms/DetailsView.js",
"~/Scripts/WebForms/TreeView.js",
"~/Scripts/WebForms/WebParts.js"));
bundles.Add(new ScriptBundle("~/bundles/MsAjaxJs").Include(
"~/Scripts/WebForms/MsAjax/MicrosoftAjax.js",
"~/Scripts/WebForms/MsAjax/MicrosoftAjaxApplicationServices.js",
"~/Scripts/WebForms/MsAjax/MicrosoftAjaxTimer.js",
"~/Scripts/WebForms/MsAjax/MicrosoftAjaxWebForms.js"));
bundles.Add(new ScriptBundle("~/bundles/modernizr").Include(
"~/Scripts/modernizr-*"));
}
}
}
Esistono opzioni che consentono di personalizzare diversi aspetti, ma, di default, i bundle
funzionano prendendo tutti i file all’interno di un dato percorso, escludendo quelli con
suffisso VSDOC o INTELLISENSE, necessari solo all’editor di Visual Studio.
Server side
um 93 di 243
In una WebForms basterà riferirsi al bundle in questo modo.
<%: Scripts.Render("~/bundles/scripts") %>
In ASP.NET MVC basterà riferirsi al bundle in questo modo.
@Scripts.Render("~/bundles/scripts")
Nel caso il bundle riguardi i CSS, bisogna utilizzare la classe StyleBundle e il metodo
Styles.Render.
Tutto il lavoro, dietro le quinte, è fatto da ASP.NET: fintanto che si è in modalità Debug,
l’engine si limiterà a includere i singoli file del bundle, in modo da semplificare
l’investigazione di eventuali errori.
Una volta messo il sito in produzione, è sufficiente impostare su WEB.CONFIG la modalità
di compilazione in release, per attivare l’engine di minification e far sì che tutti i riferimenti
siano automaticamente condensati all’interno di un unico link e rielaborati in modo da
limitarne la dimensione.
SICUREZZA applicativa
Si usa il Provider Model per autenticare gli utenti e autorizzarli all’utilizzo dell’applicazione.
In pratica, si sfrutta un DB SQL Server e per configurarlo si usa il seguente tool sia da
linea di comando, se si passano i relativi parametri sia come wizard, nel caso in cui non si
passa alcun parametro.
C:\Windows\Microsoft.NET\Framework64\v4.0.30319>aspnet_regsql.exe /?
Microsoft (R) ASP.NET SQL Registration Tool versione 4.0.30319.18408
Utilità amministrativa per l'installazione e la disinstallazione delle funzional
ità ASP.NET in un'istanza di SQL Server.
Copyright (C) Microsoft Corporation. Tutti i diritti sono riservati.
-- OPZIONI GENERALI --?
Visualizza questo argomento della Guida.
-W
Modalità guidata. Impostazione predefinita utilizzata se non
sono specificati altri parametri.
-- OPZIONI DI CONNESSIONE SQL --S <server>
Istanza di SQL Server (SQL Server 7.0 o versione successiva)
da utilizzare.
-U <ID accesso> Nome utente di SQL Server per l'autenticazione. È richiesta
l'opzione -P.
-P <password> Password di SQL Server per l'autenticazione. È richiesta
l'opzione -U.
-E
Esecuzione dell'autenticazione con le credenziali di Windows correnti.
-C <stringa di connessione>
Stringa di connessione. Anziché specificare nome utente,
password e nome del server, è possibile specificare una
stringa di connessione di SQL Server. Tale stringa non deve
contenere un nome di database, a meno che non venga
specificato diversamente.
-sqlexportonly <nomefile>
Generazione del file script SQL per l'aggiunta o la rimozione
delle funzionalità specificate, senza eseguire l'operazione
effettiva. Sono supportate le opzioni seguenti: -A, -R,
-ssadd e -ssremove.
-- OPZIONI DEI SERVIZI APPLICATIVI -Server side
um 94 di 243
-A all|m|r|p|c|w Aggiunge il supporto per una funzionalità. È possibile
specificare più valori contemporaneamente, ad esempio:
-A mp
-A m -A p
all: tutte le funzionalità
m: appartenenza
r: Gestione ruoli
p: profili
c: personalizzazione
w: provider di eventi Web SQL
-R all|m|r|p|c|w Rimozione del supporto per una funzionalità. È possibile
specificare più valori contemporaneamente, ad esempio:
-R mp
-R m -R p
all : tutte le funzionalità, oltre alle tabelle comuni e alle
stored procedure condivise dalle funzionalità
m: appartenenza
r: Gestione ruoli
p: profili
c: personalizzazione
w: provider di eventi Web SQL
-d <database> Nome del database da utilizzare con i servizi applicativi. Se
non si specifica il nome del database, verrà utilizzato il
database predefinito "aspnetdb".
-Q
Modalità non interattiva. Non chiede di confermare la
rimozione delle funzionalità.
-- OPZIONI RELATIVE ALLA DIPENDENZA DELLA CACHE SQL (PER SQL SERVER 7.0
E 2000)
--d <database> Nome del database da utilizzare con la dipendenza della cache
SQL in SQL 7.0 e SQL 2000. In alternativa, il nome del
database può essere specificato utilizzando la stringa di
connessione con l'opzione -C. (Richiesto)
-ed
Abilitazione di un database per la dipendenza della cache SQL.
-dd
Disabilitazione di un database per la dipendenza della cache SQL.
-et
Abilitazione di una tabella per la dipendenza della cache
SQL. È richiesta l'opzione -t.
-dt
Disabilitazione di una tabella per la dipendenza della cache
SQL. È richiesta l'opzione -t.
-t <tabella>
Nome della tabella da abilitare o disabilitare per la
dipendenza della cache SQL. È richiesta l'opzione -et o -dt.
-lt
Elenco di tutte le tabelle abilitate per la dipendenza della
cache SQL.
-- OPZIONI STATO SESSIONE --ssadd
Aggiunta del supporto per lo stato sessione in modalità
SQLServer.
-ssremove
Rimozione del supporto per lo stato sessione in modalità
SQLServer.
-sstype t|p|c Tipo di supporto dello stato sessione:
t: temporaneo. I dati dello stato sessione vengono archiviati
nel database "tempdb", mentre le stored procedure per la
gestione della sessione vengono installate nel database
"ASPState". Se si riavvia SQL Server, i dati non vengono
mantenuti. (Impostazione predefinita)
Server side
um 95 di 243
p: persistente. Sia le stored procedure che i dati dello
stato sessione vengono archiviati nel database "ASPState".
c: personalizzazione. Sia le stored procedure che i dati
dello stato sessione vengono archiviati in un database
personalizzato. È necessario specificare il nome del
database.
-d <database> Nome del database personalizzato da utilizzare se -sstype è
"c".
Si crea un nuovo DB chiamato ASPNETDB contenente le tabelle e le SP necessarie per la
corretta gestione delle credenziali.
Server side
um 96 di 243
VISUAL STUDIO
INTRODUZIONE
Prima di avviare un qualsiasi progetto web, è importante la scelta degli strumenti
più adatti per raggiungere i propri obiettivi.
La soluzione di scrivere da zero l’intero codice è inefficiente e richiede un notevole
dispendio di tempo e risorse.
Per fortuna, è possibile evitare di “reinventare la ruota”, ricorrendo a strumenti che
forniscano il codice comune e indispensabile alla maggior parte dei progetti.
È possibile creare un sito web oppure un progetto web, in base a questa scelta cambia il
modello di compilazione e di distribuzione.
Il progetto web è da preferire perché gestisce in maniera più rigorosa il ciclo di sviluppo.
Server side
um 97 di 243
SITO WEB
Per creare un nuovo sito web, fare clic su File/Nuovo/Sito web… (MAIUSC+ALT+N).
Nella finestra di dialogo Nuovo sito Web selezionare Modelli/Visual C#/Sito Web
ASP.NET vuoto, scegliere il Percorso Web: Filesystem C\INETPUB\WWWROOT.
Per distribuire il sito web, è necessario copiare tutti i file all’interno del percorso, in questo
caso, è possibile fare una modifica ad un singolo file senza la necessità di caricare l’intera
applicazione ma applicando le sole modifiche.
Il progetto web necessita, viceversa, di una compilazione per ogni modifica che è fatta,
inoltre è necessario copiare tutti i file, a esclusione di quelli con estensione CS il cui
contenuto è compilato automaticamente.
In entrambi i casi, la cartella BIN contiene tutti gli assembly generati da Visual Studio che
sono utilizzati all’interno dell’applicazione.
APP_CODE
Memorizza classi in formato sorgente, da compilare al volo insieme all’applicazione,
supporta un solo linguaggio per volta.
APP_DATA
Contiene file di dati, per esempio TXT, DB o XML, in pratica è una cartella pensata per
contenere file che sono protetti dal download ma che si possono sfruttare nelle pagine.
APP_THEMES
Include i file legati ai temi.
APP_WEBREFERENCES
Include i file generati per l’utilizzo delle reference di WS.
APP_LOCALRESOURCE
Contiene i file di risorse che sono locali alle singole pagine web.
APP_GLOBALRESOURCE
Contiene le risorse globali cui hanno accesso tutte le componenti dell’applicazione.
Server side
um 98 di 243
PROGETTO WEB
Per creare un nuovo progetto, fare clic su File/Nuovo/Progetto… (CTRL+MAIUSC+N).
Nella finestra di dialogo Nuovo Progetto selezionare Altri linguaggi/Visual C#/Web,
quindi selezionare il tipo di applicazione, Applicazione Web ASP.NET vuota.
Immettere il nome del progetto nel campo Nome:, per esempio WebForm, quindi per
creare il progetto, premere OK.
Fare clic destro in Esplora soluzioni sul nome del progetto, dal menu contestuale
selezionare Aggiungi/Nuovo elemento… (CTRL+MAIUSC+A).
Alla voce Visual C# selezionare Web/Web Form.
File WEBFORM1.ASPX
Selezionare il menu Visualizza/Finestra di progettazione (MAIUSC+F7), si apre l’editor
visuale della pagina web in modo Progettazione.
Dalla Casella degli strumenti trascinare nella finestra Progettazione un’etichetta e un
pulsante, la pagina di markup è la seguente.
Server side
um 99 di 243
Nella finestra Proprietà sono visualizzate le proprietà dell’oggetto.
Selezionare il modo Origine per visualizzare il codice HTML.
L’attributo runat="server" indica che la pagina è eseguita server side: s’istruisce il server
che, alla pressione del pulsante, quando sarà eseguito il PostBack della pagina,
dev’essere richiamato il metodo btnPremi_Click contenuto nel code-behind.
L’etichetta è rappresentata dal TAG Label, ha una proprietà ID che serve a identificare
univocamente il controllo all’interno della pagina corrente e la proprietà Text che assume
per default lo stesso valore del TAG ID.
Il pulsante è rappresentato dal TAG Button, ha una proprietà ID.
Per l’etichetta, assegnarle l’ID lblVisualizza, cancellare il valore della proprietà Text
lasciando una stringa vuota.
Per il pulsante, assegnargli l’ID btnPremi, cancellare il valore della proprietà Text e inserire
la stringa "Premi".
Fare doppio clic sul pulsante, nella pagina di markup, all’interno del TAG Button è
aggiunto il comando seguente.
<asp:Button ID="btnPremi" runat="server" Text="Premi" OnClick="btnPremi_Click" />
File WEBFORM1.ASPX.DESIGNER.CS
Il controllo è inserito automaticamente.
protected global::System.Web.UI.WebControls.Button btnPremi;
File WEBFORM1.ASPX.CS
Contiene il code-behind della pagina, questa caratteristica è molto importante: tutto il
codice degli script della pagina che in genere è immerso all'interno dell'HTML, ora può
risiedere in un file separato, consentendo una separazione tra grafica e codice.
Nella finestra del code-behind dove c’è il codice relativo all’evento associato al pulsante.
protected void btnPremi_Click(object sender, EventArgs e)
{ lblVisualizza.Text = "Ciao, mondo!"; }
Server side
um 100 di 243
Quando l’utente clicca sul pulsante è valorizzata l’etichetta.
Compilare il progetto, fare clic su Debug/Avvia senza eseguire debug (CTRL+F5).
È avviato il server web integrato in Visual Studio e l’applicazione ASP.NET sarà
visualizzata all'interno del browser web predefinito.
File WEB.CONFIG
Il comportamento di un’applicazione ASP.NET può essere personalizzato mediante l’uso
di questo file di configurazione, in formato XML.
È possibile avere un file WEB.CONFIG diverso in ciascuna cartella del sito: ognuno di essi
applica le impostazioni di configurazione sulla propria cartella e su tutte le sotto cartelle.
I file di configurazione nelle sotto cartelle possono stabilire configurazioni aggiuntive a
quelle ereditate dalla cartella padre oppure possono sostituire o modificare quelle definite
nei livelli superiori.
Un file WEB.CONFIG può contenere vari tipi di informazioni.
 Variabili comuni a tutte le pagine.
 Configurazioni per le sessioni.
 Opzioni per la gestione degli errori.
 Informazioni per la sicurezza.
In fase di progettazione, la proprietà debug dev’essere true.
In fase di pubblicazione, la proprietà debug dev’essere false.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.5.1" />
<httpRuntime targetFramework="4.5.1" />
</system.web>
</configuration>
Sostanzialmente se la proprietà debug è impostata a true.
 La compilazione è più lenta in quanto le ottimizzazioni sono disabilitate.
 Tutti gli script e le immagini non sono inserite nella cache del client.
 Si verifica un maggior consumo di memoria.
 Il codice gira più lentamente in quanto sono utilizzati i file di debug.
Su un server di produzione, sul quale non si effettuerà mai debug con Visual Studio,
potrebbe risultare scomodo verificare manualmente se i WEB.CONFIG di ciascuna
applicazione web ospitata hanno la proprietà debug impostata a false.
Per fare in modo, invece che la modalità debug sia disabilitata indipendentemente dalla
specifica impostazione presente eventualmente in ciascun WEB.CONFIG, si può agire
globalmente utilizzando la proprietà retail dell’elemento deployment presente nel file di
configurazione globale MACHINE.CONFIG.
<configuration>
<system.web>
<deployment retail="true"/>
</system.web>
Server side
um 101 di 243
</configuration>
L’impostazione a true di questa proprietà, oltre a disabilitare la modalità debug per tutte le
applicazioni del server indipendentemente dalle specifiche impostazioni di ciascuna,
disabilita anche tutti gli eventuali output di tracing presenti nelle pagine di tutte le
applicazioni e, inoltre, forza la visualizzazione degli errori custom al posto di quelli
generici.
Componente dinamica
Per aggiungere una componente dinamica, fare doppio clic su un punto vuoto della pagina
all’interno dell’editor, il cursore si posiziona automaticamente sul gestore dell’evento Load
che è inserito nel code-behind della pagina.
protected void Page_Load(object sender, EventArgs e)
{}
La firma dell’evento è esattamente la stessa dell’evento Load di una Windows Form.
Anche il significato è lo stesso: il codice inserito in questo metodo sarà eseguito ogni volta
che la pagina sarà caricata.
Si desidera che ogni volta che si apre o si aggiorna la pagina, l’etichetta definita in
precedenza contenga la data e l’ora dell’operazione, per fare questo si deve scrivere il
seguente codice.
protected void Page_Load(object sender, EventArgs e)
{ lblVisualizza.Text = "Ora di connessione: " + DateTime.Now;
Page.Title = "Progetto web";
}
Esecuzione dell’applicazione nel server web IIS
Copiare il file WEBFORM1.ASPX che si trova nella cartella seguente.
F:\ESERCIZI\C#\WEB\WEBFORM\WEBFORM\ WEBFORM1.ASPX
Nella cartella del server web.
C:\INETPUB\WWWROOT.
Copiare la cartella BIN che si trova nella cartella seguente.
F:\ESERCIZI\C#\WEB\WEBFORM\WEBFORM\BIN
Nella cartella BIN del server web.
C:\INETPUB\WWWROOT\BIN.
Server side
um 102 di 243
File GLOBAL.ASAX
Oltre a WEB.CONFIG, ad un sito ASP.NET può essere aggiunto questo file che risiede
nella cartella principale del sito ed è un contenitore di codice comune all’applicazione.
È impiegato per eseguire operazioni all’avvio, al termine delle sessioni e dell’applicazione,
inoltre, esegue del codice al verificarsi di una condizione di errore.
Per inserire il file GLOBAL.ASAX, fare clic con il tasto destro del mouse sul nome del
progetto in Esplora soluzioni e selezionare la voce Aggiungi/Nuovo elemento….
Si apre una finestra di dialogo in cui sono mostrati tutti i tipi di file che possono essere
aggiunti, selezionare Classe di applicazione globale.
Ha il codice seguente già inserito e include già le dichiarazioni per gli event handler che
possono essere definiti.
using System;
namespace WebForm {
public class Global : System.Web.HttpApplication {
protected void Application_Start(object sender, EventArgs e)
{ }
protected void Session_Start(object sender, EventArgs e)
{ }
protected void Application_BeginRequest(object sender, EventArgs e)
{ }
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{ }
protected void Application_Error(object sender, EventArgs e)
{ }
protected void Session_End(object sender, EventArgs e)
{ }
protected void Application_End(object sender, EventArgs e)
{ }
}
}
Navigazione
Si usa l’oggetto seguente con la proprietà NavigateUrl.
<asp:HyperLink ID="hplPagina" runat="server" NavigateUrl="~/Pagina2.aspx">Vai alla
pagina numero 2</asp:HyperLink>
Server side
um 103 di 243
WEB FORM
PAGINA
Una Web Form differisce da una Windows Form perché utilizza controlli differenti, chiamati
Web Controls e perché, a differenza di quest’ultima, produce HTML e codice eseguito
server side.
I Web Controls sono raggruppati in categorie nella Casella degli strumenti.
BulletedList
Uno degli elementi più comuni delle pagine web è l’elenco puntato.
È un controllo server che permette di ottenere elenchi puntati o ordinati, sfruttando in fase
di rendering i TAG <ul> e <ol>.
Può essere costruito sia specificando un insieme di elementi ListItem sia sfruttando il databinding.
Tramite la proprietà BulletStyle è possibile settare lo stile dell’elemento grafico posto
davanti al testo, cerchietti, dischetti, quadratini, immagini custom, lettere e numeri.
<asp:BulletedList Runat="server" ID="Sample" BulletStyle="Square">
<asp:ListItem>Primo elemento</asp:ListItem>
<asp:ListItem>Secondo elemento</asp:ListItem>
<asp:ListItem>Terzo elemento</asp:ListItem>
</asp:BulletedList>
FileUpload
Rappresenta una valida alternativa al controllo HTML pre esistente.
Internamente il controllo utilizza la collection Request.Files di tipo HttpFileCollection e da
essa recupera il file caricato sul server di tipo HttpPostedFile.
HiddenField
È renderizzato come un TAG <input type="hidden"> e la sua utilità è quella di
memorizzare informazioni di stato, in alternativa, per esempio, al ViewState all’atto di
eseguire un post.
HiddenField fornisce l’evento ValueChanged che è scatenato quando il valore associato al
controllo è ritornato al server modificato.
Server side
um 104 di 243
ImageMap
Permette di trasformare un’immagine in un menu di navigazione cliccabile, definendo
tramite coordinate geometriche alcune aree sensibili, HotSpot, alle quali può essere
associato un diverso comportamento all’atto del clic.
Principalmente i comportamenti possono essere due.
1. L’area funge da link ad un URL modalità HotSpotMode.Navigate.
2. Il clic sull’area produce un PostBack modalità HotSpotMode.PostBack.
Le aree sensibili di un controllo ImageMap possono essere rettangolari, circolari o
poligonali.
In fase di rendering il controllo è trasformato in una mappa client TAG <map>, per la quale
sono definite le aree cliccabili tramite altrettanti TAG <area>.
<asp:ImageMap Runat="server" ID="Sample" ImageUrl="Sample.jpg" Width="300"
OnClick="Sample_Click" HotSpotMode="PostBack">
<asp:RectangleHotSpot Top="0" Bottom="225" Left="0" Right="150"
AlternateText="Area 1" PostBackValue="Area1"></asp:RectangleHotSpot>
<asp:RectangleHotSpot Top="0" Bottom="225" Left="151" Right="300"
AlternateText="Area 2" PostBackValue="Area2"></asp:RectangleHotSpot>
</asp:ImageMap>
MultiView e View
MultiView definisce un insieme di viste rappresentate da una collezione di tipo
ViewCollection, di queste viste solamente una è riconosciuta come attiva per il controllo ed
è renderizzata sul client.
Il controllo ingloba tutti i meccanismi per poter commutare da una vista ad un’altra, grazie
alla proprietà ActiveViewIndex e all’evento SetActiveView.
<asp:MultiView Runat="server" ID="Sample">
<asp:View Runat="Server" ID="View1">...</asp:View>
<asp:View Runat="Server" ID="View2">...</asp:View>
<asp:View Runat="Server" ID="View3">...</asp:View>
</asp:MultiView>
Wizard
Permette di costruire una sequenza di schermate da mostrare in successione all’utente
finale.
In realtà è un controllo composito che al suo interno utilizza un controllo MultiView per
mostrare i vari passi della sequenza che quindi non sono altro che controlli View in quanto
WizardStepBase deriva dal tipo View.
Il controllo mette a disposizione i pulsanti di avanzamento, Avanti, Indietro, Fine, Annulla e
sfrutta eventi server side per gestire la navigazione ogni volta che l’utente decide di
cambiare schermata.
È possibile navigare sia in modo lineare sia in modo casuale, saltando da un passo ad un
altro.
<asp:Wizard Runat="server" ID="Sample" SideBarEnabled="True" ActiveStepIndex="0">
<WizardSteps>
<asp:WizardStep Runat="server" Title="Primo passo">Primo
passo</asp:WizardStep>
<asp:WizardStep Runat="server" Title="Secondo passo">Secondo
passo</asp:WizardStep>
<asp:WizardStep Runat="server" Title="Terzo passo">Terzo
passo</asp:WizardStep>
</WizardSteps>
Server side
um 105 di 243
</asp:Wizard>
La pagina ASP.NET ha estensione ASPX e quando si richiede parte il worker process
ASPNET_WP.EXE.
È suddivisa in due parti.
1. Markup.
2. Codice: con estensione ASPX.CS.
La prima richiesta ad una pagina è leggermente più lenta delle successive, perché c’è un
overhead aggiunto dalla fase di compile-time.
Durante questo momento, infatti, è richiamato il compilatore specifico per il linguaggio
utilizzato e tutto il codice presente nella pagina, sia sotto forma di codice sia di HTML, è
convertito in una classe ed è creato un assembly DLL (Dynamic Link Library)
corrispondente alla pagina che è chiamato con il nome della stessa.
Fino ad un’eventuale modifica o riavvio del processo, ASP.NET continuerà ad utilizzare la
versione già compilata delle pagina, con un accesso alla stessa istantaneo.
Il meccanismo di compilazione incrementa le performance dell’applicazione web, perché le
richieste sono tenute, già compilate in assembly, all’interno di un percorso ben definito sul
disco eseguite in MSIL (MicroSoft Intermediate Language) dal JIT.
Nella compilazione nell’assembly corrispondente sono però racchiusi più passaggi.
1. Sono individuate tutte le dipendenze con eventuali classi esterne.
2. È invocato il compilatore specifico per il linguaggio utilizzato nella pagina.
3. È generato un assembly e salvato su disco, in una cartella temporanea, per essere
riutilizzato.
Le pagine non sono altro che classi ed ereditano le funzionalità di base dalla classe Page
come una Windows Form eredita dalla classe Form.
Page si trova nel namespace System.Web.UI.Page e contiene al proprio interno la logica
necessaria a far funzionare una pagina HTML, per esempio l’invio del codice al client e il
recupero delle informazioni.
La modalità code-behind che separa codice da contenuto, sfrutta proprio questa
caratteristica per creare la pagina, in un file separato, una classe a tutti gli effetti da cui poi
la pagina vera e propria eredita.
Metodi di base
Sono agganciati attraverso HttpContext, una classe istanziata da HttpRuntime che espone
verso la pagina l’accesso a querystring e form, i principali metodi sono i seguenti.
Response
Fornisce un ponte verso la classe HttpResponse che implementa le funzionalità di output
verso il client.
Request
Si aggancia alla classe HttpRequest, utilizzata per recuperare informazioni dal client.
Server
Sfrutta HttpServerUtility per fornire funzionalità di uso comune alla pagina.
Session
Fornisce un ponte verso la classe HttpSessionState che contiene le funzionalità
necessarie alla gestione dello stato della sessione.
Application
Si aggancia a HttpApplicationState, per fornire la logica di accesso allo stato
Server side
um 106 di 243
dell’applicazione.
EVENTI
Come tutti gli oggetti, anche la classe Page può avere degli eventi che si verificano in
seguito ad un comportamento del client e che possono essere di natura automatica o
associati a particolari condizioni.
Come è possibile avere eventi in un’applicazione web che è senza stato?
Dopo tutto una pagina web comincia la sua vita non appena il client la richiede, per morire
quando il suo risultato è inviato al client.
ASP.NET sfrutta questo concetto: tutti gli eventi si verificano sul server ma sono invocati
dal client, in pratica non fa altro che rendere più semplice, per chi scrive codice, pensare
ad eventi, sfruttando però del normale codice JavaScript per fare il submit di un form,
passando i dati necessari a far eseguire il codice server side.
Da parte del programamtore non è necessario scrivere codice JavaScript, perché la
pagina è in grado di fornire la struttura di base sulla quale operare e che si occuperà di
fornire il substrato necessario all’invocazione degli eventi.
Sono scatenati all’interno di una pagina, nell’ordine in cui sono intercettati.
Page_PreInit
Si verifica prima dell’inizializzazione della pagina, serve per impostare Master Page e
theme.
Page_Init
Si verifica all’inizializzazione della classe rappresentata dalla pagina ed è, di fatto, il primo
vero evento.
Page_InitComplete
Si verifica subito dopo l’evento INIT.
Page_LoadState
Segna il caricamento dello stato della pagina e dei controlli dal ViewState.
Page_PreLoad
Si verifica prima del caricamento della pagina.
Page_Load
Si verifica al caricamento della pagina, successivamente all’inizializzazione.
Page_LoadComplete
Si verifica subito dopo l’evento LOAD.
Page_PreRender
Si verifica subito prima del rendering della pagina.
Page_Render
Si verifica al rendering della pagina e segna la generazione del codice HTML associato.
Page_SaveState
Salva lo stato dei controlli all’interno del ViewState.
Page_UnLoad
Si verifica allo scaricamento dell’istanza della pagina, non corrisponde al metodo Dispose
perché questo è gestito dal GC (Garbage Collector).
Server side
um 107 di 243
Page_Error
Si verifica in caso di errore non gestito all’interno della pagina e può essere sfruttato per
visualizzare un avviso all’utente o registrare la causa del fallimento dell'esecuzione.
POSTBACK
Nella programmazione web si ragiona con questa logica Form->Post->Action.
L’idea è che un form posizionato in una pagina ASP passa dei dati ad una seconda pagina
tramite un POST generato dalla pressione di un pulsante.
La seconda pagina preleva poi i dati e li utilizza per i propri scopi.
ASP.NET fornisce all’utente un frameWork che consente di astrarsi da queste conoscenze
e utilizzare direttamente controlli e programmazione ad eventi.
Progettare un’applicazione web in modo che l’utente possa digitare il proprio nome e,
premendo un pulsante, riceva un messaggio di saluto.
Impostare le proprietà degli oggetti.
lblNome
txtNome
btnConferma
lblSaluto
Label
TextBox
Button
Label
Text = Nome:
Text = Conferma
Text = Ciao, mondo
File WEBFORM1.ASPX
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs"
Inherits="WebApplication1.WebForm1" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>PostBack & ViewState</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Label ID="lblNome" runat="server" Text="Nome:"></asp:Label>
&nbsp;
<asp:TextBox ID="txtNome" runat="server"></asp:TextBox>
&nbsp;&nbsp;
<asp:Button ID="btnConferma" runat="server" OnClick="btnConferma_Click"
Text="Conferma" />
<br />
<br />
<asp:Label ID="lblSaluto" runat="server" Text="Ciao, mondo!"></asp:Label>
</div>
</form>
Server side
um 108 di 243
</body>
</html>
Quando la pagina è caricata all’interno del browser, è generato l’evento Page_Load.
Nel codice del delegate per Page_Load è possibile verificare se l’utente sta effettuando il
primo accesso alla pagina oppure sta effettuando un PostBack.
La tecnica del PostBack è quella che consente ad una pagina web di trasmettere a se
stessa delle informazioni di stato.
In pratica, in una pagina web dinamica è creato un form che ha come campo action
l’indirizzo della pagina stessa e al suo interno dei campi nascosti che mantengono
informazioni sullo stato della pagina.
Per esempio si può avere un campo che contiene il testo di una casella di testo.
Sono usati campi nascosti per ricordare se includere una porzione di codice o meno.
Queste informazioni una volta generato un evento submit che non necessariamente
scaturisce da un pulsante, sono rispedite indietro alla pagina che le usa per modificare il
suo aspetto.
La proprietà IsPostBack restituisce il valore true quando il modulo presente nella pagina è
stato eseguito, false quando si tratta del primo accesso alla pagina.
File WEBFORM1.ASPX.CS
using System;
using System.Web.UI;
namespace WebApplication1 {
public partial class WebForm1 : System.Web.UI.Page {
protected void Page_Load(object sender, EventArgs e)
{ if (Page.IsPostBack) {
// la pagina è stata già processata
// è stato sollevato qualche evento che ha provocato un PostBack
}
else {
// primo caricamento della pagina
}
}
Sono continui scambi d’informazioni tra il browser e il server, per esempio un doppio clic
su un pulsante genera due chiamate al server.
In caso di transazioni complesse una continua pressione del pulsante potrebbe mandare
in timeout il server.
Allora bisogna disabilitare il pulsante dopo che l’utente lo ha cliccato tramite la proprietà
Attributes dell’oggetto Button e il relativo metodo Add che accetta due parametri.
1. Il nome dell’attributo che sarà aggiunto al TAG HTML.
2. Il nome della funzione o il codice client script che sarà eseguito dal pulsante.
btnConferma.Attributes.Add("onclick", "this.disabled = true;");
Dopo aver chiamato la pagina, quest’istruzione è convertita nel seguente codice HTML.
<input type="submit" name="btnConferma" value="Ricerca"id=" btnConferma"
onclick="this.disabled = true;" />
Premendo il pulsante sulla pagina web il suo stato passa in disabilitato e non è più
eseguito il PostBack verso il server.
Quindi non è più eseguito lo script lato server contenuto nell’evento clic del pulsante.
Per ovviare a questo malfunzionamento occorre aggiungere una chiamata al metodo
Server side
um 109 di 243
GetPostBackEventReference all’interno della classe Page.
Questo metodo restituisce il codice JavaScript necessario a fare il submit della pagina,
ovvero a contattare il server per fornirgli i dati contenuti nella pagina.
Si possono utilizzare i metodi e le proprietà di questa classe in quanto ogni pagina
ASP.NET crea una classe derivandola da Page.
String strScript = "this.disabled = true;";
strScript += Page.GetPostBackEventReference(btnConferma);
btnConferma.Attributes.Add("onclick", strScript);
Nel metodo bisogna utilizzare un parametro per specificare il controllo al quale associare
la chiamata PostBack verso il server.
Ecco come sarà convertito il nuovo codice in HTML completo delle funzioni di PostBack.
<input type="submit" name=" btnConferma " value="Ricerca" id=" btnConferma "
onclick="this.disabled = true; __doPostBack('btnRicerca', '');" />
Quando si preme sul pulsante di conferma, in automatico, è fatto un invio del form.
Quest’azione si chiama PostBack, perché il form è nuovamente inviato a se stesso.
In altre parole, il PostBack si verifica esattamente ogni volta che il client invia il controllo al
server al seguito di un’azione compiuta dall’utente sulla pagina.
È questo il motivo per cui con ASP.NET si fa pochissimo uso dell’oggetto Request, dato
che si può direttamente accedere alla proprietà che contiene il testo del controllo.
Per scatenare il PostBack, ASP.NET utilizza due campi nascosti all’interno del form che
automaticamente aggiunge alle pagine che indicano rispettivamente il controllo che ha
scatenato il PostBack e i parametri da passare.
Queste informazioni serviranno ad ASP.NET per ricostruire l’evento scatenato dall’utente
associato al controllo.
__EVENTTARGET
__EVENTARGUMENT
Con quest’operazione, ASP.NET riceve nuovamente la pagina e capisce che c’è da
intercettare l’evento clic, richiamando l’event handler specificato nel markup, definito con
l’attributo OnClick.
protected void btnConferma_Click(object sender, EventArgs e)
{ lblSaluto.Text = "Il tuo nome è " + txtNome.Text; }
}
}
Eseguito nel browser, questo codice genera la schermata seguente.
Server side
um 110 di 243
Visualizzare il sorgente della pagina all’interno del browser web, ad esempio, in IExplorer,
con il comando Visualizza/Origine.
Si vede che tutto il codice ASP.NET è stato tradotto in HTML standard.
Non c’è però traccia del codice dello script, esso, in modo del tutto invisibile, è stato
compilato in una libreria che risiede sul server e che è richiamata ogni volta che si effettua
il post della pagina.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>PostBack & ViewState</title>
</head>
<body>
<form method="post" action="WebForm1.aspx" id="form1">
<div class="aspNetHidden">
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE"
value="vjQaB82JZxbWmzxEDPGVWhTKqamnYE4KgzSux/jxrWm5CxRNT8a3aKuURHKc
mAeF4Z7veDIU6Fzo14RRn5QbMgcItUjf5yLdy1oWdiUlPruIyUYTgasMaYmoya++VVfFWs
QVMFvHW1Ayxsfj4J9Kw+vwYPikFa1YmVn1r0OYUg8=" />
</div>
<div>
<span id="lblNome">Nome:</span>
&nbsp;
<input name="txtNome" type="text" value="Andrea" id="txtNome" />
&nbsp;&nbsp;
<input type="submit" name="btnConferma" value="Conferma" id="btnConferma" />
<br />
<br />
<span id="lblSaluto">Il tuo nome è Andrea</span>
</div>
<div class="aspNetHidden">
<input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION"
value="9Y1S/98Im9RB7OHBBrAG7hrH9Oq3n3AX3/DExCUT8yG9IBkqnIqfTcyIQ1YIJ7Rt3
jm8UJh7VZeUn/t5NxWfV0U0rAqIpNXY3zWoLp0+Y+3NPyahiKw1VVf41d1v0fKEuJX3YIO
oBKHKei7CB46kvw==" />
</div></form>
<!-- Visual Studio Browser Link -->
<script type="application/json" id="__browserLink_initializationData">
{"appName":"Internet Explorer","requestId":"bf0cdea20c904977b4e6f09aa80ce557"}
</script>
<script type="text/javascript"
src="http://localhost:49216/759a4a15f8834677b4d38141d5a000d6/browserLink"
async="async"></script>
<!-- End Browser Link -->
</body>
</html>
La TextBox ha mantenuto lo stato senza che il programmatore dovesse effettivamente
gestirlo manualmente, questa caratteristica fa parte dell’infrastruttura ASP.NET e si
chiama ViewState.
ACCESSO AI META TAG
ASP.NET mette a disposizione due proprietà della classe Page che consentono di avere
Server side
um 111 di 243
un controllo maggiore sui meta TAG inseriti nella pagina quando questa è convertita in
HTML.
Le due proprietà sono MetaKeywords e MetaDescription e dal nome, consentono
rispettivamente di valorizzare il meta TAG Keywords e il meta TAG Description della
pagina.
Queste due proprietà sono di tipo String e possono essere impostate sia
dichiarativamente.
<%@ Page MetaKeywords="key1,key2, key3" %>
<%@ Page MetaDescription="Descrizione della pagina" %>
Sia da code-behind.
Page.MetaKeywords ="key1, key2, key3";
Page.MetaDescription ="Descrizione della pagina";
CONTROLLI
Se la Web Form è il contenitore, gli oggetti contenuti all’interno di quest’ultima sono
chiamati controlli, producono, come output, codice HTML, anche se la loro dichiarazione
all’interno della pagina ha una sintassi differente da quello che potrebbe essere un TAG.
Ci sono due grandi famiglie di controlli, divisi in base alle funzionalità che implementano.
Web controls
Hanno il prefisso <asp> e la sintassi che li contraddistingue è di tipo XML.
Questo prefisso è, in genere, riservato ai controlli disponibili all’interno di ASP.NET,
mentre il suffisso è il nome vero e proprio della classe che sarà istanziata.
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
HTML controls
Appartengono tutti i TAG HTML cui è aggiunto l’attributo runat = "server", ASP.NET li usa
per mappare gli oggetti della pagina sulle istanze di classi che poi andrà a creare, in fase
di compile-time.
Questa caratteristica, applicata ai frammenti di codice HTML, li rende controlli server che
producono un markup e sono in grado di fornire un comportamento.
<form id="form1" runat="server">
I web control hanno un modello a oggetti che rende controlli molto diversi nel markup ma,
in realtà, molto simili nel modello a oggetti.
Gli HTML control hanno un modello a oggetti che ricalca quello dei TAG HTML cui si
riferiscono.
La differenza tra queste due famiglie è che i primi ricordano, nel nome, i controlli per
Windows e s’inseriscono all’interno delle pagine con una sintassi diversa dal
corrispondente codice HTML generato, mentre i secondi permettono di utilizzare un TAG
HTML sfruttandone la possibilità di essere trattato come oggetto e quindi di accedere in
maniera programmatica alle sue funzionalità.
I web control offrono un insieme coerente di proprietà, in modo che la stessa funzionalità
implementata su controlli differenti mantenga lo stesso nome all’interno di tutto il
framework.
Tanto i web control, quanto gli HTML control, producono alla fine codice HTML grazie al
componente page parser.
Il page parser garantisce che i programmatori possono scrivere il markup nel modo
Server side
um 112 di 243
classico ma che, contestualmente, a run-time i frammenti sono automaticamente tradotti in
codice.
Il vantaggio è di poter scrivere l’interfaccia in modo semplice e veloce sfruttando le stesse
funzionalità delle applicazioni Windows, con il risultato di poter programmare i controlli
posizionati nella pagina, impostandone le proprietà e, soprattutto, potendone gestire gli
eventi associati agli oggetti della pagina.
La Casella degli strumenti contiene gli oggetti attraverso i quali il programmatore
costruisce le Web Form e l’utente interagisce con la pagina.
Dati: sono controlli con funzionalità avanzate.
Convalida: sono controlli per la validazione dell’input, hanno una forte componente client.
HTML: sono elementi HTML esposti lato server.
Controllo Wizard: consente di strutturare una serie di passaggi da far compiere all’utente.
Controlli container: funzionano da contenitore, in pratica possono raggruppare altri
controlli e, se implementano l’interfaccia INamingContainer, assicurano agli stessi che il
loro ID sarà generato univocamente.
Un controllo contenuto in un container non è direttamente accessibile utilizzando l’ID,
come si fa con un controllo contenuto in una pagina ma va ricercato all’interno dell’albero
dei controlli che contiene tutta la struttura della pagina, usando il metodo FindControl sul
contenitore.
Il controllo PlaceHolder permette di raggruppare e nascondere o visualizzare un gruppo di
controlli, senza agire singolarmente sugli stessi.
Esempio, subito dopo il clic dell’utente nascondere, contestualmente il form d’immissione
dati.
File FORM2.ASPX
<%@ Page Language="C#" CodeFile="Form2.aspx.cs" Inherits="Form2" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Esempio di contenitore</title>
</head>
<body>
<form runat="server">
<div>
<asp:PlaceHolder ID="EntryForm" runat="server">Inserisci il tuo nome:
Server side
um 113 di 243
<asp:TextBox ID="txtNome" runat="server" />
<br />
<asp:Button ID="btnConferma" runat="server" Text="Conferma"
OnClick="VisualizzaNome" />
</asp:PlaceHolder>
<asp:PlaceHolder ID="Results" runat="server" Visible="false">
Il tuo nome è
<asp:Literal ID="lblNome" runat="server" />
</asp:PlaceHolder>
</div>
</form>
</body>
</html>
File FORM2.ASPX.CS
using System;
using System.Web.UI;
public partial class Form2 : Page {
protected void VisualizzaNome(object sender, EventArgs e)
{ EntryForm.Visible = false;
Results.Visible = true;
lblNome.Text = txtNome.Text;
}
}
Server side
um 114 di 243
PASSAGGIO D’INFORMAZIONI
CICLO DI VITA
Un utente richiede una pagina ASPX tramite il browser, in tre modi.
1. Digita l’URL nel browser.
2. Fa clic su un link: è una richiesta HTTP di tipo GET.
3. Fa clic su un pulsante: è una richiesta HTTP di tipo POST.
La pagina esegue un’elaborazione, compilazione ed esecuzione sul server web che
termina con la restituzione di una risposta HTTP al browser.
All’interno della risposta HTTP si trova la pagina in formato HTML con i dati frutto
dell’elaborazione.
Ogni volta che è fatta una nuova richiesta HTTP su una pagina sono perse tutte le
informazioni in essa contenute.
Per ovviare a questo inconveniente, ASP.NET mette a disposizione diversi meccanismi
per preservare i dati tra un PostBack e l’altro, divisi in due gruppi.
1. MECCANISMI DI CONSERVAZIONE DEI DATI LATO CLIENT
I meccanismi 1, 2 e 4 permettono di riutilizzare i dati solo se si rimane nella stessa pagina
ma se si va su altre pagine si perde il loro contenuto.
1.1 ViewState
È una tabella associativa che contiene lo stato degli oggetti presenti nella pagina.
In pratica, consente alle pagine di mantenere lo stato dei controlli attraverso i vari
PostBack e concorre al supporto degli eventi all’interno del sistema.
In questo modo tra un PostBack e un altro i dati sono salvati e recuperati da questo
contenitore che è implementato come campo nascosto dalla Web Form.
__VIEWSTATE
Se ad esempio s’implementa un sistema di validazione dell’input dell’utente, non ci si deve
preoccupare di mantenere il valore dei campi presenti sulla pagina, perché il ViewState se
ne occupa direttamente per noi.
HTTP è un protocollo stateless, senza stato, ovvero non mantiene le informazioni sullo
stato di una pagina tra una visita e l’altra.
Per sopperire a tale mancanza, ASP.NET utilizza il campo ViewState.
Ogni volta che si ricarica una pagina, i controlli in essa presenti sono inizializzati sulla
base del contenuto del ViewState che è generato automaticamente da ASP.NET.
Questa soluzione consente di trasferire lo stato dei controlli dal server al client e viceversa.
Ciò significa che quando il server leggerà il ViewState di una pagina sarà in grado di
ripristinare, ad esempio, il valore corrente di tutti i campi input, senza bisogno che sia il
programmatore a farlo via codice.
Trattandosi di una tabella associativa, inoltre, nel ViewState è possibile inserire anche dei
valori personalizzati.
Esempio, memorizzare il numero di volte in cui il pulsante btnConferma è stato premuto.
protected void btnConferma_Click(object sender, EventArgs e)
{ int click;
if (ViewState["click"] == null)
click = 1;
else
Server side
um 115 di 243
click = (int)ViewState["click"] + 1;
lblSaluto.Text="Il tuo nome è " + txtNome.Text + ", hai premuto " + click + " volte";
ViewState["click"] = click;
}
Si legge il valore associato alla chiave click nel ViewState: se non è stato ancora
inizializzato, ovvero vale null, significa che questa è la prima pressione del pulsante,
altrimenti s’incrementa il valore in esso contenuto.
Dopo aver stampato il numero di clic, si aggiorna il contenuto del ViewState, ad ogni
pressione del pulsante il numero stampato aumenterà.
Il ViewState è mantenuto solo se sono eseguite richieste consecutive della stessa pagina,
nel caso in cui sia caricata una nuova pagina, il ViewState sarà perso.
Per mantenere le informazioni durante la navigazione, si usa l’oggetto Session.
È possibile abilitare/disabilitare il ViewState di un controllo impostando la sua proprietà
EnableViewState oppure intervenire a livello di pagina con la direttiva seguente.
<%@ Page EnableViewState = "False" %>
È possibile salvare/prelevare variabili di ogni tipo del ViewState a livello di code-behind,
per questo motivo è necessario fare il cast con il tipo corrispondente quando si prelevano.
// salvo i dati nel ViewState: contenuto della proprietà Text di una Label
this.ViewState["ora_iniziale"] = lblOra.Text;
// prelevo i dati dal ViewState
string ora = (string) this.ViewState["ora_iniziale"];
1.2 Hidden fields
Sono come caselle di testo ma non sono visibili sulla pagina, ASP.NET li usa per
memorizzare il ViewState, il programmatore li usa tramite code-behind.
// definizione nella pagina di markup
<asp:HiddenField ID =" HiddenField1" runat "server" Value "pluto" />
// utilizzo lato code-behind
HiddenField1.Valure = "pippo";
1.3 Querystring
È un’informazione appesa alla fine di un URL, comincia con un (?) ed è costituita da
coppie attributo/valore separate da (&), utile per passare informazioni tra pagine; è buona
regola crittografare il contenuto perché viaggia in chiaro.
È il caso di più pagine web che si richiamano tra di loro e che si passano informazioni.
Il richiamo di una pagina avviene utilizzando il metodo Redirect della classe Response.
Server side
um 116 di 243
Response.Redirect ("pagina.aspx");
In ASP.NET ci sono diverse possibilità.
1. Impostazione di una stringa di query.
2. Cookie.
3. Sessione.
4. Applicazione.
L’impostazione di una stringa di query, è il metodo più semplice e prevede l’inserimento
delle informazioni all’interno dell’URL della pagina cui si è reindirizzati.
Esempio, costruire una pagina in cui dopo aver richiesto il nome e il cognome di un utente
richiama un’altra pagina che visualizza un messaggio.
File RICHIESTA.ASPX
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="richiesta.aspx.cs"
Inherits="query.richiesta" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>Richiesta</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Label ID="lblnome" runat="server" Text="Inserisci il nome:"></asp:Label>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <asp:TextBox ID="txtNome"
runat="server"></asp:TextBox>
<br />
<br />
<asp:Label ID="lblCognome" runat="server" Text="Inserisci il
cognome:"></asp:Label>
&nbsp; <asp:TextBox ID="txtCognome" runat="server"></asp:TextBox>
<br />
&nbsp;<br />
<asp:Button ID="btnConferma" runat="server" Text="Invia informazioni"
OnClick="btnConferma_Click" />
<br />
Server side
um 117 di 243
</div>
</form>
</body>
</html>
File RICHIESTA.ASPX.CS
using System;
using System.Web;
namespace query {
public partial class richiesta : System.Web.UI.Page {
protected void Page_Load(object sender, EventArgs e)
{ }
protected void btnConferma_Click(object sender, EventArgs e)
{ string query;
if (txtNome.Text != "" || txtCognome.Text != "") {
query = txtNome.Text + " " + txtCognome.Text;
Response.Redirect("visualizza.aspx?nome=" + query);
}
}
}
}
File VISUALIZZA.ASPX
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="visualizza.aspx.cs"
Inherits="query.visualizza" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>Visualizza</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Label ID="lblMessaggio" runat="server"></asp:Label>
</div>
</form>
</body>
</html>
Server side
um 118 di 243
File VISUALIZZA.ASPX.CS
using System;
namespace query {
public partial class visualizza : System.Web.UI.Page {
protected void Page_Load(object sender, EventArgs e)
{ lblMessaggio.Text = "Benvenuto in questa pagina: "+
Request.QueryString["nome"];
}
}
}
1.4 Cookies
Sono file di testo che risiedono sul PC dell’utente, nei quali si possono memorizzare i dati,
permettono di riutilizzare i dati su più pagine.
È salvato automaticamente e in modo trasparente per l’utente nella memoria del browser
se le informazioni in esso contenute sono temporanee.
È salvato automaticamente e in modo trasparente per l’utente sul disco se le informazioni
in esso contenute sono di più lunga durata che è stabilita con il metodo Expires.
Esempio, costruire una pagina in cui dopo aver richiesto il nome e il cognome di un utente
richiama un’altra pagina che visualizza un messaggio.
File RICHIESTA.ASPX.CS
using System;
using System.Web;
namespace query {
public partial class richiesta : System.Web.UI.Page {
protected void Page_Load(object sender, EventArgs e)
{ }
protected void btnConferma_Click(object sender, EventArgs e)
{ HttpCookie prova;
if (txtNome.Text != "" || txtCognome.Text != "") {
prova = new HttpCookie("ASP.NET");
// inserire una variabile con un dato valore
Response.Cookies["nome"].Value = txtNome.Text + " " + txtCognome.Text;
/* aggiungere il cookie creato alla collezione dei cookies della pagina web con il
* metodo Add */
Response.Cookies.Add(prova);
Response.Redirect("visualizza.aspx");
}
}
}
}
Server side
um 119 di 243
File VISUALIZZA.ASPX.CS
using System;
namespace query {
public partial class visualizza : System.Web.UI.Page {
protected void Page_Load(object sender, EventArgs e)
{ lblMessaggio.Text = "Benvenuto in questa pagina: " +
Request.Cookies["nome"].Value;
}
}
}
2. MECCANISMI DI CONSERVAZIONE DEI DATI LATO SERVER
2.1 Session
È una tabella associativa e funziona esattamente come il ViewState, tuttavia le variabili
archiviate al suo interno non sono cancellate quando l’utente passa da una pagina ad
un’altra dell’applicazione ma sono mantenute per tutta la sessione che inizia quando un
browser punta al sito e finisce quando è chiusa.
È l’intera fase di lavoro dell’utente sull’applicazione web, comincia quando l’utente effettua
la prima richiesta ad una pagina dell’applicazione web e termina quando l’utente esce
dall’applicazione web o quando rimane inattivo per diverso tempo.
// in una pagina salviamo il dato della sessione
Session["nome_variabile"] = "pippo";
// in un'altra pagina o nella pagina stessa lo preleviamo
string nome = (string)Session["nome_variabile"];
// è buona regola rilasciare le variabili dalla sessione non appena sono obsolete
Session.Remove("nome_variabile");
Session.RemoveAll();
Prima differenza con il ViewState: le variabili che sono messe in sessione sono estraibili
da tutte le pagine dell’applicazione e non solo dalla pagina dalla quale sono state portate
in sessione.
Seconda differenza con il ViewState: le variabili di sessione risiedono sul server e non sul
client.
2.2 Cache
Permette la gestione dello stato della pagina lato server, l’utilizzo è simile alla sessione, le
variabili sono visibili contemporaneamente a tutti gli utenti connessi all’applicazione web.
Server side
um 120 di 243
MASTER PAGE
INTRODUZIONE
Le Windows Form permettono di sfruttare l’ereditarietà per usare l’UI, dato che un form è
una classe che può contenere controlli e da essa è possibile derivare.
Non si può dire la stessa cosa per le Web Form, per le quali non è possibile parlare di
ereditarietà, a causa della presenza del codice di markup.
Pertanto nella realizzazione di applicazioni web si sono sempre cercate strade alternative
all’ereditarietà, cercando di sfruttare al meglio la possibilità di modularizzare le pagine, al
fine di minimizzare il lavoro svolto e favorire il riuso del codice.
Con ASP il meccanismo utilizzato per ottenere lo scopo è stato l'inclusione di file
sfruttando SSI (Server Side Includes).
Questo approccio è stato in seguito soppiantato dagli Web User Control, tramite cui è
stato possibile trattare ogni singola porzione di una pagina ASPX come un controllo
custom definito dal programmatore.
Per superare i limiti della soluzione basata su Web User Controls, è stato introdotto un
nuovo meccanismo basato su Master Page e Content Page.
Anche se non risolvono il problema dell’ereditarietà, le Master Page forniscono una
struttura comune e condivisa tra tutte le pagine che da esse dipendono, sia da un punto di
vista grafico sia logico.
Nello sviluppo di applicazioni web è essenziale che tutte le pagine mantengano un layout
comune.
L’uso di questa tecnica è potente e consente di annidare anche Master Page tra loro,
questo permette di poter disporre di template diversificati per ciascuna sezione del sito.
È possibile assegnare una Master Page anche da codice all’interno dell’evento Pre_Init.
MASTER PAGE
È un template che, può contenere al suo interno qualsiasi elemento HTML e qualsiasi
elemento ASP.NET, in pratica sia contenuti dinamici sia statici, contiene alcune aree
rappresentate da altrettanti controlli di tipo ContentPaceHolder che saranno riempiti con i
contenuti definiti nelle varie sezioni delle Content Page associate.
In altre parole, permette di centralizzare le funzionalità comuni, sia in termini di layout sia
di code-behind, a tutte le pagine del sito web mettendo a disposizione del programmatore
un unico file in cui fare le modifiche.
In questo modo le pagine ereditano l’apparenza e il comportamento implementato nella
Master Page.
Una Master Page è un file con estensione MASTER che ha una sintassi del tutto analoga
ad una normale pagina ASPX, identificata dalla direttiva seguente.
<%@Master
Sostituisce la direttiva @Page delle pagine web.
Una Master Page contiene una serie di controlli ContentPlaceHolder che identificano
alcune regioni personalizzabili il cui contenuto è caricato a run-time a partire da una
Content Page.
Una Master Page priva dei controlli ContentPlaceHolder non ha senso di esistere.
Esempio, progettare una Master Page con tre aree che saranno poi specializzate nella
Content Page.
Fare clic destro in Esplora soluzioni sul nome del progetto, dal menu contestuale
Server side
um 121 di 243
selezionare Aggiungi/Nuovo elemento… (CTRL+MAIUSC+A).
Alla voce Visual C# selezionare Web/Web Form/Pagina Master Web Form.
Nel progetto, il template inserisce automaticamente i seguenti file.
File SITE.MASTER
Contiene solamente un ContentPlaceHolder posizionato a centro pagina, pronto per
essere personalizzato.
È possibile aggiungerne più di uno, basta trascinare il controllo dalla Casella degli
strumenti, oppure aggiungerlo tramite codice.
<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Site.master.cs"
Inherits="MasterPage.Site" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>Esempio di Master Page</title>
<asp:ContentPlaceHolder ID="head" runat="server">
</asp:ContentPlaceHolder>
</head>
<body>
<form id="form1" runat="server">
<div class="left">
<asp:ContentPlaceHolder ID="Left" runat="server">
<div>Sinistra</div>
</asp:ContentPlaceHolder>
</div>
<div class="body">
<asp:ContentPlaceHolder ID="Body" runat="server" >
<p>Centro</p>
</asp:ContentPlaceHolder>
</div>
<div class="right">
Server side
um 122 di 243
<asp:ContentPlaceHolder ID="Right" runat="server">
<div>Destra</div>
</asp:ContentPlaceHolder>
</div>
</form>
</body>
</html>
File SITE.MASTER.CS
using System;
namespace MasterPage {
public partial class Site : System.Web.UI.MasterPage {
protected void Page_Load(object sender, EventArgs e)
{ }
}
}
File SITE.MASTER.DESIGNER.CS
Il codice è generato automaticamente dal template.
CONTENT PAGE
È una Web Form che contiene unicamente controlli di tipo Content e alla quale è associata
una Master Page.
Inoltre, per ogni controllo di tipo Content, deve esistere un controllo di tipo
ContentPaceHolder nella Master Page.
Ciascun controllo Content include il contenuto effettivo per ogni ContentPaceHolder
presente nella Master Page.
La corrispondenza tra i due tipi di controllo si basa sul valore della proprietà ID e
ContentPlacerHolderID.
Questo è necessario perché in una Master Page si possono avere tanti
ContentPlaceHolderID e si deve avere il modo di distinguerli in modo da associare i
contenuti correttamente.
Adesso bisogna associare la Master Page appena progettata alle pagine web del sito.
Fare clic destro in Esplora soluzioni sul nome del progetto, dal menu contestuale
selezionare Aggiungi/Nuovo elemento… (CTRL+MAIUSC+A).
Alla voce Visual C# selezionare Web/Web Form mediante pagina master.
Si apre una finestra per selezionare la Master Page da associare alla pagina web.
Non è sempre obbligatorio sovrascrivere il placeholder, per questo motivo, nell’esempio,
sono soltanto definite la parte centrale e quella destra.
L’uso dell’attributo MasterPageFile sulla direttiva @Page indica il percorso virtuale del file
Server side
um 123 di 243
MASTER.
File CONTENTPAGE.ASPX
<%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master"
AutoEventWireup="true" CodeBehind="ContentPage.aspx.cs"
Inherits="MasterPage.ContentPage" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="Left" runat="server">
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="Body" runat="server">
<div>Parte centrale della pagina</div>
</asp:Content>
<asp:Content ID="Content4" ContentPlaceHolderID="Right" runat="server">
<div>Parte destra personalizzata</div>
</asp:Content>
File CONTENTPAGE.ASPX.CS
using System;
namespace MasterPage {
public partial class ContentPage : System.Web.UI.Page {
protected void Page_Load(object sender, EventArgs e)
{ }
}
}
Il codice HTML e i possibili script non sono inseriti nell’HTML della pagina ma nel codice
della MasterPage; questo permette al designer del sito di modificarne l’aspetto senza
dover ritoccare ogni singola pagina: basterà modificare la Master Page.
È possibile associare una specifica Master Page ad una Content Page tramite l’attributo
MasterPageFile nell’ambito della direttiva @ Page, specificando il percorso del file
.MASTER.
In alternativa, è possibile definire la Master Page per le pagine anche a livello di singola
cartella o a livello di applicazione direttamente nel WEB.CONFIG tramite l'attributo
masterpagefile del TAG <pages/>.
<configuration>
<system.web>
<pages masterpagefile="MasterPage.master" />
</system.web>
</configuration>
È inoltre possibile associare una Master Page ad una pagina anche dinamicamente via
Server side
um 124 di 243
codice.
L’associazione dinamica può essere fatta solamente nell’ambito dell’event handler
dell’evento di pagina PreInit, dato che il run-time di ASP.NET carica le informazioni relative
alle impostazioni della pagina subito dopo questo evento.
void Page_PreInit(object sender, EventArgs e)
{ string master = "MasterPage.master";
if(Page.Request["Master"] != null)
master = Page.Request["Master"].ToString();
this.MasterPageFile = master;
}
È possibile annidare le Master Page, in questo caso ciascuna pagina si comporta nei
confronti della propria Master Page come una normale pagina di contenuto,
indipendentemente dal fatto che la Content Page sia a sua volta Master Page.
Una Master Page collegata ad un’altra Master Page presenta qualsiasi possibile
combinazione di oggetti Content e ContentPlaceHolder.
Una Master Page può essere associata ad una pagina di contenuto in relazione al tipo di
browser utilizzato.
Aggiungendo un prefisso all’attributo MasterPageFile nella direttiva @ Page, è possibile
indicare per quale particolare tipologia di browser la Master Page dev’essere caricata a
run-time.
Per esempio, il prefisso ie identifica Internet Explorer.
<%@ Page Language="c#" ie:MasterPageFile="IE_MasterPage.master"
MasterPageFile="MasterPage.master" %>
Oltre che da template, la Master Page può fungere da Page Controller per le pagine di
contenuto cui è associata.
Data una particolare Master Page è possibile definire nell’ambito della sua interfaccia una
serie di membri pubblici custom.
Per poter utilizzare questi membri aggiuntivi nell’ambito della pagina di contenuto, si
possono seguire due strade.
È possibile castare in modo esplicito la proprietà Master di Page al tipo specifico di
MasterPage che si sta usando nell’ambito del codice.
((MyMaster)this.Master).MyMethod();
In alternativa è possibile utilizzare la direttiva @ MasterType nell’ambito della Content
Page.
In questo caso non è più necessario fare il cast al tipo specifico di Master Page utilizzata.
<%@ MasterType VirtualPath="MasterPage.master" %>
Server side
um 125 di 243
Esempio, progettare un sito web composto da pagine che hanno la stessa struttura.
File DEFAULT.ASPX.CS
L’istruzione IsPostBack restituisce un valore booleano che indica se il PostBack si è
verificato o meno, di solito si usa nell’evento Page_Load.
Quando restituisce false significa che è la prima volta che la pagina è caricata nel browser.
Nell’esempio, si valorizza con l’orario corrente la proprietà Text della lblOra.
using System;
namespace WebApplication1 {
public partial class _default : System.Web.UI.Page {
protected void Page_Load(object sender, EventArgs e)
{ if (!IsPostBack)
lblOra.Text = "Sono le ore: " + System.DateTime.Now.TimeOfDay.ToString();
}
protected void btnAggiorna_Click(object sender, EventArgs e)
{ if (!string.IsNullOrWhiteSpace(txtNominativo.Text))
lblOra.Text = "Ciao " + txtNominativo.Text + " sono le ore: " +
System.DateTime.Now.TimeOfDay.ToString();
}
}
}
L’orario visualizzato nella pagina, è aggiornato solo se l’utente digita il nome nella casella
di testo.
Quindi ASP.NET preserva l’orario già presente sulla pagina, grazie al ViewState perché
aggiunge nella pagina un campo nascosto, hidden fields, chiamato _VIEWSTATE.
In questo campo sono aggiunte tutte le proprietà dei controlli presenti nella pagina che
sono state modificate durante il roundtrip, in altre parole il processo di gestione del
PostBack.
Eseguire l’applicazione, nel browser, fare clic su Strumenti/Strumenti di sviluppo F12.
Nel campo value c’è il contenuto del ViewState della pagina, serializzato con una codifica
Server side
um 126 di 243
a base 64 bit.
Quando la pagina è caricata nel browser, evento Page_Load, il ViewState è codificato e le
proprietà in essa contenute sono associate ai controlli corrispondenti.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>
</title><link href="Site.css" rel="stylesheet" /></head>
<body>
<form method="post" action="default.aspx" id="form1">
<div class="aspNetHidden">
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE"
value="kV/ZvwlahzV65fC6pTJTrxFp5X8qZ0+Al9roCnaqVl+QnGckXn5Hf3OB0akGW
mxuegcvd5ttCDP3cLg5E7PyYeDiUUNhtfL0W3p9EYXNqbg6XRTHg6L8GcgwJxYxvm
VKS7lgrLugX1TmK3fFw/33Vw/cmQ26484IV0OmriKc6kRXD8vTBI8to4rAWuNmK3/o"
/>
</div>
<div class="aspNetHidden">
<input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION"
value="DlUDOlyNm7vagb53ueTN41D7/oeHNQxI5Q9XEilwbSExUolLEl1Pg4EoYD4bgPW
BfARVmvz0W3RM1nYKuUO/SBdICZbmXZAD3P0aAGe2E0sqG/iQdJ9dlbUHSoo0DVh9A
yaFjIdIViSXtBFPWBP0aA==" />
</div>
<div id="container">
<header>
<h1>Biciclette</h1>
<nav>
<ul>
<li><a href="default.aspx">Home</a></li>
<li><a href="webform1.aspx">Chi Siamo</a></li>
<li><a href="webform2.aspx">Prodotti</a></li>
</ul>
</nav>
</header>
<div id="body">
<h2>Home</h2><br />
<span id="ContentPlaceHolder1_lblNominativo">Nominativo: </span><input
name="ctl00$ContentPlaceHolder1$txtNominativo" type="text"
id="ContentPlaceHolder1_txtNominativo" />
<br />
<input type="submit" name="ctl00$ContentPlaceHolder1$btnAggiorna"
value="Aggiorna" id="ContentPlaceHolder1_btnAggiorna" />
<br /><br />
<span id="ContentPlaceHolder1_lblOra">Sono le ore: 11:07:58.9355468</span>
</div>
<footer>© 2023 - Biciclette</footer>
</div>
</form>
</body>
</html>
File SITE.MASTER
Le pagine devono avere un layout monolitico fisso a colonna singola, una testata che
Server side
um 127 di 243
contiene il menu di navigazioen del sito.
L’intestazione è rappresentata dal TAG <header>, all’interno si usa il TAG <nav>.
Il corpo è rappresentato dal TAG <body>, all’interno si usa il ContentPlaceHolder.
Il piè di pagina è rappresentato dal TAG <footer>.
<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Site.master.cs"
Inherits="WebApplication1.Site" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title></title>
<link href="Site.css" rel="stylesheet" />
</head>
<body>
<form id="form1" runat="server">
<div id="container">
<header>
<h1>Biciclette</h1>
<nav>
<ul>
<li><a href="default.aspx">Home</a></li>
<li><a href="webform1.aspx">Chi Siamo</a></li>
<li><a href="webform2.aspx">Prodotti</a></li>
</ul>
</nav>
</header>
<div id="body">
<asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
</asp:ContentPlaceHolder>
</div>
<footer>© 2023 - Biciclette</footer>
</div>
</form>
</body>
</html>
File SITE.CSS
Definisce il layout del sito: margini, dimensioni, colore, font e allineamenti del testo e degli
sfondi.
html { margin: 0px; padding: 0px;}
body { margin: 0px; padding: 0px;}
#container { margin: 0px auto; width: 1060px; text-align: left;
border-right-color: black; border-left-color: black;
border-right-width: 2px; border-left-width: 2px;
border-right-style: solid; border-left-style: solid;
}
header { color: red; background-color: grey; }
footer { padding: 0.1em; text-align: center; color: red; background-color: grey; }
nav { background-color: blue; }
#body { padding: 1em; }
nav ul { margin: 0px; padding: 0px; list-style-type: none; }
nav li { margin: 0px 0px 0px 1em; padding: 0px; display: inline; }
Server side
um 128 di 243
nav a { font: bold arial, sans-serif; font-size:18pt;color: red; text-decoration: none; }
nav a:hover { color: white; text-decoration: underline; }
File WEBFORM1.ASPX
Inserire, quindi, il contenuto della pagina: due Label, una TextBox e un Button.
File DEFAULT.ASPX
<%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master"
AutoEventWireup="true" CodeBehind="default.aspx.cs"
Inherits="WebApplication1._default" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1"
runat="server">
<h2>Home</h2><br />
<asp:Label ID="lblNominativo" runat="server" Text="Nominativo:
"></asp:Label><asp:TextBox ID="txtNominativo" runat="server"></asp:TextBox>
<br />
<asp:Button ID="btnAggiorna" runat="server" Text="Aggiorna"
OnClick="btnAggiorna_Click" />
<br /><br />
<asp:Label ID="lblOra" runat="server"></asp:Label>
</asp:Content>
Server side
um 129 di 243
TEMI
INTRODUZIONE
L’aspetto grafico di un sito può dipendere dalla definizione di stili, come colori e font,
all’interno di un file CSS.
ASP.NET prevede la possibilità di applicare temi al proprio sito anche a run-time.
Realizzando vari modelli grafici per il proprio sito sarà possibile far scegliere all’utente
quello a lui più gradevole e cambiarlo in tempo reale.
Rappresentano il principale meccanismo per personalizzare la resa grafica delle
applicazioni web.
Un tema definisce un insieme di stili e di attributi grafici e li associa ai vari elementi e
controlli utilizzati nell’ambito dell’applicazione.
Ciascun tema è caratterizzato da un nome che lo identifica univocamente ed è composto
dai file CSS contenenti gli stili dei TAG, dagli skin dei controlli e dalle immagini.
Se da una parte un CSS contiene le impostazioni di rappresentazione dei TAG HTML e
definisce le classi CSS associate agli elementi delle pagine, dall’altra lo skin è un file di
testo contenente i valori predefiniti per le proprietà grafiche relative ai controlli web.
Di fatto si può pensare ad uno skin come ad una specie di stylesheet server side riferito ai
controlli di ASP.NET.
Rispetto ad un file CSS, lo skin può contenere l’impostazione di proprietà grafiche che non
hanno una corrispondenza con un attributo CSS.
Anche se è possibile farlo, non sarebbe in ogni caso indicato utilizzare lo skin per
impostare valori che possono essere settati utilizzando i CSS.
Risulta più corretto associare allo skin di un controllo una classe CSS in cui siano indicati
tutti gli attributi utili alla definizione della resa grafica.
Un file .SKIN contiene l’insieme dei TAG relativi ai controlli da personalizzare.
Ogni skin può essere identificato tramite un ID oppure l’identificazione può essere
omessa.
Lo skin senza ID rappresenta lo skin predefinito per un particolare controllo.
In uno stesso file .SKIN possono coesistere più skin relativi allo stesso tipo di controllo
contrassegnati con ID diversi.
<asp:TextBox ID="TextBox1" runat="server" SkinID="LongText" CssClass="InputText"
Columns="100" />
<asp:TextBox ID="TextBox2" runat="server" SkinID="ShortText" CssClass="InputText"
Columns="10" />
<asp:TextBox ID="TextBox3" runat="server" CssClass="InputText" Columns="50" />
Nell’ambito dell’applicazione è possibile specificare un particolare skin per un controllo
web tramite la proprietà SkinID.
<asp:TextBox ID="txtEmail" Runat="server" SkinID="LongText"/>
Per creare un tema basta inserire una nuova sotto cartella nella cartella APP_THEMES
dell’applicazione web.
Il nome della cartella rappresenta il nome del tema e in essa vanno posizionati i file CSS e
gli skin.
Nella cartella relativa al tema possono essere presenti più file .CSS e .SKIN.
Le immagini vanno collocate nella sotto cartella IMAGES.
I temi possono essere definiti per la singola pagina, per tutte le pagine di un’applicazione o
anche a livello di sistema.
Server side
um 130 di 243
A livello di singola pagina il tema può essere impostato tramite l’attributo Theme nella
direttiva @ Page.
<%@ Page Language="C#" Theme="DarkBeer" AutoEventWireup="true"
CodeBehind="WebForm1.aspx.cs" Inherits="Tema.WebForm1" %>
È possibile associare un tema ad una pagina anche dinamicamente via codice.
L’associazione dinamica può essere fatta solamente nell’ambito dell’event handler
dell’evento di pagina PreInit, dato che il run-time di ASP.NET carica le informazioni relative
al tema subito dopo questo evento.
void Page_PreInit(object sender, EventArgs e)
{ string theme = "Default";
if(Page.Request["DarkBeer"] != null)
theme = Page.Request["DarkBeer "].ToString();
this.Theme = theme;
}
A livello di applicazione, il tema può essere impostato dentro al WEB.CONFIG tramite
l’attributo theme del TAG <pages>.
<configuration>
<system.web>
<pages theme=" DarkBeer"/>
</system.web>
</configuration>
È fondamentale che esista una corrispondenza tra il nome del tema specificato e il nome
di una delle sotto cartella presenti nella cartella APP_THEMES.
Server side
um 131 di 243
WEB USER CONTROL
INTRODUZIONE
ASP.NET consente due modalità per riutilizzare il codice.
1. Custom control: sono classi vere e proprie che ereditano da Control o da un altro
controllo e sono composte da codice Visual C# o Visual Basic: sono complessi, sono
distribuiti su più progetti e sono compilati in Web Control Library.
2. Web User Control: sono pezzi di pagina, composti più da HTML che da codice vero e
proprio, sono semplici ma meno portabili, sono file con estensione ASCX.
Un Web User Control è progettato come una Web Form, quindi è dotato di un’UI e di un
file con il code-behind; a differenza di una Web Form, tuttavia, è contenuto in un file ASCX
e non può avere i TAG <html>, <body> e <form> poiché è inserito in una Web Form che
questi TAG li contiene già.
Un Web User Control è una classe ed eredita le sue funzionalità di base da
SYSTEM.WEB.UI.USERCONTROL.
Per definire un Web User Control, dopo aver creato un nuovo progetto ASP.NET, fare clic
con il tasto destro del mouse sul nome del progetto all’interno di Esplora soluzioni e
selezionare la voce Aggiungi/Nuovo elemento….
Si aprirà una finestra di dialogo in cui sono mostrati tutti i tipi di file che possono essere
aggiunti, selezionare Controllo utente Web Form.
Grazie al run-time comune del .NET Framework è possibile avere una Web Form scritta in
Visual C# al cui interno si trova un Web User Control realizzato con Visual Basic e
viceversa.
Il nuovo Web User Control sarà aggiunto al progetto e contiene i seguenti file.
File WEBUSERCONTROL1.ASCX
<%@ Control Language="C#" AutoEventWireup="true"
CodeBehind="WebUserControl1.ascx.cs" Inherits="Temi.WebUserControl1" %>
File WEBUSERCONTROL1.ASCX.CS
using System;
namespace Temi {
public partial class WebUserControl1 : System.Web.UI.UserControl {
protected void Page_Load(object sender, EventArgs e)
{ }
}
}
File WEBUSERCONTROL1.ASCX.DESIGNER.CS
Il codice è generato automaticamente dal template.
Esempio, progettare un controllo composto da una Label e da una TextBox.
Avere un Web Control che li definisce entrambi in una sola volta permette di risparmiare
tempo nella creazione delle pagine.
Server side
um 132 di 243
Impostare le proprietà degli oggetti.
lblEtichetta
txtNome
Label
TextBox
Text = Etchetta
Aggiungere le proprietà che consentono di lavorare con l’etichetta e la casella di testo.
Dal momento che il Web User Control, una volta inserito in una pagina ASP.NET, è visto
come un unico oggetto, deve disporre di proprietà che permettano di modificare gli oggetti
contenuti al suo interno.
Nel file del code-behind definire le proprietà Caption e Text, per leggere e cambiare,
rispettivamente, il testo della Label e il contenuto della TextBox.
using System;
namespace Temi {
public partial class WebUserControl1 : System.Web.UI.UserControl {
public string Caption
{ get { return lblEtichetta.Text; }
set { lblEtichetta.Text = value; }
}
public string Text
{ get { return txtNome.Text; }
set { txtNome.Text = value; }
}
protected void Page_Load(object sender, EventArgs e)
{ }
}
}
Aggiungere il controllo ad una pagina ASP.NET.
Visualizzare la Web Form in cui inserire l’oggetto, quindi all’interno di Esplora soluzioni,
selezionare il Web User Control e trascinarlo nella posizione desiderata sulla pagina.
La finestra delle proprietà dell’oggetto mostra anche le proprietà che si sono definite in
precedenza.
Server side
um 133 di 243
I valori di Caption e Text possono essere impostati sia in fase di progettazione utilizzando
la finestra delle proprietà sia da codice.
using System;
namespace Temi {
public partial class WebForm1 : System.Web.UI.Page {
protected void Page_Load(object sender, EventArgs e)
{ WebUserControl1.Caption = "Sono nella label Etichetta";
WebUserControl1.Text = "Sono nella TextBox Nome";
}
}
}
Modificando una proprietà in fase di progettazione, il Web User Control non sarà
aggiornato con i nuovi valori, che, però, saranno correttamente visualizzati quando si
caricherà la pagina nel browser.
Selezionare il modo Origine per visualizzare il codice HTML della Web Form.
Quando si aggiunge un Web User Control ad una pagina, è inserita la direttiva @ Register
ad indicare che nella pagina si utilizza un controllo il cui codice è contenuto in un file
esterno.
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs"
Inherits="Temi.WebForm1" %>
<%@ Register src="WebUserControl1.ascx" tagname="WebUserControl1" TagPrefix
="uc1" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>WEB USER CONTROL</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<uc1:WebUserControl1 ID="WebUserControl1" runat="server" />
</div>
</form>
</body>
</html>
L’attributo src è riferito al path per arrivare al file sorgente e può essere un percorso
relativo o assoluto ma deve sempre puntare ad una risorsa raggiungibile localmente.
Server side
um 134 di 243
L’attributo TagPrefix indica il prefisso da utilizzare per la dichiarazione nella pagina.
L’attributo Namespace è il riferimento al namespace che contiene i controlli.
L’attributo Assembly indica il file risultante dalla compilazione.
COMUNICARE CON LA PAGINA
Visualizzare a video la data attuale.
File TEST1.ASCX
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="test1.ascx.cs"
Inherits="Web_User_Control.test1" %>
<p>Data attuale: <asp:literal id="data" runat="server" /></p>
File TEST1.ASCX.CS
using System;
namespace Web_User_Control {
public partial class test1 : System.Web.UI.UserControl {
protected void Page_Load(object sender, EventArgs e)
{ data.Text = DateTime.Now.ToLongDateString(); }
}
}
Il Web User control deve comunicare con gli altri soggetti presenti sulla pagina, infatti, può
essere contenuto all’interno di una pagina ma anche all’interno di un altro Web User
Control, di fatto non è detto che l’oggetto contenitore sia a sua volta un altro controllo di
questo tipo, anzi spesso è proprio così.
Per semplicità, si specifica come oggetto contenitore una pagina.
Un Web user Control è un qualsiasi oggetto e quindi pertanto può essere esteso, per
esempio con una serie di proprietà per far sì che l’aspetto grafico sia più gradevole.
Dotare l’oggetto di una proprietà di testo di nome CssClass che serve per specificare uno
stile da associare al testo scritto.
// proprietà per specificare uno stile
private string cssClass;
public string CssClass
{ get { return cssClass; }
set { cssClass = value; }
}
Associare questo valore alla rispettiva proprietà di un panel all’interno del quale si
rinchiude il testo già presente sul controllo.
Si deve specificare, nella pagina, il valore da associare a questa proprietà.
<uc1:test2 ID="test2" runat="server" CssClass="date"/>
Fare la stessa modifica per specificare un testo alternativo, da associare ad un controllo
Literal inserito sul controllo, da visualizzare prima della data.
// proprietà per specificare un testo di descrizione
private string text = "Data attuale:";
public string Text
{ get { return text; }
set { text = value; }
}
Server side
um 135 di 243
Defininire un evento sul Page_Load che vada a formattare gli oggetti della pagina con le
proprietà specificate.
protected void Page_Load(object sender, EventArgs e)
{ testo.Text = Text;
data.Text = DateTime.Now.ToLongDateString();
if (cssClass != null)
contenitore.CssClass = cssClass;
Trace.Write("Control_Data", "Render");
}
MANTENERE LO STATO CON IL VIEWSTATE
Assegnare le proprietà attraverso codice, si nota che, tra i vari PostBack, i valori non sono
mantenuti e che, soprattutto, gli eventi si verificano, nella pagina e nei controlli, secondo
modalità differenti.
Sequenza degli eventi tra pagina e controlli
Sia la pagina che eredita dalla classe Page, sia gli user controls che ereditano da
UserControl, hanno una serie di eventi in comune che servono per eseguire codice in
base al verificarsi di determinate condizioni.
Il giusto ordine in cui si verificano questi eventi all’interno dei controlli è il seguente.
Un Web User Control contenuto in una pagina, avrà la stessa sequenza di eventi della
pagina, con la differenza che ogni evento sarà invocato subito dopo l’evento
corrispondente contenuto nella pagina, in pratica, la sequenza sarà la seguente.
1. Page_Init
1.1. Della pagina
1.2. Degli user Controls
2. Page_Load
2.1. Della pagina
2.2. Degli user Controls
3. Page_PreRender
3.1. Della pagina
3.2. Degli user Controls
4. Page_Render
4.1. Della pagina
4.2. Degli user Controls
Se ad esempio si devono passare, da un Web User Control, informazioni che la pagina
dovrà leggere nell’evento Page_Load, si deve scrivere il codice all'interno del Page_ Init.
Analogamente, se un Web User Control è contenuto in un altro Web User Control, questi
eventi si verificheranno sempre nel controllo contenitore.
Per quanto riguarda il primo problema, è essenzialmente dovuto al fatto che tutti i controlli
che si usano sulle pagine mantengono il loro stato attraverso il ViewState.
Dunque per fare in modo che il controllo mantenga lo stato delle proprietà tra i vari
PostBack, si deve salvare e leggere il valore di queste proprietà da questo state bag.
// proprietà per specificare uno stile
private string cssClass;
public string CssClass
{ // leggiamo dal ViewState
get { return ViewState["data_cssClass"] as String; }
Server side
um 136 di 243
// scriviamo nel ViewState
set {
ViewState["data_cssClass"] = value;
cssClass = value;
}
}
Per recuperare la proprietà, si legge dal ViewState, dato che in fase di assegnazione si è
salvato il valore.
L’ultima modifica poi, riguarda il momento in cui applicare le proprietà al controllo.
Tra gli eventi a disposizione per chi sviluppa controlli, quello che rappresenta il momento
migliore in cui andare ad applicare eventuali proprietà di tipo “grafico” è Page_PreRender
che si verifica dopo Page_Init e Page_Load e prima che la pagina sia costruita per essere
inviata al client.
Allora, bisogna spostare tutta la logica in questo evento, in modo che sia possibile
effettuare tutte le operazioni quando il ViewState è stato già caricato.
Aggiungere un pulsante nella pagina alla cui pressione lo stile associato al controllo sarà
modificato.
protected void btnCambia_Click(object sender, EventArgs e)
{ Trace.Write(test3.CssClass);
if (test3.CssClass == "date")
test3.CssClass = "datedark";
else
test3.CssClass = "date";
}
Server side
um 137 di 243
WEB CONTROL LIBRARY
INTRODUZIONE
La differenza principale tra i due tipi di controlli riguarda la fase di progettazione e consiste
nella semplicità di creazione da una parte e nella facilità d’uso dall’altra.
I Web User Control sono semplici da creare, dal momento che si realizzano in maniera
visuale, dispongono del code-behind e supportano la gestione degli eventi.
Tuttavia, un Web User Control non può essere aggiunto alla Casella degli strumenti ed è
rappresentato in maniera statica quando è aggiunto ad un pagina, in pratica la modifica di
una sua proprietà non si riflette nelle visualizzazione all'interno del designer ma è visibile
solo in run-time.
Inoltre, l’unico modo di condividere il controllo tra applicazioni diverse consiste
nell’inserirne una copia distinta in ciascun progetto, soluzione che richiede una maggiore
gestione nel caso in cui si apportino modifiche al controllo.
Una Web Control Library, invece, si realizza scrivendo a mano il codice che poi sarà
compilato, dunque è più difficile da realizzare.
Una volta realizzato il controllo, tuttavia, è possibile aggiungerlo alla Casella degli
strumenti e gestirlo in modo analogo a quanto visto per i controlli standard.
CREAZIONE
Per creare un nuovo progetto, fare clic su File/Nuovo/Progetto… (CTRL+MAIUSC+N).
Nella finestra di dialogo Nuovo Progetto selezionare Modelli/Visual C#/Web, quindi
selezionare il tipo di applicazione, Controllo Server ASP.NET.
File SERVERCONTROL1.CS
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace ServerControl {
[DefaultProperty("Text")]
[ToolboxData("<{0}:ServerControl1 runat=server></{0}:ServerControl1>")]
public class ServerControl1 : WebControl {
[Bindable(true)]
[Category("Appearance")]
[DefaultValue("")]
[Localizable(true)]
public string Text
{ get {
String s = (String)ViewState["Text"];
return ((s == null)? "[" + this.ID + "]" : s);
}
set
{ ViewState["Text"] = value; }
}
protected override void RenderContents(HtmlTextWriter output)
Server side
um 138 di 243
{ output.Write(Text); }
}
}
Eseguire il progetto, compare la finestra seguente perché si ottiene
SERVERCONTROL1.DLL che sarà utilizzato da un’applicazione ASP.NET.
il
file
Ogni controllo estende la classe WebControl che fornisce proprietà, metodi ed eventi
comuni a tutti i controlli server web.
Alla dichiarazione della classe e alla proprietà Text sono stati aggiunti, tra ([]), i Custom
Attributes, in altre parole una serie di attributi che fornisce informazioni aggiuntive sulle
classi, sui metodi e sulle proprietà.
Ad esempio, ToolboxData indica quale TAG è associato al controllo: in pratica, quando
sarà inserito in una pagina, esso sarà identificato dal TAG specificato in questo attributo.
Category specifica la categoria in cui sarà visualizzata la proprietà Text all’interno della
visualizzazione per categorie della finestra Proprietà.
Il metodo RenderContents, è il cuore del Web Control: specifica qual è il codice HTML che
dev’essere inserito nella pagina per visualizzare il controllo, riceve come parametro un
oggetto di tipo HtmlTextWriter su cui scrivere il codice HTML.
Il metodo RenderContents è automaticamente richiamato dal run-time del .NET sia
quando il controllo è visualizzato in una pagina ASP.NET sia quando dev’essere generato
il contenuto HTML da inviare al browser.
Nel primo caso, output rappresenta la pagina all'interno dell’editor, nel secondo si riferisce
alla pagina che è inviata al client per la visualizzazione nel browser, in pratica, il codice
HTML che è scritto dal metodo RenderContents è il codice che l’utente riceve quando
richiede la pagina al server.
Anche i controlli web standard si comportano nello stesso modo: ogni controllo inserito in
una pagina genera il codice HTML necessario alla sua visualizzazione tramite il metodo
RenderContents, ad esempio, in un controllo Label produce il seguente codice HTML.
<span id="Label1">Label</span>
Il metodo RenderContents si limita a scrivere nella pagina il contenuto della variabile Text,
senza aggiungere alcuna formattazione HTML.
UTILIZZO
Per aggiungere un nuovo progetto, fare clic su File/Aggiungi/Progetto….
Nella finestra di dialogo Nuovo Progetto selezionare Altri linguaggi/Visual C#/Web,
quindi selezionare il tipo di applicazione, Applicazione Web ASP.NET vuota.
Fare clic destro in Esplora soluzioni sul nome del progetto, dal menu contestuale
Server side
um 139 di 243
selezionare Aggiungi/Nuovo elemento… (CTRL+MAIUSC+A).
Alla voce Visual C# selezionare Web/Web Form.
Aprire DEAFULT.ASPX in modalità Progettazione.
La Casella degli strumenti ha una nuova scheda che corrisponde al ServerControl e
contiene ServerControl1 che può essere inserito nella pagina.
Aggiungere il contollo alla pagina e, nella finestra delle proprietà, modificare il valore di
Text: a differenza di quanto avviene con i Web User Control, la modifica si riflette anche in
fase di progettazione.
Eseguire l’applicazione.
Esempio, modificare il controllo affinchè il testo specificato appaia in grassetto.
È sufficiente modificare il codice HTML generato dal controllo, in pratica intervenire sul
metodo Render.
Poichè il metodo Write dell’oggetto HtmlTextWriter si limita a scrivere sulla pagina tutto
quello che riceve come parametro, basta inserire tutto in un’unica istruzione.
output.Write("<b>" + Text + "</b>");
Questa soluzione è corretta ma rischia di creare confusione, inoltre, la possibilità di
dimenticare qualche (<>) oppure (/) cresce all’aumentare del numero di TAG da inserire.
Server side
um 140 di 243
Si possono usare altri metodi messi a disposizione da HtmlTextWriter per produrre codice
più leggibile e con una distinzione maggiore tra TAG HTML e contenuto vero e proprio.
protected override void Render(HtmlTextWriter output)
{ output.WriteBeginTag("b");
output.Write(HtmlTextWriter.TagRightChar);
output.Write(Text);
output.WriteEndTag("b");
}
Il metodo WriteBeginTag scrive il (<) e il TAG indicato come parametro ma non lo chiude
con (>) perchè, in generale, esso potrebbe contenere degli attributi, da specificare con il
metodo WriteAttribute.
Per questo motivo è necessaria la successiva istruzione di Write che scrive il carattere (>)
(HtmlTextWriter.TagRightChar).
In alternativa a queste due istruzioni, si può usare la riga seguente.
// scrive <b>
output.WriteFullBeginTag("b");
Dopo aver stampato il testo vero e proprio, chiudere il TAG con il metodo WriteEndTag.
Ricompilare il controllo ed eseguire l’applicazione web.
Visualizzare il sorgente della pagina all’interno del browser web, ad esempio, in IExplorer,
con il comando Visualizza/Origine, il testo specificato nella proprietà Text del controllo è
stato inserito tra i TAG <b>Ciao, mondo!</b>.
Anche questi controlli, come i Web Control, una volta inseriti in una pagina prevedono la
direttiva @ Register.
<%@ Register assembly="ServerControl" namespace="ServerControl" TagPrefix ="cc1"
%>
WEB USER CONTROL O WEB CONTROL LIBRARY
Se si ha bisogno di un controllo che abbia quasi solo funzionalità visive, allora un Web
User Control è perfetto, perché è un file sorgente con HTML mischiato ad un po’ di codice.
Se, invece, si ha bisogno di un “vero” controllo, con possibilità di creare una classe,
gestirla, ereditarla, o più semplicemente se si ha bisogno di modificare un controllo
esistente, come il Repeater, perché offra funzionalità aggiuntive, allora la scelta cade sui
Web Control Library.
La vera differenza è che questi ultimi sono compilati in assembly, mentre i Web User
Control no.
Server side
um 141 di 243
CONVALIDA
INTRODUZIONE
Un’applicazione web dev’essere in grado d’individuare gli errori (gli eventi non previsti) che
si verificano mentre l’utente la usa e deve correggerli (gestirli) per consentire una corretta
conclusione delle operazioni.
Nel caso in cui non sia possibile correggerli, allora bisogna avvisare l’utente con
informazioni che gli facciano capire come proseguire.
Metodologie di gestione degli errori: da quella più bassa a quella più alta.
1. A LIVELLO DI WEB.CONFIG
All’interno dell’area <system.web> usando il TAG <customErrors> è possibile definire delle
pagine di errore su cui redirigere l’utente quando si verifica un errore.
È possibile definire sia una pagina di errore di default, ErrorPage.html, sia pagine
specifiche per tipologia di errore, per esempio per i codici di errore 401 (necessaria
autenticazione) ErrorPage401.html, 404 (risorsa non trovata) ErrorPage404.html e 500
(errore interno del server) ErrorPage500.html.
Inoltre, bisogna settare le proprietà mode="On" per informare ASP.NET che deve
redirezionare l’utente alle pagine di errore indicate.
La gestione degli errori a questo livello è la più semplice disponibile ma anche la meno
dettagliata, infatti, non è possibile dare all’utente informazioni dettagliate circa l’errore che
si è verificato.
Questo perché quando si verifica un errore, il CLR se ne accorge e redireziona l’utente
sulla pagina corrispondente alla tipologia di errore che si è verificato.
In questo redirezionamento, però, è persa la traccia dell’errore.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
<customErrors mode="On" defaultRedirect="ErrorPage.html">
<error statusCode="401" redirect="ErrorPage401.html"/>
<error statusCode="404" redirect="ErrorPage404.html"/>
<error statusCode="500" redirect="ErrorPage500.html"/>
</customErrors>
<compilation debug="true" targetFramework="4.5" />
</system.web>
</configuration>
È buona regola di programmazione definire sempre in questo file una pagina di errore.
File ERRORPAGE.HTML
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title></title>
</head>
<body>
<h2>Errore: Si è verificato un errore non gestito dall'applicazione.</h2>
<br /> <br />
Server side
um 142 di 243
</body>
</html>
File ERRORPAGE401.HTML
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title></title>
</head>
<body>
<h2>Errore: 401--Unauthorized--Necessaria autenticazione.</h2>
<br /> <br />
</body>
</html>
File ERRORPAGE404.HTML
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title></title>
</head>
<body>
<h2>Errore: 404--Not found--Il server non ha trovato la risorsa richiesta.</h2>
<br /> <br />
</body>
</html>
File ERRORPAGE500.HTML
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title></title>
</head>
<body>
<h2>Errore: 500--Internal server error--Errore interno al server.</h2>
<br /> <br />
</body>
</html>
2. A LIVELLO di APPLICAZIONE WEB
Quando si verifica un errore in un’applicazione web, difficilmente si riesce a risolverlo,
perché spesso gli errori dipendono da risorse al momento non disponibili, per esempio WS
offline, DB o server non raggiungibili.
In questi casi l’intervento da codice da parte del programmatore non serve.
Per questo motivo è meglio gestire gli errori in modo centralizzato, in altre parole a livello
di applicazione web.
Bisogna scrivere il codice di gestione degli errori all’interno del metodo Application_Error
che si trova nel file GLOBAL.ASAX.
protected void Application_Error(object sender, EventArgs e)
Server side
um 143 di 243
{
// prendiamo l'ultimo errore dal server
Exception exc = Server.GetLastError();
if (exc is HttpUnhandledException) {
if (exc.InnerException != null) {
HttpContext.Current.Session["lastError"] = exc;
Response.Redirect("ErrorPage.aspx", false);
Server.ClearError();
}
}
}
Questo metodo scatta ogni volta che si verifica un errore che non è stato gestito
dall’applicazione web.
L’istruzione Server.GetLastError prende l’ultima eccezione sollevata, se si tratta di
un’eccezione non gestita HttpUnhandledException si verifica se possiede un’eccezione
interna InnerException.
Quando un’eccezione sollevata non è gestita dall’applicazione web, il CLR crea
un’eccezione non gestita di tipo HttpUnhandledException all’interno della quale colloca
l’eccezione originale.
Adesso si mette questa eccezione originale in sessione, in modo da averla a disposizione
nella pagina di errore ERRORPAGE.ASPX, grazie all’istruzione Response.Redirect.
Per evitare di mettere l’eccezione in sessione, si potrebbe usare il metodo Server.Transfer
che conserva l’informazione sull’errore, cosa che, invece, non fa il metodo
Response.Redirect.
Server.Transfer non modifica l’indirizzo del browser, quindi, l’utente non capisce che si
trova su una pagina diversa da quella dove si è verificato l’errore.
Dopo aver gestito l’errore, bisogna eliminarlo dal server con l’istruzione Server.ClearError,
se non lo si fa l’errore continuerebbe a essere considerato come non risolto e potrebbe
essere gestito nuovamente in un’altra parte dell’applicazione web.
La gestione degli errori deve prevedere l’uso di pagine di errore che siano chiare per
l’utente, in pratica devono spiegare che errore si è verificato, cosa comporta l’errore e
cosa si deve fare in seguito.
Inoltre, occorrono delle sezioni che riportino informazioni dettagliate per il programmatore,
in modo tale che quando l’applicazione web gira in fase di test possa individuare il punto
che ha generato l’errore.
File ERRORPAGE.ASPX
<%@ Page Language="C#" AutoEventWireup="true" MasterPageFile="~/Site.Master"
CodeBehind="ErrorPage.aspx.cs" Inherits="WebApplication1.ErrorPage" %>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1"
runat="server">
<h2>Errore:</h2>
<br />
<%-- area utente--%>
Cosa è successo: <asp:Label ID="FriendlyErrorMsg" runat="server" Text="Label" FontSize="Large" style="color: red"></asp:Label>
<asp:Panel ID="ErrorPanel" runat="server">
<p>
Conseguenze:
<br />
<asp:Label ID="WhatErrorMsg" runat="server" Font-Bold="true" Font-Size="Large"
/><br />
</p>
Server side
um 144 di 243
<p>
Cosa puoi fare:
<br />
<asp:Label ID="ActionsErrorMsg" runat="server" Font-Bold="true" FontSize="Large" /><br />
</p>
<p>
Informazioni di supporto:
<br />
<asp:Label ID="SupportErrorMsg" runat="server" Font-Bold="true" FontSize="Large" /><br />
</p>
</asp:Panel>
<br /> <br /><br /> <br />
<%-- area programmatore --%>
<asp:Panel ID="DetailedErrorPanel" runat="server" Visible="false">
<p>
Errore Dettagliato:
<br />
<asp:Label ID="ErrorDetailedMsg" runat="server" Font-Bold="true" FontSize="Large" /><br />
</p>
<p>
Messaggio di errore dettagliato:
<br />
<asp:Label ID="InnerMessage" runat="server" Font-Bold="true" Font-Size="Large"
/><br />
</p>
<pre>
<asp:Label ID="InnerTrace" runat="server" />
</pre>
</asp:Panel>
</asp:Content>
Il codice associato all’area utente si trova nel file ERRORPAGE.ASPX.CS.
Exception ex = (Exception)Session["lastError"];
// se l'eccezione non esiste più allora creane una generica
if (ex == null)
ex = new Exception(unhandledErrorMsg);
else {
if (ex.InnerException is CustomException) {
CustomException myex = (CustomException)ex.InnerException;
FriendlyErrorMsg.Text = myex.WhatHappened;
WhatErrorMsg.Text = myex.WhatHasBeenAffected;
ActionsErrorMsg.Text = myex.WhatActionsCanUserDo;
SupportErrorMsg.Text = myex.SupportInformation;
}
}
Bisogna prendere l’eccezione che si era messa in sessione nel metodo Application_Error.
Se l’eccezione è nulla, si crea un’eccezione base con un messaggio di errore generico.
Nel caso in cui l’eccezione presa dalla sessione ne ha una interna InnerException di tipo
CustomException, in pratica quella personalizzata, allora s’istanzia un’eccezione di questo
Server side
um 145 di 243
tipo e si valorizzano le caselle di testo della pagina di errore con le proprietà corrispondenti
dell’eccezione personalizzata.
La proprietà InnerException restituisce un’eccezione generica di tipo Exception, quindi si
deve fare il cast esplicito a CustomException.
Il codice associato all’area programmatore si trova nel file ERRORPAGE.ASPX.CS.
// visualizza i dettagli degli errori solo per il programmatore in fase di test
if (Request.IsLocal) {
// mostra il pannello per il programmatore
DetailedErrorPanel.Visible = true;
// messaggio di errore dettagliato
ErrorDetailedMsg.Text = ex.Message;
if (ex.InnerException != null) {
InnerMessage.Text=ex.GetType().ToString()+"<br/>"+ex.InnerException.Message;
InnerTrace.Text = ex.InnerException.StackTrace;
}
else {
InnerMessage.Text = ex.GetType().ToString();
if (ex.StackTrace != null)
InnerTrace.Text = ex.StackTrace.ToString().TrimStart();
}
}
Attraverso la proprietà IsLocal della classe Request si vede se la richiesta HTTP è arrivata
dalla stessa macchina in cui risiede l’applicazione web.
Se l’utente è il programmatore, allora si visualizza il pannello.
Si valorizzano le caselle di testo con i valori presenti nelle proprietà della classe Exception
ovvero GetType che dice di che tipo di eccezione si tratta, Message riporta il messaggio di
errore restituito dall’eccezione e StackTrace riporta l’intero percorso dell’errore a partire
dalla riga di codice della pagina dove si è verificato fino alla riga di codice della pagina
dove è stato gestito.
Esempio, simulare un errore sollevando un’eccezione con l’istruzione throw.
File DEFAULT.ASPX
<%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master"
AutoEventWireup="true" CodeBehind="default.aspx.cs"
Inherits="WebApplication1._default" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1"
runat="server">
<h2>Home</h2><br />
<asp:Label ID="lblOra" runat="server"></asp:Label>
</asp:Content>
File DEFAULT.ASPX.CS
using System;
namespace WebApplication1 {
public partial class _default : System.Web.UI.Page {
protected void Page_Load(object sender, EventArgs e)
{ InvalidOperationException ex1 = new InvalidOperationException("An
InvalidOperationException ");
try
{ throw ex1; }
Server side
um 146 di 243
catch (Exception exsss)
{ throw new CustomException(ex1.Message, ex1, "E' stata eseguita
un’operazione non valida", "l'esecuzione si è interrotta", "riprova a caricare la pagina", "se
il problema persiste scrivi a: webmaster@pippo.it"); }
}
}
}
Si è istanziata un’eccezione di tipo InvalidOperationException e si è sollevata dentro ad un
blocco try.
Questo fa in modo che l’esecuzione del codice passi all’interno del blocco catch dove si
solleva l’eccezione personalizzata di tipo CustomException.
Al costruttore di questa eccezione si passa il messaggio di errore dell’eccezione originale.
A questo punto il CLR genererà un’eccezione non gestita perché si è sollevata
un’eccezione che non sarà gestita da nessun’altra parte nell’applicazione web.
Questo significa che andrà in esecuzione il metodo Application_Error che metterà
l’eccezione personalizzata in sessione e farà un redirect alla pagina di errore area utente.
Testare l’applicazione web.
Impostare la pagina DEFAULT.ASPX come pagina iniziale.
Inserire un breakpoint nel metodo Page_Load del file DEFAULT.ASPX.CS.
Inserire un breakpoint nel metodo Application_Error del file GLOBAL.ASAX.
Inserire un breakpoint nel metodo Page_Load del file ERRORPAGE.ASPX.
3. A LIVELLO di PAGINA
La gestione degli errori su ogni pagina o su pagine particolari è gestita con il codice
seguente.
File DEFAULT2.ASPX.CS
using System;
namespace WebApplication1 {
public partial class _default2 : System.Web.UI.Page {
protected void Page_Load(object sender, EventArgs e)
{ throw new InvalidOperationException("An InvalidOperationException "); }
private void Page_Error(object sender, EventArgs e)
{ // Get last error from the server.
Exception exc = Server.GetLastError();
// prendi l'ultimo errore dal server
if (exc is InvalidOperationException) {
// passa l'errore alla pagina di errore
Server.Transfer("ErrorPage2.aspx", true);
}
}
Server side
um 147 di 243
}
}
All’interno del sorgente di una pagina si deve definire il metodo Page_Error e all’interno
del metodo si deve prendere l’errore con il metodo GetLastError delal classe Server.
Se l’eccezione è di tipo InvalidOperationException si chiama la pagina di errore
secondaria ERRORPAGE2.ASPX.
Testare l’applicazione web.
Impostare la pagina DEFAULT2.ASPX come pagina iniziale.
Inserire un breakpoint nel metodo Page_Load del file DEFAULT.ASPX.CS.
Inserire un breakpoint nel metodo Page_ERROR del file DEFAULT.ASPX.CS.
Inserire un breakpoint nel metodo Page_Load del file ERRORPAGE2.ASPX.
4. A LIVELLO di CODICE
Il programmatore gestisce gli errori per risolvere gli inconvenienti o per lo meno informare
dettagliatamente l’utente.
string pippo = "testo";
try
{ // apro una connessione ad un DB
Conn.Open();
// eseguo una query sul DB, converto in decimale la variabile pippo: eccezione
Decimal n = Decimal.Parse(pippo);
}
catch (Exception ex)
{ Server.Transfer("ErrorPage.aspx", true); }
finally
{ // chiudo la connessione
Conn.Close();
}
LOGGING
È buona regola di programmazione registrare gli errori per effettuare un monitoraggio, una
verifica e consentire la loro correzione.
Nel file di log bisognerebbe tenere traccia anche degli eventi principali che caratterizzano
l’applicazione web.
Log4net
Permette di generare log da codice su diversi supporti persistenti.
Può essere usato sia per monitorare gli errori sia per tenere traccia delle operazioni più
importanti svolte durante le sessioni di lavoro dagli utenti.
http://logging.apache.org/log4net
Per utilizzarlo aggiungere le seguenti righe nel file WEB.CONFIG, indicare il percorso
Server side
um 148 di 243
dove memorizzare il log e il nome del file
<log4net>
<appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
<file value="F:\Esercizi\asp\WebApplication1\web.log" />
<appendToFile value="true" />
<maximumFileSize value="1024KB" />
<maxSizeRollBackups value="5" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date %level %logger - %message%newline" />
</layout>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="RollingFile" />
</root>
</log4net>
Aggiungere un riferimento alla libreria LOG4NET.DLL nel progetto.
Importare la libreria nei file dove si vuole usarla.
using log4net;
Richiamare il metodo
GLOBAL.ASAX.
seguente
nell’evento
Application_Start
presente
nel
file
protected void Application_Start(object sender, EventArgs e)
{ log4net.Config.XmlConfigurator.Configure(); }
Definire il log nella pagina dove serve e richiamare il suo metodo Error per annotare
l’errore.
private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.
GetCurrentMethod().DeclaringType);
log.Error("Si è verificato un errore:", ex);
La variabile di tipo ILog rappresenta il log e si passa al suo metodo Error il messaggio di
errore e l’eccezione intercettata.
Esempio, file di log creato da Log4net.
Server side
um 149 di 243
ELMAH
Funziona esclusivamente su applicazioni ASP.NET.
Non si deve scrivere codice e l’installazione aggiunge in automatico le righe di
configurazione nel file WEB.CONFIG.
I log prodotti sono consultabili nel file ELMAH.AXD.
Permette di monitorare le sole eccezioni non gestite dall’applicazione
http://code.google/p/elmah
CONTROLLI DI VALIDAZIONE/VALIDATORI
ASP.NET supporta nativamente la validazione dei dati all’interno di un form perchè ogni
validatore deriva da una classe BaseValidator che a sua volta deriva dalla classe Label,
quindi il programmatore non dovrà più sviluppare codice JavaScript per realizzare le
stesse cose.
In effetti l’obiettivo finale dell’utilizzo di un controllo di validazione è quello di mostrare
un’informazione, tramite un’etichetta di testo che illustri se e quale errore si sia verificato
nel compilare i campi di una pagina client side o anche in qualche operazione avvenuta
server side.
Ogni controllo validatore può riferirsi ad un controllo d’input, per esempio una TextBox,
una DropDownList e ognuno dei controlli d’input potrà essere affidato alla verifica da parte
di più controlli di validazione.
Per esempio, nel caso in cui la TextBox debba contenere un indirizzo email e questo
debba essere obbligatoriamente inserito, si potrebbe associare alla casella di testo sia un
controllo che verifichi la validità del formato sia un secondo che verifichi l’avvenuta
compilazione del campo.
La classe Page fornisce una proprietà Validators che restituisce la collezione di tutti i
controlli validatori presenti nella pagina stessa.
I controlli presenti nella collezione possono essere poi validati tutti in un sol colpo, ad
esempio quando si fa clic su un pulsante per inviare i dati di un modulo al server, oppure
singolarmente.
Per gestire il primo caso, la classe Page fornisce il metodo Validate, posseduto anche da
ogni controllo derivato da BaseValidator che mette poi a disposizione una proprietà IsValid
che restituisce un valore booleano indicante se il controllo contiene dati validi, impostato
appunto dopo la chiamata al metodo Validate.
Per essere certi che la convalida sia avvenuta, server side, si deve richiamare la proprietà
IsValid della classe Page, dimenticando di farlo, l’effetto sarà di non verificare la convalida,
dato che quella client side può essere aggirata disattivando il supporto JavaScript.
Per associare un controllo di validazione ad un controllo d’input, la classe BaseValidator
fornisce la proprietà ControlToValidate che dev’essere impostata utilizzando il valore della
proprietà ID del controllo destinatario della validazione.
Le classi che è possibile validare sono identificate dall’attributo ValidateProperty e fra
questi, quelli utilizzati sono i controlli TextBox, ListBox, DropDownList, File Upload,
RadioButtonList, mentre non sono associabili ad un controllo validatore i controlli
CheckBox, RadioButton e CheckBox List.
Ciò non significa che questi ultimi non sono verificabili ma si dovrà fare del lavoro in più,
con un validatore personalizzato.
Ogni validatore possiede la proprietà Display che può assumere i seguenti valori.
 Static: lo spazio per la Label contenente il messaggio di errore è riservato sulla pagina
e occupato sia che l’errore si verifichi sia nel caso contrario.
 Dynamic: il calcolo dello spazio da allocare sulla pagina è fatto dinamicamente, questo
è di fondamentale importanza quando si utilizzano più controlli di validazione affiancati,
in quanto nel caso si verifichi solo uno degli errori e magari non il primo, la Label che
Server side
um 150 di 243
mostra l’errore apparirebbe in mezzo alla pagina, lasciando uno sgradevole spazio
bianco riservato staticamente ad un altro errore.
 None: non visualizza il messaggio anche in caso di errore.
Esempio, modulo di registrazione.
Tutti i campi sono obbligatori tranne il campo Anno di nascita.
Il campo Username dev’essere compilato con una stringa lunga da 5 a 15 caratteri.
Il campo Password dev’essere confermato dal campo di Conferma password.
Il campo Email deve contenere una stringa nel formato nome@dominio.est.
Verificare i campi obbligatori
Quando è necessario rendere obbligatoria la compilazione di un campo d’input, si usa il
validatore RequiredFieldValidator.
Il primo passo è creare il controllo aggiungendolo alla pagina, in corrispondenza del punto
in cui si vuole visualizzare il messaggio, trascinandolo dalla barra degli strumenti di Visual
Studio, oppure inserendo nel codice HTML il TAG corrispondente.
Per esempio per controllare che il campo Username sia stato compilato si deve scrivere il
codice seguente.
<td style="width: 158px; text-align: left;">
<asp:TextBox ID="txtUsername" runat="server" Width="148px"></asp:TextBox></td>
</td>
<td>
<asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server"
ControlToValidate="txtUsername"
Display="Dynamic" ErrorMessage="Username
obbligatoria">*</asp:RequiredFieldValidator>
<asp:CustomValidator ID="UsernameLengthValidator" runat="server"
ErrorMessage="Username deve essere lungo da 5 a 15 caratteri"
OnServerValidate="UsernameLengthValidator_ServerValidate"
ControlToValidate="txtUsername" SetFocusOnError="True"
ClientValidationFunction="ControllaLunghezzaUsername" Display="Dynamic"
EnableClientScript="False"></asp:CustomValidator>
</td>
Il controllo d’input di cui verificare l’avvenuta compilazione, è indicato tramite la proprietà
ControlToValidate.
La proprietà ErrorMessage serve a impostare il messaggio da visualizzare nei casi in cui si
verifichi un errore, nell’esempio l’assenza della stringa nel campo txtUsername.
Se al posto della proprietà ErrorMessage o in concomitanza ad essa, s’imposta la
proprietà Text, il valore di quest’ultima sarà visualizzato in ogni caso all’esecuzione della
pagina.
Così facendo sarà possibile impostare un valore che indichi all’utente d’inserire lo
Username, per esempio un (*), mentre il valore di ErrorMessage potrà essere visualizzato
Server side
um 151 di 243
in un riepilogo definito tramite un ValidationSummary.
Eseguire l’applicazione e premere il pulsante Invia senza compilare alcuno dei campi.
La pagina web ha una serie di errori mostrati sia con singoli validatori sia con un
ValidationSummary e anche con una MessageBox.
Confrontare due campi
Il controllo CompareValidator esegue un confronto fra i valori inseriti in due campi grazie
alla proprietà ControlToCompare, oppure fra il contenuto di un campo e un altro valore
costante assegnato con ValueToCompare, la proprietà Type specifica il tipo di valore
mentre Operator il tipo di operatore da usare.
<asp:CompareValidator ID="CompareValidator1" runat="server"
ControlToCompare="txtPassword"
ControlToValidate="txtConfermaPassword" ErrorMessage="I campi password non
coincidono">
</asp:CompareValidator>
È necessario indicare il controllo da validare, mediante il suo ID, nell’esempio
txtConfermaPassword, il controllo con cui eseguire il confronto è invece determinato dalla
proprietà ControlToValidate, quindi la proprietà ErrorMessage contiene la stringa da
mostrare nel caso di valore inserito non valido.
Se, invece, si vuol eseguire un controllo fra il contenuto di un campo e una costante, si
possono utilizzare diverse proprietà.
Per esempio, verificare che il campo Anno di nascita, se compilato, contenga un valore
numerico e che sia minore dell’anno corrente.
Il tipo di confronto da eseguire è determinato dalla proprietà Operator che può essere
impostata ad uno dei valori dell’enumerazione ValidationCompareOperator, i cui membri
definiscono gli operatori di confronto.
Server side
um 152 di 243
Per default sarà considerato come Equal, in pratica un confronto di uguaglianza.
Nell’esempio si esegue il controllo da codice e piuttosto che impostare una costante 2023,
si ricava l’anno attuale dalla data del sistema, impostando la proprietà ValueToCompare.
Il valore è intero, allora s’imposta la proprietà Type al valore ValidationDataType.Integer.
protected void Page_Load(object sender, EventArgs e)
{
YearCompareValidator.ValueToCompare = DateTime.Today.Year.ToString();
YearCompareValidator.Type = ValidationDataType.Integer;
YearCompareValidator.Operator = ValidationCompareOperator.LessThan;
}
Verificare intervalli di valori
Il controllo RangeValidator consente di verificare che il valore inserito in un controllo sia
compreso in un intervallo di valori predeterminato oppure calcolato a run-time.
Per esempio, per verificare che il campo Anno contenga un valore positivo e minore di
2023, basta aggiungere il seguente codice di markup.
<asp:TextBox ID="txtAnno" runat="server"></asp:TextBox>
<asp:RangeValidator ID="RangeValidatorAnno" runat="server"
ControlToValidate="txtAnno" ErrorMessage="Inserire un valore fra 0 e 2023"
MaximumValue="2023" MinimumValue="0" Type="Integer">
</asp:RangeValidator>
È impostato il tipo Integer mediante la proprietà Type, mentre l'intervallo di valori
consentito è determinato dai valori dati a MinimumValue e MaximumValue.
La stessa cosa può essere realizzata da codice.
RangeValidatorAnno.MaximumValue = Datetime.Today.Year.ToString();
Espressioni regolari
Le applicazioni ASP.NET hanno il controllo RegularExpressionValidator per convalidare
l’input inserito dagli utenti nelle TextBox delle Webforms.
Con la proprietà ValidationExpression è possibile impostare il pattern d’input corretto, in
modo da segnalare all’utente eventuali errori e impedire l’invio dei dati.
Nella finestra Proprietà, se si fa clic sulla proprietà ValidationExpression del controllo, è
possibile utilizzare alcuni template offerti dalla finestra di dialogo.
Server side
um 153 di 243
<td style="width: 158px; height: 21px">
<asp:TextBox ID="txtEmail" runat="server" Width="148px"></asp:TextBox>
</td>
<td style="height: 21px">
<asp:RequiredFieldValidator ID="RequiredFieldValidator4" runat="server"
ControlToValidate="txtEmail"
Display="Dynamic" ErrorMessage="Email obbligatoria">*</asp:RequiredFieldValidator>
<asp:RegularExpressionValidator ID="EmailRegularExpressionValidator" runat="server"
ControlToValidate="txtEmail" ErrorMessage="Indirizzo non valido"
ValidationExpression="\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*">
</asp:RegularExpressionValidator></td>
Visual Studio permette d’impostare alcune delle espressioni regolari più comuni.
Fare clic su Modifica/Trova e sostituisci/Sostituisci nei file (CTRL+MAIUSC+H).
Nella finestra che si apre espandere Opzioni di ricerca, segno di spunta in Usa
Espressioni regolari, i pulsanti dei campi Trova: e Sostituisci con: sono disponibili.
Server side
um 154 di 243
Validazione personalizzata
Se nessuno dei precedenti validatori fornisse le funzionalità ricercate o se si volesse
validare un controllo che non è marcato con l’attributo ValidationProperty, si usa il controllo
CustomValidator.
Nell’esempio, il campo Username deve contenere una stringa di lunghezza minima 5
caratteri e massima di 15.
Per eseguire questa verifica si possono usare due metodi.
Client side
Inserire il nome della funzione JavaScript, ControllaLunghezzaUsername, da eseguire
nella proprietà ClientValidationFunction.
La proprietà ValidateEmptyText indica che il contenuto dev’essere verificato anche se il
campo è vuoto.
Il parametro args ricava il valore del campo e imposta la validità con la proprietà IsValid.
function ControllaLunghezzaUsername(source, args)
{ if(args.Value.length >4 && args.Value.length <16 )
args.IsValid=true;
else
args.IsValid = false;
}
Server side
um 155 di 243
Server side.
Bisogna gestire l’evento ServerValidate.
protected void UsernameLengthValidator_ServerValidate(object source,
ServerValidateEventArgs args)
{
if (args.Value != null) {
int len = args.Value.Length;
args.IsValid = (len > 4 && len < 16);
}
}
È anche possibile tralasciare d’impostare la proprietà ControlToValidate e quindi ricavare
server side i valori contenuti in tutti i controlli che si vuole, dato che in tal caso la proprietà
Value del parametro args sarà uguale ad una stringa vuota.
Bisogna però tenere presente che il metodo UsernameLengthValidator_ServerValidate è
eseguito dopo un PostBack e quindi solo nel caso in cui non ci siano altri errori gestiti da
altri validatori nella pagina a bloccare tale PostBack.
Riepilogare gli errori
Il controllo ValidationSummary permette di riepilogare in una singola Label tutti gli
eventuali errori trovati dai validatori di una pagina.
È possibile mostrare la lista di errori in differenti modi, definiti dall’enumerazione
ValidationSummaryDisplayMode, impostando la proprietà DisplayMode del controllo.
Per default essa è pari al valore BulletList, in pratica è un elenco puntato.
È possibile anche fornire un testo d’intestazione con la proprietà HeaderText.
Oltre alla Label sulla pagina, in corrispondenza del ValidationSummary, è possibile
visualizzare una MessageBox con lo stesso riepilogo, impostando la proprietà
ShowMessage Box.
<asp:ValidationSummary ID="ValidationSummary1" runat="server"
HeaderText="Riepilogo degli errori" ShowMessageBox="True" Width="411px" />
Il riepilogo degli errori è visualizzato solo se c’è almeno un errore nella pagina e se la
proprietà ShowSummary non è stata impostata a False.
Esempio.
File DEFAULT1.ASPX
<%@ Page Language="C#" CodeFile="Validator.aspx.cs" Inherits="Form" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Validazione dati</title>
</head>
<body>
<form runat="server">
<div>
<asp:PlaceHolder ID="EntryForm" runat="server">Inserisci il tuo nome:
<asp:TextBox ID="txtNome" runat="server" />
<asp:RequiredFieldValidator ID="RequiredFieldValidator1"
runat="server" ControlToValidate="txtNome"
ErrorMessage=" Casella di testo vuota!" />
<br />
<asp:Button ID="btnConferma" runat="server" Text="Conferma"
Server side
um 156 di 243
OnClick="VisualizzaNome" />
</asp:PlaceHolder>
<asp:PlaceHolder ID="Results" runat="server" Visible="false">
Il tuo nome è
<asp:Literal ID="lblNome" runat="server" />
</asp:PlaceHolder>
</div>
</form>
</body>
</html>
File DEFAULT1.ASPX.CS
using System;
using System.Web.UI;
public partial class Form3 : Page {
protected void VisualizzaNome(object sender, EventArgs e)
{ EntryForm.Visible = false;
Results.Visible = true;
lblNome.Text = txtNome.Text;
}
}
RequiredFieldValue
Effettua il controllo più semplice: verifica che ci sia del testo.
UnobtrustiveValidation
Grazie all’adaptive rendering di ASP.NET, è possibile attivare questa funzionalità
continuando ad utilizzare i validatori.
Uno switch nel WEB.CONFIG e l’uso della libraria di jQuery consentono un sistema di
validazione estendibile, personalizzabile e moderno.
<add name="ValidationSettings:UnobtrusiveValidationMode" value="WebForms" />
L’attivazione
può
avvenire
anche
da
codice,
impostando
la
proprietà
SYSTEM.WEB.UI.VALIDATIONSETTINGS.UNOBTRUSIVEVALIDATIONMODE.
A questo punto, il codice prodotto dai controlli sarà differente: si avranno degli attributi
nell’HTML e non una serie di registrazioni, nella pagine, d’istruzioni JavaScript, includere
nell’applicazione la libreria MICROSOFT.JQUERY.UNOBTRUSIVE.VALIDATION.
ANTIXSS LIBRARY
È una libreria dedicata alla sicurezza, applica meccanismi più robusti di controllo delle
stringhe ed è maggiormente indicata quando si vuole applicare un algoritmo più
aggressivo alla gestione dei dati che arrivano dall’utente.
Va attivata agendo sul WEB.CONFIG.
Server side
um 157 di 243
<httpRuntime encoderType =
"System.Web.Security.AntiXss.AntiXssEncoder,System.Web,Version=4.0.0.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
Sfrutta la possibilità per alcune chiamate, metodi HtmlEncode/Decode UrlEncode/Decode
di HttpUtility, di sfruttare il provider model e, quindi, di essere rimappate su
un’implementazione differente.
In questo caso, le chiamate che già si hanno a questi metodi sono automaticamente
rigirate sull’implementazione basata sull’AntiXSS Library, con benefici da parte della
sicurezza.
Anche il sistema di validazione delle richieste è stato migliorato, semplificando le modalità
con cui introdurre le eccezioni.
Per aggiungere le regole di validazione sui dati, si usano gli attributi di validazione
contenuti nel namespace System.ComponentModel.DataAnnotations.
Creare un’apposita classe all’interno della quale, grazie all’utilizzo degli attributi, si
possono definire le regole di validazione.
Le classi che costituiscono il modello dati creato con EF sono classi partial.
Ciò consente di creare una nuova classe partial con lo stesso nome e nello stesso
namespace e aggiungervi la logica di controllo personalizzata.
Esempio, creare una classe Contatto e decorarla con l’attributo MetaDataType che accetta
come parametro un tipo che identifica una classe destinata a contenere le regole di
validazione e i metadati necessari per istruire il run-time di ASP.NET MVC nel trattare i
dati.
namespace NegozioMvcApp.Models {
[MetadataType(typeof(ContattoMetadata))]
public partial class Contatto
{}
class ContattoMetadata {
[ScaffoldColumn(false)]
public object IDContatto;
[Required(ErrorMessage="Campo nome obbligatorio")]
[StringLength(50, MinimumLength=5)]
public object Nome;
[RegularExpression(@"\b[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b",
ErrorMessage="Inserisci una email valida")]
public object Email;
}
}
Nella classe ContattoMetadata sono esplicitati i campi corrispondenti ai dati dell’entità
prodotto.
Non è importante che siano property e che siano dello stesso tipo di dato definito nel
modello.
L’importante è che abbiano lo stesso nome delle proprietà della classe Prodotto in quanto
svolgono il solo scopo di segnaposto per applicare gli attributi di validazione.
La classe permette di concentrare in un unico posto le regole di validazione.
Sono a disposizione numerosi attributi di validazione.
DataTypeAttribute
Consente di specificare il tipo di dato da associare ad un campo dell’entità.
Server side
um 158 di 243
EditableAttribute
Specifica se il campo è editabile o readonly.
RangeAttribute
Consente di specificare un range di valori tra un minimo e un massimo.
RegularExpressionAttribute
Per specificare una regular expression che sarà valutata nel momento in cui il valore sarà
impostato.
RequiredAttribute
Rende il campo obbligatorio.
ScaffoldColumnAttribute
Istruisce il run-time a non visualizzare il campo nell’interfaccia utente.
StringLengthAttribute
Per specificare un numero massimo di caratteri, accetta altri parametri come il numero
minimo consentito.
UIHintAttribute
Consente di specificare un custom template da utilizzare per visualizzare il campo
nell’interfaccia utente.
Se gli attributi di validazione presenti non fossero sufficenti, è possibile creare attributi
personalizzati creando una classe che derivi dalla classe base ValidationAttribute.
Esempio, creare un attributo per la validazione del campo Prezzo.
L’attributo creato è definito in una nuova classe in cui è presente una proprietà che
consente di specificare un prezzo minimo e una proprietà booleana IsValid nella quale è
possibile indicare le regole di validazione.
Se il valore Prezzo è NULL non sarà dichiarato invalido consentendo così di non rendere
obbligatorio questo valore.
Per l’obbligatorietà dei dati si può utilizzare l’attributo Required.
using System;
using System.ComponentModel.DataAnnotations;
namespace NegozioMVCApp.Models {
public class PrezzoAttribute : ValidationAttribute
{ public double PrezzoMinimo
{ get; set; }
public override bool IsValid(object value)
{ if (value == null)
return true;
var prezzo = Convert.ToDouble(value);
if (prezzo < PrezzoMinimo)
return false;
// ...altre regole di validazione
return true;
}
}
}
Usare l’attributo PrezzoAttribute nella classe ProdottoMetadata decorando il campo
Server side
um 159 di 243
Prezzo.
using System.ComponentModel.DataAnnotations;
namespace NegozioMVCApp.Models {
[MetadataType(typeof(ProdottoMetatada))]
public partial class Prodotto
{}
class ProdottoMetatada {
[Prezzo(PrezzoMinimo = 5.50)]
public object Prezzo;
[Required]
[StringLength(50, MinimumLength = 5]
public object Nome;
}
}
Anche ASP.NET MVC può utilizzare la libreria System.ComponentModel.DataAnnotations
per decorare le classi del modello.
È possibile definire che l’IDCategoria sia visualizzato in fase di editing con una drop down
list presente in un apposito template.
Per creare un template per visualizzare la proprietà IDCategoria, quando l’utente modifica
i dati, si deve creare una cartella di nome EDITORTEMPLATES all’interno della cartella
del controller Prodotti.
Il path del template di nome ucCategoria utile per la proprietà IDCategoria utilizzato in fase
di editing sarà: \VIEWS\PRODOTTI\EDITORTEMPLATES\UCCATEGORIA.ASPX.
Mentre il template utilizzabile per la visualizzazione avrà il seguente path.
\VIEWS\PRODOTTI\DISPLAYTEMPLATES\UCCATEGORIA.ASPX
Se il template creato non è legato solo ai prodotti ma può essere utilizzato per visualizzare
parti d’interfaccia utente comuni ad altri dati e controller allora si deve creare la sotto
cartella EDITORTEMPLATES e DISPLAYTEMPLATES all’interno della cartella SHARED.
\VIEWS\SHARED\EDITORTEMPLATES\UCCATEGORIA.ASPX
Il contenuto del template ucCategoria per l’editing, dovrà visualizzare una lista drop down
popolata con l’elenco delle categorie e il valore corrente della proprietà IDCategoria
selezionato.
Si può utilizzare l’HTML helper Html.DropDownList e passargli l’insieme di categorie come
SelectList.
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<%= Html.DropDownList("", new SelectList((IEnumerable)ViewData["Categorie"],
"IDCategoria","Descrizione", Model)) %>
L’oggetto ViewData legge l’elenco che il controller Prodotti dovrà aver prima popolato.
Nella view di editing dell’entità prodotto, per fare in modo che il run-time di ASP.NET MVC
esamini i metadati e utilizzi le istruzioni che si sono definite, si può utilizzare un HTML
helper che si chiama Html.EditorForModel.
Richiamando questo metodo nella view sarà creato il markup HTML necessario per
reindirizzare i controlli per ogni proprietà del modello.
<% using (Html.BeginForm()) {%>
<fieldset>
<legend>Fields</legend>
<%= Html.EditorForModel() %>
<p>
<input type="submit" value="Save" />
Server side
um 160 di 243
</p>
</fieldset>
<% } %>
Per visualizzare i dettagli con un template, usare il metodo Html.DisplayForModel.
Grazie ai metadati associabili alle entità e ai template si può decidere come visualizzare i
dati in un punto unico, non ripetendo codice e in maniera più ordinata.
Per dichiarare nella classe dei metadati di utilizzare il template ucCategoria si usa
l’attributo UIHint.
[MetadataType(typeof(ProdottoMetatada))]
public partial class Prodotto
{}
class ProdottoMetatada
{ [UIHint("ucCategoria")]
public int IDCategoria { get; set; }
}
Server side
um 161 di 243
APPLICAZIONI MULTILINGUA
INTRODUZIONE
Globalizzazione e Localizzazione sono due facce della stessa medaglia e costituiscono la
base del processo d’internazionalizzazione delle applicazioni.
Globalizzazione
È il processo con cui si prepara l’applicazione a supportare diversi linguaggi.
Localizzazione
È il processo che si occupa della traduzione dell’applicazione nella lingua desiderata.
Le risorse di un’applicazione che necessitano di una traduzione sono i seguenti.
 Immagini: alcune immagini di un’applicazione potrebbero contenere del testo che
dovrà essere localizzato.
 Testi statici: anche label, descrizioni testuali statiche, tooltip devono essere tradotte
nelle lingue supportate dall’applicazione.
 Testi da DB: le applicazioni fanno uso di contenuti provenienti da DB.
 Date, numeri: anche se queste informazioni non devono essere “tradotte”, andranno,
comunque, visualizzate in modo diverso in base alla lingua di destinazione, per
esempio il formato delle date: il 20 ottobre 2023 è scritto 20/10/2023 per la lingua
italiana, 10/20/2023 per l’inglese americano.
DB
Server side
um 162 di 243
Creare il DB e la tabella che conterrà le informazioni sui prodotti.
Campi: nome, descrizione, prezzo e data disponibilità.
Chiave della tabella: è composta dalla coppia idProdotto e lingua.
Popolare la tabella.
PROGETTO
Una scheda legge i dettagli di un prodotto da una tabella di DB e li visualizza in una
pagina web.
Nel .NET Framework è presente il namespace System.Globalization destinato alla
Server side
um 163 di 243
localizzazione delle informazioni.
La classe principale è CultureInfo che rappresenta una cultura specifica e ne definisce la
visualizzazione di numeri, valute, date ed altro.
La classe RegionInfo fornisce informazioni sul paese.
Altre classi utili sono NumberFormatInfo per la formattazione dei numeri e
DatetimeFormatInfo per la formattazione delle date.
Culture
Per specificare in modo univoco una cultura, è stato introdotto uno standard chiamato
RFC (Request for Comments) 1766 che definisce codici univoci per ciascuna di esse.
Questi sono formati da due parti separate da un (-).
1. La prima (in minuscolo) rappresenta la lingua.
2. La seconda (in maiuscolo) specifica il paese.
Esempi.
it-IT: italiano – Italia.
en-GB: inglese – Regno Unito.
en-US: inglese – Stati Uniti.
File LANGUAGECONTROLLER.ASCX
È uno “User Control” in cui inserire i pulsanti per cambiare la lingua attiva e il codice
necessario per notificarne il cambiamento all’applicazione.
Il controller non fa altro che scrivere un cookie con il nome della lingua selezionata e
ricaricare la pagina.
File GLOBAL.ASAX
<%@ Application Language="VB" %>
<%@ Import Namespace="System.Globalization" %>
<%@ Import Namespace="System.Threading" %>
<script runat="server">
Sub Application_BeginRequest(ByVal sender As Object, ByVal e As EventArgs)
Dim lang As CultureInfo
If Request.Cookies("culture") Is Nothing Then
Response.Cookies("culture").Value = "it-IT"
End If
Try
lang = New CultureInfo(Request.Cookies("culture").Value)
Catch
lang = New CultureInfo("it-IT")
End Try
Thread.CurrentThread.CurrentCulture = lang
Thread.CurrentThread.CurrentUICulture = lang
End Sub
</script>
Il metodo Application_BeginRequest, legge il cookie che è stato scritto; crea un oggetto
CultureInfo in base alla lingua selezionata e imposta la lingua del Thread corrente.
È eseguito a ogni richiesta di pagina, questo consente di risparmiare codice in un sito che
ha più pagine perchè non si deve inserire il codice per l’impostazione della lingua in tutte
le pagine
La riga seguente.
lang = New CultureInfo(Request.Cookies("culture").Value)
Crea l’oggetto CultureInfo in base alla lingua selezionata dall’utente.
Server side
um 164 di 243
Le righe seguenti.
Thread.CurrentThread.CurrentCulture = lang
Thread.CurrentThread.CurrentUICulture = lang
Assegnano l’oggetto CultureInfo al Thread corrente.
CurrentCulture specifica la cultura utilizzata per visualizzare informazioni e dati, è usata
per l’ordinamento delle stringhe, la visualizzazione di date, numeri e valute.
CurrentUICulture permette di specificare la cultura per l’interfaccia utente ed è utilizzata
quando si ricercano le informazioni nei file di risorsa.
File DEFAULT.ASPX
Crea la pagina che visualizza i prodotti.
È presente il controllo che permette di cambiare la lingua corrente.
Gli altri componenti sono: un’immagine che conterrà il titolo della pagina, le label con le
descrizioni e alcune TextBox che conterranno i dati letti dal DB.
Per localizzare le immagini, creare la cartella IMAGES e, al suo interno, tante cartelle
quante sono le lingue che si vogliono supportare, chiamandole con la sigla della lingua in
questione.
Nell’esempio sono quattro: it-IT, en-US, fr-FR e de-DE.
A questo punto, creare le quattro immagini con il titolo nelle diverse lingue e salviarle nelle
cartelle della lingua corrispondente con nome HEADER.GIF.
File DEFAULT.ASPX.VB
Dichiarare una variabile globale che rappresenta la lingua selezionata.
Private lang As CultureInfo
Creare la procedura seguente.
Protected Sub Page_PreInit(ByVal sender As Object, ByVal e As System.EventArgs)
Handles Me.PreInit
lang = Thread.CurrentThread.CurrentCulture
' immagine
img_titolo.ImageUrl = "images/" & lang.Name & "/header.gif"
Legge il valore di CurrentCulture e assegna l’immagine corretta utilizzando la proprietà
Name di lang.
Per localizzare le etichette con le descrizioni e altri elementi della pagina nelle varie lingue
si usano i file di risorsa.
File RESOURCE.RESX
È il file per la lingua di default, è composto da due colonne.
1. Nome: nomi delle risorse cui accedere poi da codice per localizzare i contenuti.
2. Valore: inserire il valore della risorsa.
I file di risorsa sono dei file che utilizzano XML per l’accesso ai dati e possono contenere
testi, immagini, icone e altri oggetti.
Per le altre quattro lingue, chiamare il file RESOURCE.LINGUA.RESX, per esempio il
francese si chiama RESOURCE.FR-FR.RESX.
Per localizzare i testi delle etichette si usa la procedura Page_PreInit.
Inserire le seguenti righe.
' etichette
lbl_nome.Text = Resource.lbl_nome
Server side
um 165 di 243
lbl_descrizione.Text = Resource.lbl_descrizione
lbl_prezzo.Text = Resource.lbl_prezzo
lbl_disponibile_dal.Text = Resource.lbl_disponibile_dal
' titolo Pagina
Page.Title = Resource.titolo_pagina
End Sub
Così facendo, i testi delle label e il Title della pagina saranno letti dinamicamente dai file di
risorsa in base alla lingua selezionata.
File PRODOTTO.VB
Legge i contenuti dal DB.
Creare la classe Prodotto per mappare i campi della tabella prodotti.
La classe ha un costruttore overloaded che legge dal DB i dettagli del prodotto in base alla
lingua e li salva nei campi privati accessibili tramite delle proprietà di sola lettura.
File GLOBALIZER.VB
Date e numeri hanno modalità di visualizzazione diversa in base alla lingua, basti pensare
al separatore dei decimali che può essere il punto oppure la virgola.
Per visualizzare correttamente questi ultimi, creare una classe Globalizer che contiene
due metodi FormatData e FormatNumero.
Server side
um 166 di 243
Server side
um 167 di 243
RILEVAZIONE DEL BROWSER
INTRODUZIONE
È possibile impostare il valore delle proprietà dei server control in base al browser
utilizzato per la visualizzazione della pagina
Esempio, inserire una Label il cui testo visualizzato sia diverso a seconda che l’utente stia
utilizzando IExplorer o Firefox.
Similmente, si può realizzare un pulsante il cui evento OnClientClick vari a seconda del
browser utilizzato.
<asp:Label ID="lblVariableLabel" runat="server" ie:Text="Testo per gli utenti che utilizzano
Internet Explorer" mozilla:Text="Testo per gli utenti che utilizzano
Firefox" Text="Testo per tutti gli altri utenti">
</asp:Label>
<asp:Button ID="txtVariableButton" runat="server" ie:Text="Pulsante per utenti IE"
ie:OnClientClick="javascript:alert('Internet Explorer');"
mozilla:Text="Pulsante per utenti Firefox"
mozilla:OnClientClick="javascript:alert('Mozilla Firefox');"
Text="Pulsante per altri browser" OnClientClick="javascript:alert('Altri
browser');"></asp:Button>
Se nell’ambito di uno stesso controllo vi sono proprietà che presentano un prefisso queste
sono valutate per prime e solo se il browser utilizzato dall’utente non rientra in nessuno di
quelli per cui è stato previsto uno specifico valore della proprietà, allora è preso in
considerazione il valore di default, senza prefisso.
Non sono solo le proprietà “semplici” a poter essere gestite in maniera condizionale sulla
base del browser utilizzato ma anche i controlli di tipo template, per esempio il controllo
Menu.
<asp:Menu runat="server" id="myVariableMenu" BackColor="#B5C7DE"
DynamicHorizontalOffset="2" Font-Names="Verdana" Font-Size="0.8em"
ForeColor="#284E98" StaticSubMenuIndent="10px">
<ie:Items>
<asp:MenuItem Text="Voce 1 per IE" />
<asp:MenuItem Text="Voce 2 per IE" />
</ie:Items>
<mozilla:Items>
<asp:MenuItem Text="Voce 1 per Firefox" />
<asp:MenuItem Text="Voce 2 per Firefox" />
</mozilla:Items>
<DynamicHoverStyle BackColor="#284E98" ForeColor="White" />
<DynamicMenuItemStyle HorizontalPadding="5px" VerticalPadding="2px" />
<DynamicMenuStyle BackColor="#B5C7DE" />
<DynamicSelectedStyle BackColor="#507CD1" />
<Items>
<asp:MenuItem Text="Voce 1 per altri
browser" />
<asp:MenuItem Text="Voce 2 per altri
browser" />
</Items>
Server side
um 168 di 243
<StaticHoverStyle BackColor="#284E98" ForeColor="White" />
<StaticMenuItemStyle HorizontalPadding="5px" VerticalPadding="2px" />
<StaticSelectedStyle BackColor="#507CD1" />
</asp:Menu>
Le voci di menu saranno diverse per ciascun browser considerato.
Tutti i prefissi utilizzabili si possono trovare nella cartella seguente.
C:\WINDOWS\MICROSOFT.NET\FRAMEWORK64\V4.0.30319\CONFIG\BROWSERS
Dove sono memorizzati diversi file con estensione .BROWSER che contengono, per
ciascun browser, l’ID che si può utilizzare per ciascuna specifica versione.
File CHROME.BROWSER
<browsers>
<!-- Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/530.1 (KHTML, like
Gecko) Chrome/2.0.168.0 Safari/530.1 -->
<browser id="Chrome" parentID="WebKit">
<identification>
<userAgent match="Chrome/(?'version'(?'major'\d+)(\.(?'minor'\d+)?)\w*)" />
</identification>
<capabilities>
<capability name="browser"
value="Chrome" />
<capability name="majorversion"
value="${major}" />
<capability name="minorversion"
value="${minor}" />
<capability name="type"
value="Chrome${major}" />
<capability name="version"
value="${version}" />
<capability name="ecmascriptversion"
value="3.0" />
<capability name="javascript"
value="true" />
<capability name="javascriptversion"
value="1.7" />
<capability name="w3cdomversion"
value="1.0" />
<capability name="supportsAccesskeyAttribute"
value="true" />
<capability name="tagwriter"
value="System.Web.UI.HtmlTextWriter" />
<capability name="cookies"
value="true" />
<capability name="frames"
value="true" />
<capability name="javaapplets"
value="true" />
<capability name="supportsCallback"
value="true" />
<capability name="supportsDivNoWrap"
value="false" />
<capability name="supportsFileUpload"
value="true" />
<capability name="supportsMaintainScrollPositionOnPostback" value="true" />
<capability name="supportsMultilineTextBoxDisplay" value="true" />
<capability name="supportsXmlHttp"
value="true" />
Server side
um 169 di 243
<capability name="tables"
</capabilities>
</browser>
</browsers>
value="true" />
In alternativa, è possibile creare dei file .BROWSER personalizzati posizionandoli
all’interno dell’applicazione nella cartella APP_BROWSERS e rispettando lo schema XML.
Server side
um 170 di 243
SEO (SEARCH ENGINE OPTIMIZATION)
INTRODUZIONE
È una tecnica volta a ottimizzare l’indicizzazione di un sito all’interno dei motori di ricerca.
L’URL routing consente di rigirare le richieste su una pagina, a fronte di un URL più
lungo.
In applicazioni dal contenuto dinamico, è frequente l’uso di parametri inseriti in querystring
per caricare informazioni e generare pagine per ogni specifica richiesta.
Questo approccio non è il migliore da adottare, perché non contiene informazioni utili
nell’URL
Queste informazioni, come una descrizione breve, possono essere utili tanto ai motori di
ricerca, quanto all’utente che, da un URL, può capire meglio il contenuto di un indirizzo.
Per sfruttare l’URL routing si devono registrare gli URL nel file seguente.
Gli URL sono costruiti nelle seguenti sezioni.
NomeController / NomeAction / Parametro
È possibile aggiungere regole di routing, ASP.NET quando riceve una richiesta analizza le
regole nell’ordine con cui sono registrate.
Prima le regole più specifiche e poi a seguire quelle più generiche fino a quelle di default.
File GLOBAL.ASAX
<%@ Application Language="C#" %>
<%@ Import Namespace="System.Web.Routing" %>
<script RunAt="server">
protected void Application_Start(object sender, EventArgs e)
{
RouteTable.Routes.Add("ProductsRoute",
new Route("products/{ProductID}({ProductName}",
new PageRouteHandler("~/products.aspx")));
ScriptManager.ScriptResourceMapping.AddDefinition("jquery", new
ScriptResourceDefinition()
{ Path = "~/scripts/jquery-1.9.1.min.js",
DebugPath = "~/scripts/jquery-1.9.1.min.js",
CdnPath = "http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.9.1.min.js",
CdnDebugPath = "http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.9.1.js"
});
}
</script>
Quando l’utente fa clic su un pulsante per inviare i dati inseriti in un form oppure quando fa
clic su un link che punta ad un certo indirizzo dell’applicazione ASP.NET MVC, la richiesta
HTTP è analizzata lato server e sulla base della regola di routing presente in questo file il
run-time individua il Controller giusto e la specifica action richiesta.
Server side
um 171 di 243
La route definita rende possibile che tutte le chiamate effettuate a URL del tipo Bicicletta
con ID=15, siano in realtà rigirate alla pagina PRODUCTS.ASPX.
File PRODUCTS.ASPX
All’interno di questa pagina, è possibile accedere al valore di uno o più parametri con una
sintassi particolare che si chiama expression builder.
<%@ Page Language="C#" CodeFile="Products.aspx.cs" Inherits="Products" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Esempio di SEO</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<h1><asp:Literal runat="server" Text="<%$ RouteValue: ProductName %>"
/></h1>
</div>
</form>
</body>
</html>
File PRODUCTS.ASPX.CS
using System.Web.UI;
public partial class Products : Page
{ }
File URLROUTING.ASPX
È possibile creare un link che sfrutti la route, con questa tecnica, al variare del percorso, in
automatico, i link seguiranno la stessa strada, evitando di doverli definire manualmente.
<%@ Page Language="C#" CodeFile="UrlRouting.cs" Inherits="UrlRouting" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Esempio di URL routing</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:HyperLink ID="HyperLink1"
NavigateUrl="<%$ RouteUrl: RouteName=ProductsRoute,ProductID=15,
Server side
um 172 di 243
ProductName = Bicicletta-ASP.NET %>"
runat="server">Bicicletta con ID=15</asp:HyperLink>
</div>
</form>
</body>
</html>
File URLROUTING.CS
using System.Web.UI;
public partial class UrlRouting : Page
{ }
Server side
um 173 di 243
MODULO 6
ASP.NET MVC
Introduzione
ASP.NET MVC vs ASP.NET WebForms
Server side
um 174 di 243
INTRODUZIONE
PAGINA
Permette soluzioni migliori sia per l’architettura sia per la pulizia del codice ma richiede
tempi di sviluppo più lunghi.
È un framework per la creazione di applicazioni web, si può utilizzare come alternativa a
Web Form per tre ragioni.
1. Necessità di controllare l’HTML per aderire ad uno standard web.
2. Migliore testabilità della logica applicativa che sta “dietro” alle pagine ASPX.
3. Migliore predisposizione all’indicizzazione nei motori di ricerca.
Il pattern MVC è basato sulla separazione dei compiti fra i componenti S/W che
compongono un’applicazione web e interpretano tre ruoli principali.
1. Model
Sono i dati che Controller e View si scambiano, si può utilizzare un ORM (Object
Relational Mapping) come Entity Framework o LinQ to SQL, meglio sarebbe applicare
anche un pattern come il Repository per disaccoppiare la logica presente nel Controller
dalla logica di persistenza dei dati.
2. View
È l’interfaccia: le pagine ASPX che contengono il codice HTML necessario a visualizzare
l’UI (User Interface) nel browser non usano più il code-behind perché i dati sono preparati
dal Controller e resi disponibili pre-caricati alla View.
3. Controller
È la business logic, per esempio Visual C#.
RICHIESTE HTTP
Quando nel browser si digita un indirizzo: http://127.0.0.1/contatti.aspx si aspetta che nella
cartella presente sul server web vi sia memorizzato il file CONTATTI.ASPX che sarà
richiamato per elaborare e visualizzare la risposta.
In un’applicazione ASP.NET MVC invece è diverso, a ogni richiesta non corrisponde un
file.
Le richieste sono indirizzate ad un Controller e ad una specifica action contenuta nel
Controller stesso.
Per esempio, il seguente indirizzo http://127.0.0.1/Prodotti/Details/5 sarà passato alla
classe Controller di nome ProdottiController al cui interno sarà la action Details a
elaborare la richiesta.
URL così formati possono contenere dei parametri, ASP.NET MVC oltre a passare la
richiesta al controller cercherà un’action al suo interno con il nome Details con un
Server side
um 175 di 243
parametro compatibile con il valore presente nell’URL.
Una volta trovata l’action, popolerà in automatico con il valore 5 il parametro dell’action
Details.
In pratica, mentre nella applicazioni web gli URL corrispondono a dei file ASPX, con
ASP.NET MVC gli URL sono mappati a classi Controller che elaborano la richiesta,
leggono i dati dal Model e reindirizzano il rendering della pagina su una determinata View.
PROGETTO
Per creare un nuovo progetto, fare clic su File/Nuovo/Progetto… (CTRL+N).
Nella finestra di dialogo Nuovo Progetto selezionare Altri linguaggi/Visual C#/Web,
quindi selezionare il tipo di applicazione, Applicazione Web ASP.NET MVC 4.
Si apre la seguente finestra.
Fare clic su OK.
Server side
um 176 di 243
ASP.NET MVC implementa il concetto che le
configurazione: questo è visibile tra il meccanismo
dell’associazione della View al Controller stesso.
Infatti, un Controller è una classe che deriva dalla classe
nome controller e offre dei metodi particolari, chiamati
derivato da ActionResult.
convenzioni vincono sulla
di attivazione del Controller e
Controller e che ha nel suffisso il
action che restituiscono un tipo
File CONTROLLERS\HOMECONTROLLER.CS
using MyMvcApplication.Models;
using System.Linq;
using System.Web.Mvc;
namespace MyMvcApplication.Controllers {
public class HomeController : Controller {
// GET: /Home/
public ActionResult Index()
{ using (var db = new StoreContext())
{ var customers = db.Customers.OrderBy(f => f.Id).Take(5);
return View(customers.ToList());
}
}
}
}
Questa action si richiama all’indirizzo seguente: /Home/Index.
La convenzione indica che il Controller è stabilito dal primo pezzo dell’URL, mentre l’action
dal secondo, Index è anche l’action di default, quindi può essere omessa.
Anche ASP.NET MVC usa le route di ASP.NET che possono essere personalizzate
agendo sul file seguente.
File APP_START\ROUTECONFIG.CS
using System.Web.Mvc;
using System.Web.Routing;
namespace MyMvcApplication {
Server side
um 177 di 243
public class RouteConfig {
public static void RegisterRoutes(RouteCollection routes)
{ routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
}
Per avere la View, per convenzione è ricercato il file che si trova nel percorso seguente.
FileVIEW\HOME\INDEX.CSHTML
Il nome del Controller e dell’action sono utilizzati per comporre dinamicamente il percorso
nel quale andare a recuperare la View.
Il ciclo mostra a video i dati prelevati dal DB, in pratica ASP.NET MVC non ha il concetto
di data binding perché basta avere una View tipizzata ed estrarre le informazioni.
Questa sintassi si chiama Razor ed è specifica di ASP.NET MVC.
@model IEnumerable<MyMvcApplication.Models.Customer>
<ul>
@foreach (var item in Model)
{
<li>@item.Name</li>
}
</ul>
@Html.ActionLink("Admin", "Index", "Admin")
Poiché si è passato nel Controller un elenco di clienti, la View sarà tipizzata usando il
Model.
Server side
um 178 di 243
Fare clic con il tasto destro sulla cartella View, dal menu contestuale selezionare
Aggiungi/Visualizza…, è proposto in automatico di utilizzare i tipi che sono disponibili.
RAZOR
È un View engine per ASP.NET MVC pensato per generare HTML utilizzando un
paradigma incentrato sul codice.
La View di default che ASP.NET MVC utilizza è basato sui concetti di pagine, controlli e
Master Page.
Fa parte anche di WebMatrix, comprende una serie di template per costruire siti web e
una serie di applicazioni web open source, fra cui WordPress, Joomla!, DotNetNuke e
Orchard su cui personalizzare stili e contenuti per realizzare applicazioni web complesse.
Nella modalità ASP.NET MVC è possibile utilizzare Razor come sintassi per progettare e
gestire le View.
L’obiettivo principale di Razor è minimizzare il numero di caratteri e parole chiave
all’interno di una View per rendere molto veloce la creazione e la manutenzione del flusso
di codice all’interno del codice di presentazione.
Il parser, infatti, è in grado di distinguere i blocchi di codice da eseguire sul server rispetto
alle parti di codice client HTML, stili e JavaScript, senza dover esplicitamente marcare
queste aree con attributi e/o TAG particolari.
Esempio, non è necessario marcare il codice della View con attributi particolari come ad
esempio i <% %>.
È possibile definire variabili e riutilizzarle all’interno del flusso della pagina, senza
preoccuparsi di definire delle aree di codice server.
Per definire variabili è sufficiente iniziare la riga con il simbolo della chiocciola.
Server side
um 179 di 243
Le variabili possono essere usate in espressioni inline senza TAG e attributi.
<!—Istruzioni su una sola riga -->
@{ var totale = 10000; }
@{ var messaggio = "Ciao, mondo!"; }
<h1>Ciao Razor</h1>
<p>Questo è un esempio di sintassi Razor</p>
<p>Il totale è : @totale </p>
<p>Il messaggio che vogliamo darti è : @messaggio</p>
Seguendo un paradigma simile a JavaScript o C# è possibile definire istruzioni multiriga.
@{
var saluti = "Benvenuti sul nostro sito!";
var weekDay = DateTime.Now.DayOfWeek;
var message = saluti + " Oggi è : " + weekDay;
}
<h1>Sito</h1>
<p> @ message </p>
Razor contiene molte classi helper per facilitare la costruzione di applicazioni che
interagiscono con DB o servizi esterni.
Queste classi sono nate per nascondere tutti i dettagli implementativi e di codice .NET dei
servizi che utilizzino.
ASP.NET MVC va bene anche per creare maschere d’inserimento dati.
Tramite wizard è possibile, in fase di creazione di un Controller, far generare in automatico
le action e le View necessarie.
Selezionare il template che fa riferimento a Entity Framework tra le opzioni e poi
specificare la classe di modello e quella con il context.
File ADMINCONTROLLER.CS
Si ha un Controller al cui interno c’è una action di nome Create decorata con un attributo
che consente di utilizzarla solo con richieste POST.
using System.Data;
using System.Linq;
using System.Web.Mvc;
using MyMvcApplication.Models;
namespace MyMvcApplication.Controllers {
public class AdminController : Controller {
Server side
um 180 di 243
private StoreContext db = new StoreContext();
// GET: /Admin/
public ActionResult Index()
{ return View(db.Customers.ToList()); }
// GET: /Admin/Details/5
public ActionResult Details(int id = 0)
{ Customer customer = db.Customers.Find(id);
if (customer == null)
return HttpNotFound();
return View(customer);
}
// GET: /Admin/Create
public ActionResult Create()
{ return View(); }
// POST: /Admin/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Customer customer)
{ if (ModelState.IsValid) {
db.Customers.Add(customer);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(customer);
}
// GET: /Admin/Edit/5
public ActionResult Edit(int id = 0)
{ Customer customer = db.Customers.Find(id);
if (customer == null)
return HttpNotFound();
return View(customer);
}
// POST: /Admin/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(Customer customer)
{ if (ModelState.IsValid) {
db.Entry(customer).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(customer);
}
// GET: /Admin/Delete/5
public ActionResult Delete(int id = 0)
{ Customer customer = db.Customers.Find(id);
if (customer == null)
return HttpNotFound();
return View(customer);
}
// POST: /Admin/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
Server side
um 181 di 243
{ Customer customer = db.Customers.Find(id);
db.Customers.Remove(customer);
db.SaveChanges();
return RedirectToAction("Index");
}
protected override void Dispose(bool disposing)
{ db.Dispose();
base.Dispose(disposing);
}
}
}
Il metodo ActionResult Edit rappresenta la chiamata che è fatta per visualizzare il form
d’inserimento dati, al cui invio sarà invocata l’action che risponde solo al metodo POST e
che, infatti, è decorata con l’attributo HttpPost.
In questo metodo sono recuperati i dati, modificati e salvati con Entity Framework: se tutto
va bene saranno inviati all’action di default che visualizza l’elenco delle informazioni.
Per reindirizzare un form dentro una View occorre il codice seguente.
L’ActionResult Create senza parametri è invocata inizialmente con una richiesta HTTP
GET e restituirà una View di nome con il modello dati vuoto.
Si riempie il form d’inserimento e si preme sul pulsante.
Il pulsante provoca una richiesta HTTP POST al cui interno sono presenti i dati inseriti nel
form.
In questo caso, il run-time individua la seconda action come quella su cui indirizzare la
richiesta e utilizza un Model Binder per popolare automaticamente il parametro con i dati
inseriti nel form.
Il Model Binder di ASP.NET MVC fa il lavoro di analizzare la richiesta e, sulla base dei
valori presenti, crea un oggetto popolandolo con i dati.
File VIEWS\ADMIN\EDIT.CSHTML
@model MyMvcApplication.Models.Customer
@{ ViewBag.Title = "Edit"; }
<h2>Edit</h2>
@using (Html.BeginForm()) {
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)
<fieldset>
<legend>Customer</legend>
@Html.HiddenFor(model => model.Id)
<div class="editor-label">
@Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Name)
@Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.City)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.City)
@Html.ValidationMessageFor(model => model.City)
</div>
<div class="editor-label">
Server side
um 182 di 243
@Html.LabelFor(model => model.Country)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Country)
@Html.ValidationMessageFor(model => model.Country)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
L’uso degli helper LabelFor, EditorFor e ValidationMessageFor che in automatico andando
a lavorare con i tipi delle proprietà del modello, danno rispettivamente il titolo, un editor per
il tipo che tiene conto di come è fatto e un messaggio di validazione.
Queste funzionalità lavorano con le data annotations che sono un modo per annotare e
arricchire le classi con le informazioni aggiuntive, come la tipologia di campo, se è
obbligatorio, oltre che con il modello stesso che in questo caso è basato su Entity
Framework e può avere attributi che includono queste informazioni.
APPLICAZIONI PER DISPOSITIVI MOBILI
Se si sceglie questo progetto, i fogli di stile predefiniti sfruttano le media query, così che il
layout si adatti a diverse risoluzioni del browser e sia correttamente visualizzabile anche
se l’accesso avviene da uno smartphone.
ASP.NET MVC pone grande attenzione nello sviluppo di applicazioni web mobile, tra i vari
template presenti, si trova un’applicazione che sfrutta jQuery Mobile e mostra come
integrare questo framework JavaScript all’interno delle View.
Questa funzionalità si chiama Display Mode e consente di associare un particolare
suffisso ad alcune caratteristiche della request per creare delle View ad hoc.
Se, per esempio, si vogliono produrre delle View specifiche per Windows Phone, basterà
registrare un nuovo display mode allo startup dell’applicazione, specificando un particolare
suffisso, in questo caso "wp".
DisplayModeProvider.Instance.Modes.Insert(0, new DefaultDisplayMode("wp")
{ ContextCondition = x => x.GetOverriddenUserAgent().IndexOf("windows phone",
StringComparison.InvariantCultureIgnoreCase) > -1
});
A questo punto, tutte le volte che si visita il sito web da un device Windows Phone, sarà
cercata una View con estensione .WP.CSHTML e, se non trovata, il sistema effettuerà
automaticamente il fallback sulla View di default.
Server side
um 183 di 243
ASP.NET MVC VS ASP.NET WEBFORM
INTRODUZIONE
Con un’applicazione WebForm si hanno una o più pagine ASPX che rispondono alle
richieste HTTP.
Con ASP.NET MVC si hanno uno o più Controller che rispondono alle richieste HTTP.
All’interno dei Controller le action svolgono il ruolo dei gestori di evento nella pagine di
code-behind delle WebForm.
Con ASP.NET MVC si organizza il codice in maniera più ordinata.
Sviluppando un sito web utilizzando le WebForm, si mettono nel code-behind tanti gestori
di eventi con l’inevitabile logica di controllo legata al codice ASPX di non facile gestione.
Il meccanismo dei PostBack e del ViewState finisce per pesare sulle performance.
Con le WebForm si ha a disposizione una serie di eventi che formano il ciclo di vita della
pagina, i PostBack per interagire con l’utente e il ViewState per mantenere lo stato dei
controlli tra un PostBack e l’altro.
ASP.NET MVC, invece, non utilizza il ViewState, la richiesta HTTP ha un ciclo di vita
differente e non necessita di una programmazione orientata agli eventi e ai PostBack dei
controlli.
In una applicazione ASP.NET MVC non sono più utilizzati i controlli data bound cui i
programmatori di applicazioni WebForm si sono abituati e che forniscono una ricca serie di
funzionalità già implementate.
Si deve scrivere gran parte del codice a mano o utilizzando gli helper HTML.
Questi sono metodi che semplificano la scrittura del codice HTML ma che non hanno la
stessa facilità d’uso dei controlli visuali normalmente utilizzati nelle WebForm.
In sintesi, con ASP.NET MVC si deve scrivere molto di più sin dall’inizio e controllare bene
il flusso di esecuzione del codice.
Con WebForm si deve scrivere meno codice senza però avere lo stesso controllo
sull’HTML e con un degrado di performance dovuto ai PostBack e al relativo ViewState.
Server side
um 184 di 243
MODULO 7
ASP.NET AVANZATO
Accesso
Dati
Accesso al DB
Programmazione client side
CAPCTHA
Server side
um 185 di 243
ACCESSO
INTRODUZIONE
L’autenticazione degli utenti all’interno di un’applicazione web è un’operazione delicata
ma, soprattutto, ripetitiva.
 Delicata perché ogni qualvolta si permette ad un utente d’inserire informazioni
all’interno del sito, si apre una “porta” verso il server, basti pensare a tutti i casi di SQL
Injection.
 Ripetitiva perché è un’operazione che coinvolge sempre le stesse risorse, ad esempio
un DB e il codice per autenticare l’utente che vanno ripetute tra le pagine dei vari siti.
ASP.NET mette a disposizione del programmatore un potente meccanismo per gestire
l’autenticazione e l’autorizzazione per l’accesso alle risorse.
Il primo passo per l’attuazione di politiche di sicurezza su un sistema informatico è sempre
costituito dall’implementazione di un sistema di gestione delle credenziali di
autenticazione.
In pratica, l’accoppiata Username/Password rappresenta il primo passo per concedere
l’utilizzo di determinate risorse in un applicativo.
ChangePassword
Permette ad un utente di cambiare la propria password.
CreateUserWizard
Raccoglie le informazioni di registrazione di un utente.
Login
Raccoglie le informazioni dell’utente e avvia il processo di autenticazione.
LoginName
Riporta automaticamente il nome dell’utente che si è autenticato.
LoginStatus
Indica lo stato di autenticazione dell’utente; visualizza un link per effettuare il Login quando
l’utente è ancora anonimo e uno per il Logout quando l’utente è autenticato.
LoginView
Definisce una zona dove inserire viste basate sullo stato di autenticazione dell’utente; in
queste viste è possibile inserire i controlli e le informazioni da far visualizzare a seconda
dello stato di autenticazione dell’utente.
Server side
um 186 di 243
PasswordRecovery
Recupera la password smarrita da un utente o ne genera una nuova; il controllo è in grado
d’inviare un’email all’utente con i dati della password previa impostazione del server di
posta SMTP.
L’autenticazione via form invia al server i dati di autenticazione e garantisce l’accesso solo
a chi è in possesso delle giuste credenziali.
Il primo passo sarà creare una pagina HTML di login, in modo che sia possibile collegarsi
ad un DB e confrontare i dati inseriti dall’utente con quelli presenti nel DB.
Poiché il web è stateless, per tenere traccia dello stato dell’autenticazione ASP.NET
utilizza un cookie.
Le informazioni contenute nel cookie possono essere criptate, attraverso un’opzione, in
modo che non sia possibile risalirne al contenuto.
Questo sistema non funzionerebbe nel caso in cui il browser non supporti i cookie ma la
stessa identica limitazione si avrebbe utilizzando un oggetto Session.
AUTENTICAZIONE NON È AUTORIZZAZIONE
Per costruire applicazioni che abbiano aree protette è necessario comprendere a fondo
entrambi i concetti, dato che sono strettamente legati tra di loro.
1. Autenticazione: è la parte dedicata al riconoscimento dell’utente e ricade sotto le
responsabilità dei form di autenticazione.
2. Autorizzazione: è gestita da ASP.NET, consente o meno l’accesso ad una risorsa
utilizzando le credenziali fornite in fase di autenticazione e confrontandole con una lista
di permessi; gli utenti autenticati potranno accedere a quella parte di risorsa che i
permessi ad essa associati gli concedono, ad esempio un certo utente avrà il
permesso di accedere ad una parte del disco ma non ad un'altra.
Esempio, progettare una pagina di login.
Una volta costruite le tabelle, si deve creare la maschera d’input.
Dalla Casella degli strumenti, selezionare il controllo CreateUserWizard.
AUTORIZZAZIONE DA WEB.CONFIG
È necessario modificare il file WEB.CONFIG che essendo il sistema demandato alle
configurazioni dell’applicazione, andrà a contenere le politiche di accesso alle risorse.
Server side
um 187 di 243
Esempio, garantire a PAGINA.ASPX l’accesso solo agli utenti autenticati.
<?xml version="1.0" encoding="utf-8"?>
<!-Per ulteriori informazioni sulla configurazione dell'applicazione ASP.NET, visitare
http://go.microsoft.com/fwlink/?LinkId=169433
-->
<configuration>
<location path="pagina.aspx">
<system.web>
<compilation debug="true" targetFramework="4.0" />
<authorization>
<deny users="?" />
</authorization>
</system.web>
</location>
</configuration>
L'effetto è che la pagina con il nome specificato non potrà essere visitata, chiave deny,
dagli utenti (?) che corrispondono a tutti quelli che non hanno fatto l’autenticazione.
Se invece, si volesse garantire l’accesso a tutti gli utenti autenticati basta specificare come
valore (*).
È possibile anche specificare una lista di utenti da bloccare, inserendo lo username.
Nel caso in cui si volesse specificare una lista di utenti cui è consentito l'accesso, è
necessario sostituire deny con allow.
Per quanto riguarda i ruoli il discorso è esattamente lo stesso.
Esempio, il ruolo amministratore ha accesso e quello utente è bloccato.
<location path="admin.aspx">
<system.web>
<authorization>
<deny roles="user" />
<allow roles="admin" />
</authorization>
</system.web>
</location>
Ovviamente è possibile combinare sia politiche di accesso per ruolo sia per utente.
L’attributo path del TAG <location> rappresenta il percorso relativo, primo (/) escluso,
rispetto alla root dell’applicazione in cui gira l’autenticazione.
Si può anche specificare una cartella e in questo modo la protezione è estesa a tutte le
risorse ASP.NET che contiene.
Server side
um 188 di 243
DATI
INTRODUZIONE
I dati di un’applicazione web sono recuperati dai contesti più disparati che possono essere
file di testo, documenti XML, un WS o un RDBMS.
ASP.NET usa il data binding, associazione di dati, per recuperarli e presentarli all’interno
delle applicazioni web con un’architettura che permetta di astrarre dal tipo di fonte dati.
Il data binding è l’associazione di una fonte dati ad un controllo, garantita dalla possibilità
della pagina di distinguere tra creazione e caricamento dei dati nei controlli.
Senza i controlli per visualizzare i dati, il data binding sarebbe inutile, infatti permettono di
associare i dati e visualizzarli nella pagina, sfruttando dei template per ripetere gli stessi.
I controlli che supportano la visualizzazione dei dati sono chiamati Data Bound Control.
I controlli principali sono tre.
1. Repeater: ripete i dati contenuti nel template.
2. DataList: offre funzionalità più avanzate rispetto al Repeater, lasciando comunque una
certa libertà di personalizzazione, produce output di solo testo o in formato XML.
3. DataGrid: offre funzionalità di ordinamento, paginazione, modifica e produce una
tabella HTML.
Ciò che hanno in comune è la proprietà DataSource che serve per specificare la sorgente
dei dati, un metodo DataBind per associare questi dati e tre eventi.
1. ItemCreated: scatenato all’aggiunta di ogni singolo item al controllo.
2. ItemDataBound: scatenato quando è effettuata l’associazione dei dati su ogni singolo
item.
3. ItemCommand: scatenato quando un controllo contenuto in un item richiede
l’esecuzione di un comando, in genere associato alle funzionalità di modifica o
cancellazione.
Non bisogna, però, confondere il data binding con l’uso della proprietà DataSource che i
controlli offrono.
Server side
um 189 di 243
Questa proprietà accetta un oggetto di tipo IList, IEnumerable o ICollection e, ovviamente,
qualsiasi tipo che implementi una di queste tre interfacce e, quindi, si presta a garantire la
possibilità di essere utilizzata con qualsiasi fonte dati, non esclusivamente un DB.
Dopo aver associato la sorgente, dietro le quinte si eseguono le seguenti operazioni.
1. È valutato il contenuto della proprietà DataSource.
2. Se ci sono elementi all’interno della sorgente, è effettuato un ciclo che visualizza, a
seconda della logica che implementa il controllo cui la sorgente è associata.
Questo meccanismo è trasparente al programmatore che non deve fare altro che
richiamare il metodo DataBind sul controllo cui è associata la sorgente.
Questo metodo è presente direttamente sulla classe Control del namespace
System.Web.UI da cui tutti i controlli derivano.
LIST CONTROL
Sono controlli speciali, per esempio DropDownList o RadioButton che, pur appartenendo
ai data bound control hanno un layout prefissato.
File LISTCONTROL.ASPX
<%@ Page Language="C#" CodeFile="05-ListControl.aspx.cs" Inherits="ListControl" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Esempio di data binding</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:DropDownList ID="DropDownList1" DataTextField="CompanyName"
DataTextFormatString="- {0}"DataValueField="CustomerID" runat="server" />
</div>
</form>
</body>
</html>
L’uso delle proprietà DataTextField e DataTextFormatString indicano rispettivamente la
proprietà da utilizzare per visualizzare e per formattare il dato, mentre DataValueField
indica qual è il valore da associare al controllo.
File LISTCONTROL.ASPX.CS
using System;
using System.Web.UI;
using NorthwindModel;
using System.Linq;
public partial class ListControl : Page {
protected void Page_Load(object sender, EventArgs e)
{ using (var entities = new NorthwindEntities())
{ var customers = entities.Customers.OrderBy(c => c.CompanyName);
DropDownList1.DataSource = customers;
DropDownList1.DataBind();
}
}
}
In questo codice si vede come sia assegnata, attraverso la proprietà DataSource, la
Server side
um 190 di 243
sorgente che è prelevata grazie a Entity Framework e salvata in una collezione locale e
come questa sia effettivamente interrogata all’invocare del metodo DataBind.
TEMPLATE
Per personalizzare l’output associato ad un controllo, si usano i template.
In realtà c'è un Data Control, tra tutti, in grado di estrarre i dati senza specificare alcun
template ed è il DataGrid.
Per tutti gli altri, invece, è necessario specificare almeno un template e in modo specifico
almeno l’ItemTemplate.
Un template non è altro che un controllo che al proprio interno può contenerne di altri.
I seguenti controlli hanno il supporto per i template.
Repeater
Dato un template, lo ripete per tutti gli elementi della sorgente dati, in pratica si usa
quando si vogliono visualizzare dati.
GridView
Visualizza in una tabella la sorgente dati, permettendone la paginazione, l’ordinamento e
la modifica delle righe.
DetailsView
Visualizza in una tabella una singola riga recuperata dalla sorgente dati, permettendone
l’inserimento e la modifica.
FormView
Simile al precedente, permette un layout personalizzato per la rappresentazione dei dati.
ListView
Consente la visualizzazione con un template personalizzato.
La scelta di questi controlli stabilisce le modalità di visualizzazione, inserimento e modifica
che si desidera utilizzare all’interno della pagina.
I template sono gestiti con una classe di tipo ITemplate, un’interfaccia particolare che è
implementata da una classe generata al volo con il page parser.
Generalmente, questi controlli sono dotati di template specifici per i diversi stati.
Per esempio, ItemTemplate è il template per il singolo elemento, mentre invece
HeaderTemplate rappresenta l’intestazione.
Per comporre il template e posizionare il contenuto della sorgente dati nei template, si
deve usare l’istruzione seguente.
<%# %> %>
È una direttiva che il page parser riconosce e che fa sì che ciò che è contenuto sia
invocato insieme all’evento DataBinding che si verifica quando il controllo scatena il data
binding.
Questi controlli offrono accesso ai dati attraverso l’interfaccia IDataItemContainer che si
usa grazie alla proprietà Container del template.
File REPEATER.ASPX
Questo codice rappresenta a video un elenco di elementi.
Dato che non è specificato diversamente, è invocato il metodo ToString che, in questo
caso, produce la visualizzazione del nome della classe.
Server side
um 191 di 243
<%@ Page Language="C#" CodeFile="Repeater.aspx.cs" Inherits="Repeater" %>
<%@ Import Namespace="NorthwindModel" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Esempio di Repeater</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Repeater id="CustomerView" runat="server">
<ItemTemplate>
<%#((Customer)Container.DataItem).CompanyName%>
<br />
</ItemTemplate>
</asp:Repeater>
</div>
</form>
</body>
</html>
File REPEATER.ASPX.CS
using System;
using System.Web.UI;
using System.Linq;
using NorthwindModel;
public partial class _06_Repeater: Page {
protected void Page_Load(object sender, EventArgs e)
{ using (var entities = new NorthwindEntities())
{ var customers = entities.Customers.OrderBy(c => c.CompanyName);
CustomerView.DataSource = customers;
CustomerView.DataBind();
}
}
}
Per accedere alle proprietà, bisogna specificare il tipo messo in binding, senza fare il
casting, la proprietà ItemType indica il tipo da utilizzare nei template di binding.
La proprietà SelectMethod consente d’indicare il metodo da richiamare per popolare la
griglia.
Deve restituire qualcosa che implementi l’interfaccia IEnumerable o IQueryable, dove T è il
tipo specificato dalla proprietà ItemType.
File DATABINDING.ASPX
<%@ Page Language="C#" CodeFile="DataBinding.cs" Inherits="DataBindingaspx" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Esempio di Repeater</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Repeater ID="Repeater1" runat="server"
Server side
um 192 di 243
ItemType="NorthwindModel.Customer" SelectMethod="GetCustomers">
<ItemTemplate>
<%#Item.CompanyName%><br />
</ItemTemplate>
</asp:Repeater>
</div>
</form>
</body>
</html>
File DATABINDING.ASPX.CS
Cambiando il metodo GetCustomers, con l’aggiunta di un parametro cui si è aggiunto un
attributo, si è in grado, in automatico, di far caricare quella proprietà attraverso la query
string, leggendo dal parametro n.
In questo caso si è usato la query string come sorgente ma ne sono supportate anche
altre, come controlli in pagina, form e session.
using System;
using System.Web.UI;
using System.Web.ModelBinding;
using NorthwindModel;
using System.Linq;
public partial class DataBindingaspx : Page {
NorthwindEntities db = new NorthwindEntities();
public IQueryable<Customer> GetCustomers([QueryString("n")] string name)
{ var customers = db.Customers.AsQueryable();
if (!String.IsNullOrEmpty(name))
customers = customers.Where(f =>
f.CompanyName.Contains(name));
return customers;
}
public override void Dispose(){
if (db !=null)
db.Dispose();
base.Dispose();
}
}
File DATABINDING.ASPX
<%@ Page Language="C#" CodeFile="DataBinding.cs" Inherits="DataBindingaspx" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Esempio di GridView</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:GridView ID="GridView1" runat="server"
SelectMethod="GetCustomers"
UpdateMethod="UpdateCustomers"
ItemType="NorthwindModel.Customer">
</asp:GridView>
</div>
Server side
um 193 di 243
</form>
</body>
</html>
File DATABINDING.ASPX.CS
using System;
using System.Web.UI;
using System.Web.ModelBinding;
using NorthwindModel;
using System.Linq;
public partial class DataBindingaspx : Page {
NorthwindEntities db = new NorthwindEntities();
public IQueryable<Customer> GetCustomers([QueryString("n")] string name)
{ var customers = db.Customers.AsQueryable();
if (!String.IsNullOrEmpty(name))
customers = customers.Where(f => f.CompanyName.Contains(name));
return customers;
}
protected void UpdateCustomer(Customer c)
{ TryUpdateModel<Customer>(c);
db.Attach(c);
db.SaveChanges();
}
public override void Dispose()
{ if (db != null)
db.Dispose();
base.Dispose();
}
}
Grazie al fatto che i metodi restituiscono un tipo IQueryable<T>, il risultato ottenuto è che il
controllo ricostruirà i criteri di ricerca sotto forma di lambda, così che Entity Framework
possa produrre l’esatto risultato.
L’uso dell’attributo all’interno dei parametri supportati dal metodo si chiama model
binding, in pratica, s’indica che la sorgente dati è in querystring.
Il risultato è che se si passa alla pagina un valore specifico, per esempio
tabella.aspx?n=Andrea, la proprietà sarà valorizzata.
È possibile recuperare questi valori dalle sorgenti più diverse, per esempio form, cookie o
session.
Lo stesso approccio è possibile in fase di aggiornamento o inserimento dei dati.
Si riceveranno in automatico, i dati caricati all’interno del tipo specificato per la tabella: ciò
vuol dire che non ci si deve preoccupare di conversioni ma solamente aggiornare i dati.
Quindi, si dovrà fare l’attach al contesto dell’entità e modificarne i dati.
In conclusione, sono ridotte le possibilità di errori, poiché non ci sono stringhe ma codice
compilato e strongly typed.
Infine, per quanto riguarda il data binding, è stato aggiunto il supporto all’HTMLEncode
direttamente in fase di binding, con questa istruzione.
<%#: Item.CustomerName %>
Così facendo, si garantisce che sia applicato in maniera specifica l’encoding, evitando
problemi di XSS (Cross Site Scripting) con dati prelevati dal DB.
Server side
um 194 di 243
ACCESSO AL DB
RICHIESTA DI DATI
I passi da seguire con un linguaggio server side sono i seguenti.
1. Dichiarazione, inizializzazione e utilizzo di un oggetto Connection.
2. Dichiarazione, inizializzazione e utilizzo di un oggetto DataAdapter.
3. Dichiarazione e riempimento di un DataSet.
4. Utilizzo dell’evento Load della pagina per impostare il DataSource della griglia in modo
da visualizzare i dati.
In totale circa una trentina di istruzioni da scrivere all’interno del codice ma soprattutto da
riscrivere nel caso in cui un’altra pagina avesse dovuto effettuare un’altra query al DB.
Il controllo SqlDataSource, invece, contiene due proprietà.
1. ConnectionString per specificare la stringa di connessione verso un DB SQL Server,
ricavata direttamente dal file WEB.CONFIG.
2. SelectCommand per specificare l’istruzione SQL da eseguire per ricavare i dati dal DB.
Grazie a questo controllo, la GridView può visualizzare il risultato della query senza dover
scrivere alcun altro tipo d’informazioni.
Sarà il controllo stesso ad aprire e chiudere la connessione, creare un oggetto
DataAdapter, eseguire la query e restituire i dati.
<asp:SqlDataSource ID="SqlDataSource1" runat="server"
ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>"
SelectCommand="SELECT * FROM [Category Sales for 1997]">
</asp:SqlDataSource>
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="True"
DataSourceID="SqlDataSource1">
</asp:GridView>
INTRODUZIONE
Per creare un nuovo progetto, fare clic su File/Nuovo/Progetto… (CTRL+N).
Nella finestra di dialogo Nuovo Progetto selezionare Altri linguaggi/Visual C#/Web,
quindi selezionare il tipo di applicazione, Applicazione Web ASP.NET vuota.
Immettere il nome del progetto nel campo Nome: per esempio WebForm, quindi per
creare il progetto, premere OK.
Invece, manualmente nella cartella App_Data fare clic con il tasto destro
Aggiungi/Elemento esistente… per inserire il DB, DATI.MDB.
Fare clic destro in Esplora soluzioni sul nome del progetto, dal menu contestuale
selezionare Aggiungi/Nuovo elemento… (CTRL+MAIUSC+A).
Alla voce Visual C# selezionare Web/Web Form.
Server side
um 195 di 243
VISUALIZZARE I DATI DELLA TABELLA ELENCO DEL DB DATI
Doppio clic sul file DEFAULT.ASPX, selezionare Visualizza finestra di progettazione si
apre l'editor visuale della pagina web in modo Progettazione.
Dopo aver scritto: Visualizzazione dati, selezionare il controllo GridView ed inserirlo nella
pagina.
Selezionare un’origine dati: <Nuova origine dati…>
Server side
um 196 di 243
Nella finestra selezionare un tipo di origine dei dati.
Nella finestra selezionare il DB.
Server side
um 197 di 243
Nella finestra configurare l’istruzione SQL Select.
Nella finestra si può eseguire il test per visualizzare un’anteprima dei dati.
Server side
um 198 di 243
Selezionare Visualizza finestra di progettazione si apre l’editor visuale della pagina web
in modo Progettazione.
Selezionare il modo Origine per visualizzare il codice HTML.
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs"
Inherits=" primodb._Default._default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Visualizzazione dei dati della tabella elenco del DB dati</title>
</head>
<body>
<form id="form1" runat="server">
<h1>Visualizzazione dati</h1>
<p>&nbsp;</p>
<p>
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataSourceID="AccessDataSource1">
<Columns>
<asp:BoundField DataField="citta" HeaderText="citta" SortExpression="citta" />
<asp:BoundField DataField="CAP" HeaderText="CAP" SortExpression="CAP" />
</Columns>
</asp:GridView>
<asp:AccessDataSource ID="AccessDataSource1" runat="server"
DataFile="~/App_Data/dati.mdb"
SelectCommand="SELECT [citta], [CAP] FROM [elenco]"></asp:AccessDataSource>
</p>
<p>&nbsp;</p>
</form>
</body>
</html>
Server side
um 199 di 243
Esecuzione dell’applicazione.
Esecuzione dell’applicazione nel server web IIS.
Copiare il file DEFAULT.ASPX nella cartella del server web C:\INETPUB\WWWROOT.
Copiare le cartelle BIN e APP_DATA nella cartella del server web.
C:\INETPUB\WWWROOT\BIN C:\INETPUB\WWWROOT\APP_DATA.
Server side
um 200 di 243
Modifiche
Selezionare le righe e ordinarle nel controllo GridView.
Selezionare il modo Origine per visualizzare il codice HTML.
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs"
Inherits="primodb._default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Visualizzazione dei dati della tabella elenco del DB dati</title>
</head>
<body>
<form id="form1" runat="server">
<h1>Visualizzazione dati</h1>
<p>&nbsp;</p>
<p>
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataSourceID="AccessDataSource1" AllowSorting="True">
<Columns>
<asp:BoundField DataField="citta" HeaderText="citta" SortExpression="citta" />
<asp:BoundField DataField="CAP" HeaderText="CAP" SortExpression="CAP" />
</Columns>
</asp:GridView>
<asp:AccessDataSource ID="AccessDataSource1" runat="server"
DataFile="~/App_Data/dati.mdb"
SelectCommand="SELECT [citta], [CAP] FROM
[elenco]"></asp:AccessDataSource>
</p>
<p>&nbsp;</p>
Server side
um 201 di 243
</form>
</body>
</html>
Esecuzione dell’applicazione.
Formattazione automatica.
Server side
um 202 di 243
Esecuzione dell’applicazione.
RICERCARE DATI DELLA TABELLA ELENCO DEL DB DATI
Configurare le impostazioni dell’origine dati, si seleziona lo stesso DB.
Fare clic sul pulsante WHERE…
Nella finestra si può eseguire il test per visualizzare un’anteprima dei dati.
Server side
um 203 di 243
Questo file RICERCADBASP.HTM è usato per l’inserimento della città da ricercare,
impostarlo con il menu Progetto/Imposta come pagina iniziale.
<html>
<head>
<title>Ricerca dati nella tabella elenco del DB dati</title>
</head>
<body>
<h1>Ricerca dati</h1>
<form method="get" action="Default.aspx">
<table>
<tr><td>Città</td>
<td><input type=text name="citta"></td></tr>
<tr><td>CAP</td>
<td><input type=text name="CAP"></td></tr>
</table>
<input type="submit" value ="Ricerca nel DB"/>
</body>
</html>
Server side
um 204 di 243
Configurare le impostazioni dell’origine dati, si seleziona lo stesso DB.
Fare clic sul pulsante WHERE…
Selezionare il modo Origine per visualizzare il codice HTML.
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs"
Inherits="primodb._default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title> Ricerca dati nella tabella elenco del DB dati</title>
</head>
<body>
<form id="form1" runat="server">
<h1>Visualizzazione dati</h1>
<p>&nbsp;</p>
<p>
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataSourceID="AccessDataSource1">
<Columns>
<asp:BoundField DataField="citta" HeaderText="citta" SortExpression="citta" />
<asp:BoundField DataField="CAP" HeaderText="CAP" SortExpression="CAP" />
</Columns>
</asp:GridView>
<asp:AccessDataSource ID="AccessDataSource1" runat="server"
DataFile="~/App_Data/dati.mdb"
SelectCommand="SELECT [citta], [CAP] FROM [elenco] WHERE ([citta] = ?)">
<SelectParameters>
<asp:QueryStringParameter Name="citta" QueryStringField="citta" Type="String"/>
Server side
um 205 di 243
</SelectParameters>
</asp:AccessDataSource>
</p> <p>&nbsp;</p>
</form>
</body>
</html>
Esecuzione dell’applicazione.
Server side
um 206 di 243
PROGETTO
Gestione di una videoteca.
1. Identificazione del sistema
Il progetto può essere scomposto in due parti.
2. ANALISI DEI DATI
Le entità del progetto sono le seguenti.
 clienti.
 film.
Tra l’entità clienti e l’entità film esiste un’associazione 1:N, in quanto un cliente possiede
uno o più DVD e un DVD è posseduto da un cliente.
Gli attributi di clienti sono: tessera, cognome, indirizzo, username, password.
Gli attributi di film sono: codice, tessera, titolo, genere, noleggiato, data_noleggio.
3. Costruzione del modello
Modello E/R
Modello logico
clienti (tessera, cognome, indirizzo, username, password)
Tabelle
clienti
Campo
tessera
cognome
indirizzo
username
password
Chiave
Primaria
Formato
Testo
Testo
Testo
Testo
Testo
Dimensione
4
20
20
10
10
film (codice, tessera, titolo, genere, noleggiato, data_noleggio)
Tabelle
film
Campo
codice
tessera
titolo
genere
noleggiato
data_noleggio
Chiave
Primaria
Esterna
Formato
Testo
Testo
Testo
Testo
Booleano
Data
Dimensione
4
4
20
20
Creazione tabelle
CREATE TABLE clienti (
tessera CHAR(4),
cognome CHAR (20),
indirizzo CHAR(20),
username CHAR(10),
password CHAR (10),
Server side
um 207 di 243
PRIMARY KEY(tessera)
);
CREATE TABLE film (
codice CHAR(4),
tessera CHAR (4),
titolo CHAR(20),
genere CHAR(20),
noleggiato YESNO,
data_noleggio DATE,
PRIMARY KEY(codice),
FOREIGN KEY(tessera) REFERENCES clienti (tessera)
);
Server side
um 208 di 243
Visualizzare i contenuti della tabella film in ordine di codice.
Effettuare il login alla videoteca.
Impostare la proprietà TextMode della casella di testo a password, affinchè al momento
dell’inserimento non sia visibile la stringa inserita.
Progettare il medesimo codice con query parametriche con variabili.
Server side
um 209 di 243
Inserire un nuovo cliente della videoteca.
L’uso di parole riservate, per esempio le password è possibile solo indicandole tra ([]) per
non creare ambiguità.
Visualizzare i film non in prestito.
Server side
um 210 di 243
Prendere in prestito un film.
Server side
um 211 di 243
PROGRAMMAZIONE CLIENT SIDE
INTRODUZIONE
Gli sviluppatori ASP.NET sono programmatori server side e non conoscono la
programmazione client side ma vista l’importanza dell’UX, Microsoft ha integrato in Visual
Studio le librerie JavaScript.
ASP.NET AJAX
È l’implementazione per i programmatori .NET di AJAX.
Se si volesse agire su una pagina web senza creare PostBack, l’unico modo per farlo è
progettare una funzione JavaScript, invece, si possono inserire i controlli web all’interno
dell’UpadatePanel così che i Postback generati sono tutti intercettati da AJAX.
File WEBFORMAJAX.ASPX
È una pagina web con un’etichetta e un pulsante all’interno di un UpadatePanel e
un’etichetta e un pulsante fuori.
Inserire un controllo ScriptManager all’interno del TAG <form> per segnalare alla pagina
che si usa la tecnologia AJAX, quindi inserire un controllo UpdatePanel.
Associare a ciascuno dei due pulsanti il metodo OnClick per cambiare il testo dell’etichetta
corrispondente.
<%@ Page Language="C#" AutoEventWireup="true"
CodeBehind="WebFormAjax.aspx.cs"Inherits="WebApplicationJuiceUI.WebFormAjax" %>
Server side
um 212 di 243
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>AJAX</title>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
<div>
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:Label ID="Label1" runat="server" Text="Label"
Width="80px"></asp:Label>
<asp:Button ID="Button1" runat="server" Text="Pulsante 1"
OnClick="Button1_Click" />
</ContentTemplate>
</asp:UpdatePanel>
<asp:Label ID="Label2" runat="server" Text="Label" Width="80px"></asp:Label>
<asp:Button ID="Button2" runat="server" Text="Pulsante 2" OnClick="Button2_Click" />
</div>
</form>
</body>
</html>
Eseguire l’applicazione e fare clic sul Pulsante 1 che si trova all’interno dell’UpadatePanel
e poi sul Pulsante 2 che si trova all’esterno.
Entrambi i pulsanti cambiano il testo dell’etichetta corrispondente ma il primo pulsante non
provoca un PostBack perché l’UpadatePanel carica solo la porzione di pagina interessata.
Il secondo pulsante provoca un PostBack con il conseguente caricamento della pagina.
L’UpadatePanel dev’essere usato con dovizia perché rallenta le prestazioni del server web
in quanto usa pesantemente le risorse di sistema.
AJAX CONTROL TOOLKIT
Fare clic su Strumenti/Gestione pacchetti NuGet/Gestisci pacchetti NuGet per la
soluzione…, nella finestra che si apre digitare, all’interno della casella di testo,
AjaxControlToolkit.
Per inserire i nuovi controlli nella Casella degli strumenti, fare clic con il pulsante destro
sulla scheda Generale e selezionare Aggiungi scheda e assegnare il nome
AjaxControlToolkit, quindi fare di nuovo clic con il pulsante destro e selezionare la voce
Scegli elementi… e selezionare il file che si trova nella cartella BIN del progetto che si
chiama AJAXCONTROLTOOLKIT.DLL.
Server side
um 213 di 243
File WEBFORMAJAXCONTROLTOOLKIT.ASPX
È una pagina web con un controllo Accordion.
<%@ Page Language="C#" AutoEventWireup="true"
CodeBehind="WebFormAjaxControlToolkit.aspx.cs"
Inherits="WebApplicationJuiceUI.WebFormAjaxControlToolkit" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>AjaxControlToolkit</title>
<style type="text/css">
.accordion {
width: 800px;
}
.accordionTestata {
border: 1px solid #2F4F4F;
color: white;
background-color: #2E4d7B;
font-family: Arial, Sans-Serif;
font-size: 12px;
Server side
um 214 di 243
font-weight: bold;
padding: 5px;
margin-top: 5px;
cursor: pointer;
}
.accordionTestataSelezione {
border: 1px solid #2F4F4F;
color: white;
background-color: #5078B3;
font-family: Arial, Sans-Serif;
font-size: 12px;
font-weight: bold;
padding: 5px;
margin-top: 5px;
cursor: pointer;
}
.accordionContenuto {
background-color: #D3DEEF;
border: 1px dashed #2F4F4F;
border-top: none;
padding: 5px;
padding-top: 10px;
}
</style>
</head>
<body>
<form id="form1" runat="server">
<ajaxToolkit:ToolkitScriptManager
runat="server"></ajaxToolkit:ToolkitScriptManager>
<div>
<ajaxToolkit:Accordion ID="Accordion1" runat="server"
CssClass="accordion"
HeaderCssClass="accordionTestata"
HeaderSelectedCssClass="accordionTestataSelezione"
ContentCssClass="accordionContenuto" >
<Panes>
<ajaxToolkit:AccordionPane ID="AccordionPane1" runat="server">
<Header>Andrea Sperelli</Header>
<Content>
Ciao, mondo da Andrea!
</Content>
</ajaxToolkit:AccordionPane>
<ajaxToolkit:AccordionPane ID="AccordionPane2" runat="server">
<Header>Guido Lavespa</Header>
<Content>
Ciao, mondo da Guido!
</Content>
</ajaxToolkit:AccordionPane>
<ajaxToolkit:AccordionPane ID="AccordionPane3" runat="server">
<Header>Mario Rossi</Header>
<Content>
Ciao, mondo da Mario!
</Content>
</ajaxToolkit:AccordionPane>
Server side
um 215 di 243
<ajaxToolkit:AccordionPane ID="AccordionPane4" runat="server">
<Header>Remo Labarca</Header>
<Content>
Ciao, mondo da Remo!
</Content>
</ajaxToolkit:AccordionPane>
</Panes>
</ajaxToolkit:Accordion>
</div>
</form>
</body>
</html>
JAVASCRIPT
File WEBFORMJAVASCRIPT.ASPX
Client side: si usa il metodo OnClientClick del controllo Button, quando il pulsante è
premuto, manda in esecuzione la funzione JavaScript: finestra di avvertimento.
<%@ Page Language="C#" AutoEventWireup="true"
CodeBehind="WebFormJavascript.aspx.cs"
Inherits="WebApplicationJuiceUI.WebFormJavascript" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Button ID="Button1" runat="server" Text="Uno"
OnClientClick="javascript:alert('Avviso!');" /><br />
<asp:Button ID="Button2" runat="server" Text="Due" />
Server side
um 216 di 243
</div>
</form>
</body>
</html>
File WEBFORMJAVASCRIPT.ASPX.CS
Server side: si aggiunge un attributo al pulsante che in corrispondenza dell’evento clic
associa la stessa funzione JavaScript.
using System;
namespace WebApplicationJuiceUI {
public partial class WebFormJavascript : System.Web.UI.Page {
protected void Page_Load(object sender, EventArgs e)
{ Button2.Attributes.Add("onclick", "javascript:alert('Avviso!');"); }
}
}
Esempio, realizzare una casella di testo che mostri l’orario sulla pagina web.
Si può agire server side nel metodo Page_Load usando la classe DateTime e leggendo la
proprietà Now per determinare l’orario attuale.
L’ora ricavata è poi visualizzata sul browser ma in tal caso l’ora sarebbe quella del server
che potrebbe anche non coincidere con quella del client e anche se così fosse, si
dovrebbe tener conto dell’intervallo che intercorre tra la richiesta al server e la
visualizzazione sul client che potrebbe influire anche di diversi secondi sulla precisione
dell’orario.
Client side: si usa JavaScript per prelevare la data client side e mostrarla nel browser.
Progettare la funzione ShowTime, inserirla nel body della pagina e invocarla all’evento
onload, inserendo il nome all’interno del TAG <body>.
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="simple.aspx.cs"
Inherits="simple" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Esempio 1</title>
</head>
Server side
um 217 di 243
<body onload="ShowTime();">
<script type="text/javascript">
<!-function ShowTime()
{ document.forms[0]['txtClientTime'].value=Date(); }
// -->
</script>
<form id="form1" runat="server">
<div>
<asp:Label ID="labTitle" runat="server" Font-Bold="True" Font-Italic="True" FontNames="Arial"
ForeColor="#400040" Text="Esempio 1"></asp:Label><br />
<br />
<asp:Label ID="Label1" runat="server" Text="Sul client sono le: "></asp:Label>
&nbsp;<asp:TextBox ID="txtClientTime" runat="server"
Width="250px"></asp:TextBox><br />
<asp:Label ID="Label2" runat="server" Text="Sul server sono le: "></asp:Label>
<asp:TextBox ID="txtServerTime" runat="server" Width="250px"></asp:TextBox><br
/><br />
<asp:HyperLink ID="HyperLink1" runat="server"
NavigateUrl="~/Default.aspx">Home</asp:HyperLink><br />
<br />
</form>
</body>
</html>
Server side: si usa ASP.NET per prelevare la data server side e mostrarla nel browser.
using System;
public partial class simple : System.Web.UI.Page {
protected void Page_Load(object sender, EventArgs e)
{ txtServerTime.Text=DateTime.Now.ToString(); }
}
ASP.NET e il .NET Framework contengono classi e relativi metodi che permettono
d’inserire codice JavaScript in una pagina web, ad esempio il passaggio parametri dal
codice client side a quello server side o viceversa; in pratica è ASP.NET che genera
anche il codice JavaScript che dev’essere utilizzato dal client.
La classe ClientScriptManager è utilizzata per “creare dinamicamente” gli script client side
utilizzando codice server side.
Server side
um 218 di 243
Per ottenere un oggetto ClientScriptManager in una pagina web ASP.NET è sufficiente
utilizzare la proprietà ClientScript dell’oggetto Page.
La classe ClientScriptManager identifica univocamente gli script utilizzando una chiave di
tipo String e un Type.
Gli script con la stessa chiave e lo stesso tipo sono considerati dei duplicati.
Il tipo è utilizzato per distinguere degli script nel caso in cui differenti controlli nella stessa
pagina definiscano degli script con una stessa chiave.
Esempio, data una pagina con due caselle di testo, copiare il contenuto della prima nella
seconda ma trasformando in maiuscolo il testo.
Client side: il metodo utilizzabile per inserire uno script client side in una pagina web è
RegisterClientScriptBlock.
<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="registerclientscriptblock.aspx.cs" Inherits="registerclientscriptblock" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Esempio 2</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Label ID="labTitle" runat="server" Font-Bold="True" Font-Italic="True" FontNames="Arial"
ForeColor="#400040" Text="Esempio 3"></asp:Label><br /> <br />
<asp:TextBox ID="txtSource" runat="server" Width="250px" ></asp:TextBox><br/><br/>
<asp:Button ID="btCopyServerSide" runat="server"
OnClick="btCopyServerSide_Click" Text="Copia server side" />
<input type="button" id="btCopyClient" runat="server" value="Copia client side"
/><br/><br/>
<asp:TextBox ID="txtTarget" runat="server" Width="250px"></asp:TextBox><br /><br />
<asp:HyperLink ID="HyperLink1" runat="server"
NavigateUrl="~/Default.aspx">Home</asp:HyperLink><br />
<br />
</div>
</form>
</body>
</html>
Server side: nell’evento Page_Load sarà creato il codice JavaScript da eseguire al clic sul
pulsante btCopyClient, registrato nella pagina con il metodo RegisterClientScriptBlock.
In questo caso è utilizzato un overload del metodo RegisterClientScriptBlock con un
parametro booleano che indica se inserire o meno nel blocco di codice generato anche i
TAG <script> di apertura e chiusura del blocco.
using System;
public partial class registerclientscriptblock : System.Web.UI.Page {
protected void Page_Load(object sender, EventArgs e)
{ if (!IsPostBack) {
string idTarget = txtTarget.ID;
string idSource = txtSource.ID;
Server side
um 219 di 243
string scriptCopy = @"function Copy()
{
document.forms[0]['"+idTarget+"'].value=document.forms[0]['"+idSource+@"'].value.toUpp
erCase(); };";
ClientScript.RegisterClientScriptBlock(this.GetType(), "Script_Copy", scriptCopy, true);
btCopyClient.Attributes["onClick"]="Copy()";
}
}
protected void btCopyServerSide_Click(object sender, EventArgs e)
{ txtTarget.Text = txtSource.Text.ToUpper(); }
}
Il pulsante a destra esegue la copia e trasforma in maiuscolo il contenuto della prima
TextBox, senza eseguire un PostBack della pagina sul server, in pratica utilizza il codice
JavaScript generato dinamicamente.
Esempio, progettare la funzione client side Date in maniera da ottenere la data attuale e
scriverla in una TextBox appena la pagina è caricata, quindi senza necessità di premere
un pulsante o di forzare un altro evento.
Client side: si usa il metodo RegisterStartupScript per registrare lo script da eseguire.
<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="registerstartupscript.aspx.cs" Inherits="registerstartupscript" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Esempio 3</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Label ID="labTitle" runat="server" Font-Bold="True" Font-Italic="True" FontNames="Arial"
ForeColor="#400040" Text="Esempio 3"></asp:Label><br />
<br />
Server side
um 220 di 243
<asp:Label ID="Label1" runat="server" Text="Sono le: "></asp:Label>
<asp:TextBox ID="txtClientTime" runat="server" Width="250px"></asp:TextBox><br />
<br />
<asp:HyperLink ID="HyperLink1" runat="server"
NavigateUrl="~/Default.aspx">Home</asp:HyperLink><br />
<br />
</div>
</form>
</body>
</html>
Server side.
using System;
public partial class registerstartupscript : System.Web.UI.Page {
protected void Page_Load(object sender, EventArgs e)
{ string scriptShowTime = @"document.forms[0]['txtClientTime'].value=Date();";
ClientScript.RegisterStartupScript(this.GetType(), "Script_ShowTime",
scriptShowTime, true);
}
}
Esempio, eseguire il codice client side al submit di un modulo HTML, in pratica non
appena si verifica l’evento onsubmit.
Client side.
<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="RegisterOnSubmitStatement.aspx.cs" Inherits="RegisterOnSubmitStatement"
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Esempio 4</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Button ID="Button1" runat="server" Text="Invia" OnClick="Button1_Click" /></div>
</form>
</body>
Server side
um 221 di 243
</html>
Server side: per registrare un blocco di codice in modo che sia eseguito, si usa il metodo
RegisterOnSubmitStatement.
In questo caso, al submit della pagina, sarà mostrata una finestra di dialogo per
confermarlo e solo se l’utente fa clic su OK sarà eseguito il codice del gestore
Button1_Click.
using System;
public partial class RegisterOnSubmitStatement : System.Web.UI.Page {
protected void Page_Load(object sender, EventArgs e)
{ string script = "return confirm('Sei sicuro di fare il submit di questo form?');";
ClientScript.RegisterOnSubmitStatement(this.GetType(), "onsubmitscript", script);
}
protected void Button1_Click(object sender, EventArgs e)
{ Button1.Text = "Submit eseguito!"; }
}
Esempio, inserire in una pagina web, dei blocchi di codice JavaScript salvati in uno o più
file esterni e referenziarli per mezzo di un URL.
File SCRIPTS\EXTERNAL.JS
function Saluti(str)
{ alert('Ciao '+str); }
Il metodo RegisterClientScriptInclude funziona come RegisterClientScriptBlock ma legge
lo script da un file esterno con estensione JS.
Il file da includere sarà inserito prima di ogni altro script eventualmente presente e dunque
potrebbe non avere modo di accedere a qualche elemento della pagina.
Client side.
<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="registerclientscriptinclude.aspx.cs" Inherits="registerclientscriptinclude" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Esempio 5</title>
Server side
um 222 di 243
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Button ID="Button1" runat="server" Text="Ciao" /></div>
</form>
</body>
</html>
Server side: al clic sul pulsante Button1, sarà invocata la funzione Saluti con parametro
“Andrea Sperelli” e quindi il risultato sarà una Message Box client side.
using System;
public partial class registerclientscriptinclude : System.Web.UI.Page {
protected void Page_Load(object sender, EventArgs e)
{ ClientScript.RegisterClientScriptInclude(this.GetType(),"externaljs","Scripts/external.js");
Button1.Attributes.Add("onclick", "Saluti('Andrea Sperelli')");
}
}
Il codice client side non può, in generale, comunicare con quello server side.
Per esempio, una funzione JavaScript non può passare dei valori al codice della pagina
durante un PostBack: due possibili soluzioni.
1. Campi hidden e cookie.
2. CallBack client side.
Funzione CallBack
È una speciale funzione che è chiamata direttamente dal SO quando ha finito o sta per
iniziare un compito.
Non occorre interrogare Windows ogni intervallo di tempo per sapere se, ad esempio,
qualcuno ha premuto un tasto.
Sarà Windows a spedire un messaggio di tipo WM_KEYDOWN che, tramite una CallBack,
può essere intercettato e gestito dall’applicazione web.
Inoltre, gli eventi, all’interno di .NET, non sono altro che delle funzioni CallBack chiamate
dal framework.
In pratica, permette di lavorare su una pagina, leggerne i valori e scriverli, senza
PostBack, in pratica senza dover rigenerare l’intera pagina.
Questo è chiamato anche CallBack fuoribanda, perché in tale situazione una funzione
Server side
um 223 di 243
client side, per esempio in JavaScript, invia una richiesta asincrona ad una pagina, al di
fuori del ciclo normale di vita.
La pagina ASP.NET a questo punto, esegue una versione modificata del proprio ciclo di
vita e processa la richiesta.
Per ottenere un riferimento alla funzione client che, una volta invocata, inizia il CallBack, si
usa la classe ClientScriptManager e in particolare il metodo GetCallBackEventReference.
Esempio, aggiornare una parte della pagina, senza eseguire alcun PostBack e dunque
con un’UX più piacevole ed efficace.
Client side: la pagina HTML contiene una DropDownList con i nomi delle regioni italiane,
e un pulsante alla cui pressione si vuole ricavare l’elenco delle province appartenenti alla
regione selezionata.
La funzione di CallBack usata dal server è DisplayResultsCallback, una volta letto il
risultato dal server, genera un elenco puntato, per mezzo dei TAG <ul> e <li> e a questo
punto lo visualizza inserendolo nell’elemento divContents.
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="ClientCallback.aspx.cs"
Inherits="ClientCallback" %>
<html>
<head>
<title>Esempio 6</title>
<script language="javascript">
function GetProvince()
{ var regione = document.forms[0].ddlRegioni.value;
GetProvinceOnServer(regione, "txtRegione");
}
function DisplayResultsCallback(result, context )
{ var strHTML="";
var s=result;
if(result=!"") {
var temp = new Array();
temp=s.split("|");
if(temp.length>0) {
strHTML="Province:<br><ul>";
for(i=0;i<temp.length;i++) {
strHTML+="<li>"+temp[i]+"</li>";
}
strHTML+="</ul>";
}
else strHTML += "<br><br><b>data not found</b>";
}
else
{ strHTML += "<br><br><b>data not found</b>"; }
divContents.innerHTML = strHTML;
}
function DisplayErrorCallback( error, context )
{ alert(" Query Failed. " + error); }
</script>
</head>
<body>
<form id="Form1" runat="server">
<H1>
Regioni e province</H1>
Server side
um 224 di 243
<asp:AccessDataSource ID="AccessDataSource1" runat="server"
DataFile="~/App_Data/reg_prov.mdb"
SelectCommand="SELECT [Nome] FROM [Regioni]"></asp:AccessDataSource>
<br><br>
<font color="#800080"><b>Seleziona la regione:</b>&nbsp;</font>
<asp:DropDownList ID="ddlRegioni" runat="server"
DataSourceID="AccessDataSource1" DataTextField="Nome">
</asp:DropDownList>
<INPUT id="btnGetProvince" type="button"
value="Mostra province" onclick="GetProvince()">
<div id="divContents">
&nbsp;</div>
</form>
</body>
</html>
Server side: si usa un DB Access con due tabelle Regioni e Province e una query.
L’elenco delle province deve apparire senza dare l’impressione che la pagina sia ricaricata
e dunque si usa il meccanismo dei CallBack, per aggiornare solo il codice HTML
contenuto in un elemento <div> della pagina.
Il metodo GetProvince ricava l’elenco delle province di una data regione e crea una stringa
contenente le province separate con un carattere (|), perché è una stringa che la funzione
di CallBack si aspetta.
La Web Form deve, inoltre, implementare l’interface ICallbackEventHandler che definisce
due metodi.
Il primo processa l’evento di CallBack inviato dal client, ricevendo un argomento string, in
questo caso il nome della regione.
Il secondo si occupa d’invocare il metodo di accesso al DB GetProvince e i restituire al
client, il risultato.
Dal client side la pagina web contiene due funzioni JavaScript, una che invia il CallBack al
server e una per ricevere i risultati.
La prima è creata al primo caricamento della pagina, per mezzo del metodo
GetCallbackEventReference per ottenere un riferimento alla funzione CallBack e poi
utilizzando il RegisterClientScriptBlock.
using System;
using System.Data;
using System.Data.OleDb;
using System.Web.UI;
public partial class ClientCallback : System.Web.UI.Page,ICallbackEventHandler {
private string _callbackArg;
public void Page_Load(object sender, EventArgs e)
{ if (!Request.Browser.SupportsCallback)
throw new ApplicationException("Il browser non supporta Client callbacks!");
if (!IsPostBack) {
string src = Page.ClientScript.GetCallbackEventReference(this,"arg",
"DisplayResultsCallback", "ctx", "DisplayErrorCallback", false);
string mainSrc = @"function GetProvinceOnServer(arg, ctx){ " + src + "; }";
Page.ClientScript.RegisterClientScriptBlock(this.GetType(),
"GetProvinceOnServer", mainSrc, true);
}
}
void ICallbackEventHandler.RaiseCallbackEvent(string eventArgument)
{ _callbackArg = eventArgument; }
Server side
um 225 di 243
string ICallbackEventHandler.GetCallbackResult()
{ try
{ return GetProvince(_callbackArg); }
catch (Exception ex)
{ throw new ApplicationException("Errore durante il run-time: " + ex.Message); }
}
public string GetProvince(string regione)
{ try {
AccessDataSource1.SelectCommand="SELECT Province.Nome" +
"FROM Regioni"+
"INNER JOIN Province ON Regioni.IDRegione = Province.IDRegione" +
"WHERE Regioni.Nome='"+regione+"'";
DataView
dv=(DataView)AccessDataSource1.Select(DataSourceSelectArguments.Empty);
DataTable dt = dv.Table;
string province="";
foreach (DataRow dr in dt.Rows)
province += dr[0].ToString() + "|";
if (province.Length > 0)
province = province.Substring(0, province.Length - 1);
return province;
}
catch (Exception ex)
{ throw ex; }
}
}
La figura mostra come interagisce il client con il server utilizzando il CallBack.
Il processo è avviato quando l’utente seleziona una regione dalla casella a discesa e
preme il pulsante di ricerca.
A questo punto è invocato il metodo GetProvinceOnServer, creato dinamicamente sul
server, in maniera da conoscere la funzione client di CallBack.
Ora il client genera l’evento di CallBack, utilizzando il metodo RaiseCallbackEvent, il
Server side
um 226 di 243
server ricerca le province sul DB e le restituisce al client per mezzo di GetCallbackResult.
Infine, il client ottiene i risultati e può occuparsi di aggiornare solo la parte di pagina che
mostrerà i risultati.
ANIMAZIONI CON JQUERY
Per usare queste funzionalità si deve includere la libreria nell’applicazione web, due modi.
1. CDN (Content Delivery Network)
Si usa la libreria pubblicata sui server remoti, riduce il tempo di caricamento
dell’applicazione web perché la richiesta di download non arriva al server web che la
ospita ma al CDN chiamato in causa.
<script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.9.0.min.js"</script>
2. Libreria inclusa in Visual Studio
Le versioni MIN sono compresse, quindi più veloci da caricare.
Il linguaggio si basa sui selettori CSS che indicano su quali elementi della pagina applicare
le animazioni, effetti e tutte le altre proprietà disponibili nella libreria.
File WEBFORMJQUERY.ASPX
<%@ Page Language="C#" AutoEventWireup="true"
CodeBehind="WebFormjQuery.aspx.cs"
Inherits="WebApplicationJuiceUI.WebFormjQuery" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>Animazione con jQuery</title>
<script src="Scripts/jquery-1.8.3.min.js"></script>
<style type="text/css">
body{
margin:0;
text-align:left;
background-color:white;
}
#main{
width:800px;
height:400px;
background-color:red;
}
.appari{ color:black;}
.scompari{ color:black;}
#content{ width:300px; height:200px; background-color:yellow; display:none;}
#menu{ width:300px; height:100px;}
#menu li{ float:left; list-style:none; cursor:pointer;margin:20px;}
</style>
<script type="text/javascript">
$(document).ready(function () {
$(".appari").click(
function () {
$("#content").fadeIn("slow");
});
Server side
um 227 di 243
$(".scompari").click(
function () {
$("#content").fadeOut("slow");
});
});
</script>
</head>
<body>
<form id="form1" runat="server">
<div id="container">
<ul id="menu">
<li class="appari">APPARI</li>
<li class="scompari">SCOMPARI</li>
</ul>
<div id="content"></div>
</div>
</form>
</body>
</html>
Quando l’utente fa clic sulle voci di menu, jQuery, grazie ai suoi selettori applicati alle
classi .appari e .scompari, capisce su quali elementi della pagina agire.
Le proprietà fadeIn e fadeOut fanno apparire e scomparire un livello con effetto comparsa.
Server side
um 228 di 243
JUICE UI
S’installa nello stesso modo e si aggiungono i suoi controlli come nell’AjaxControlToolkit.
File WEBFORMJUICE.ASPX
È la stessa pagina WEBFORMAJAXCONTROLTOOLKIT.ASPX con il controllo Accordion.
<%@ Page
Language="C#"AutoEventWireup="true"CodeBehind="WebFormJuice.aspx.cs"Inherits="
WebApplicationJuiceUI.WebFormJuice"%>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>Juice</title>
<script src="Scripts/jquery-1.8.3.min.js"></script>
<script src="Scripts/jquery-ui-1.9.2.min.js"></script>
<script src="Scripts/amplify.min.js"></script>
<style type="text/css">
.accordion {
width: 800px;
}
</style>
</head>
<body>
<form id="form1" runat="server">
Server side
um 229 di 243
<asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
<div>
<Juice:Accordion runat="server" Collapsible="true" ID="Accordion1"
CssClass="accordion">
<Juice:AccordionPanel ID="AccordionPanel1" runat="server" Title="Andrea Sperelli">
<PanelContent>
Ciao, mondo da Andrea!
</PanelContent>
</Juice:AccordionPanel>
<Juice:AccordionPanel ID="AccordionPanel2" runat="server" Title="Guido Lavespa">
<PanelContent>
Ciao, mondo da Guido!
</PanelContent>
</Juice:AccordionPanel>
<Juice:AccordionPanel ID="AccordionPanel3" runat="server" Title="Mario Rossi">
<PanelContent>
Ciao, mondo da Mario!
</PanelContent>
</Juice:AccordionPanel>
<Juice:AccordionPanel ID="AccordionPanel4" runat="server" Title="Remo Labarca">
<PanelContent>
Ciao, mondo da Remo!
</PanelContent>
</Juice:AccordionPanel>
</Juice:Accordion>
</div>
</form>
</body>
</html>
Permette di usare i suoi controlli come se fossero controlli server side, quindi il
programmatore client side, non deve scrivere codice JavaScript ma solo CSS.
File WEBFORMJUICE2.ASPX
<%@ Page Language="C#" AutoEventWireup="true"
CodeBehind="WebFormJuice2.aspx.cs"
Inherits="WebApplicationJuiceUI.WebFormJuice2" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title></title>
<script src="Scripts/jquery-1.8.3.min.js"></script>
<script src="Scripts/jquery-ui-1.9.2.min.js"></script>
<script src="Scripts/amplify.min.js"></script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
<juice:Accordion ID="Accordion1" runat="server">
</juice:Accordion>
<div>
</div>
</form>
Server side
um 230 di 243
</body>
</html>
File WEBFORMJUICE2.ASPX.CS
S’istanzia AccordionPanel e si settano le proprietà Title e PanelContent.
La classe AccordionPanelTemplate eredita dall’interface ITemplate ed è usata per
aggiungere testo all’AccordionPanel.
using System;
using System.Web.UI;
namespace WebApplicationJuiceUI {
public partial class WebFormJuice2 : System.Web.UI.Page {
protected void Page_Load(object sender, EventArgs e)
{ Juice.AccordionPanel panel1 = new Juice.AccordionPanel();
panel1.Title = "Andrea Sperelli";
AccordionPanelTemplate c1=new AccordionPanelTemplate("Ciao, mondo da Andrea!");
panel1.PanelContent = c1;
Accordion1.AccordionPanels.Add(panel1);
Juice.AccordionPanel panel2 = new Juice.AccordionPanel();
panel2.Title = "Guido Lavespa";
AccordionPanelTemplate c2=new AccordionPanelTemplate("Ciao, mondo da Guido!");
panel2.PanelContent = c2;
Accordion1.AccordionPanels.Add(panel2);
}
public class AccordionPanelTemplate : ITemplate {
private string _testo;
public AccordionPanelTemplate(string testo)
{ _testo= testo; }
public void InstantiateIn(Control container)
{ LiteralControl l = new LiteralControl(_testo);
container.Controls.Add(l);
}
}
}
}
Server side
um 231 di 243
Spa (single page applicationS)
Sono applicazioni web mono pagina che caricano una sola pagina HTML e la aggiornano
dinamicamente invece di caricare nuove pagine.
Dopo il caricamento della pagina web, l’applicazione dialoga con il server attraverso
richieste AJAX facendo uso di jQuery, KNOCKOUT.JS e l’ASP.NET WEB API.
Questo rende la comunicazione performante ed elimina il referesh della pagina.
Fare
clic
su,
File/Nuovo
Progetto…
(CTRL+MAIUSC+N)/Modelli/Visual
C#/Web/Applicazione Web ASP.NET.
Server side
um 232 di 243
Il template genera il progetto seguente.
Eseguire l’applicazione web, genera automaticamente il DB SQL Server di nome
ASPNET-SPA-20140425055118.MDF.
Server side
um 233 di 243
Fare clic su Esplora server.
Selezionare la tabella ASPNETUSERS e con il pulsante destro del mouse fare clic su
Mostra dati tabella.
SPWS (SINGLE PAGE WEB SITE)
È un sito web composto da una sola pagina: all’interno della quale sono organizzati tutti i
contenuti.
Elevato impatto comunicativo, per esempio curriculum vitae, tesina esame di stato,
promozione di un prodotto.
Adatto: a ogni tipo di browser, a ogni tipo di dispositivo: desktop, tablet e mobile.
Si sfrutta il template HTML 5.0 Boilerplate.
I link del menu punteranno a parti specifiche della pagina, individuate dagli ID degli
elementi article.
Ogni area della pagina è individuata da un article, contenente un header e una o più
sezioni.
Dato che tutto il sito è in una pagina, l’utente potrebbe scorrerla a lungo perdendo di vista
la navigazione: ci sono diverse soluzioni.
Nel progetto si è scelto di rendere fisso il menu e creare un effetto dinamico in modo che il
browser non salti direttamente all’elemento desiderato ma lo raggiunga con uno
scorrimento.
Due soluzioni.
1. Plugin JQUERY.SCROLLTO.MIN.JS.
2. Metodo animate di JQuery.
Server side
um 234 di 243
Cartella CSS
MAIN.CSS
Contiene gli stili del sito web, le unità di misura sono relative ed espresse in % e in cm.
Ridimensionando la finestra (cambia la larghezza della viewport), si vede il corpo della
pagina allargarsi e restringersi.
Il riferimento iniziale del lavoro è il desktop, in seguito si modificheranno alcuni elementi
per adattarli agli altri dispositivi.
NORMALIZE.CSS
Rende la resa della pagina indipendente dal browser, infatti, provvede ad azzerare gli stili
predefiniti dei browser affinché il sito sia cross-browser.
Cartella JS
A parte MODERNIZR-2.6.2.MIN.JS, tutti gli altri script sono inclusi in fondo al documento,
per due motivi.
1. Consentire il caricamento del DOM prima dell’esecuzione degli script.
2. Evitare che il caricamento degli script ritardi l’accesso alla pagina da parte dell'utente.
DETECTMOBILEBROWSER.JS
È istanziata la variabile IsMobile che assume valore true o false secondo l’esito del test.
MAIN2.JS
Conoscere la posizione degli elementi rispetto alla viewport, in altre parole l’area visibile
della pagina, permette di aggiungere funzionalità che arricchiscono l’UI, per esempio
modificare il colore delle intestazioni man mano che si avvicinano alla sommità della
viewport.
Bisogna progettare un algoritmo che cambi progressivamente il colore di sfondo degli
elementi header, discendenti da ogni article, man mano che questi si avvicinano, durante
lo scorrimento, alla sommità della viewport (meno di 50px).
Se il blocco article è al di sotto della metà della viewport, lo sfondo dell’header è nero; se è
alla sommità, è rosso scuro; durante lo scorrimento il valore del rosso scuro cambia
linearmente rispetto alla distanza di scorrimento.
Server side
um 235 di 243
Si possono calcolare i valori delle variabili con l’equazione di una retta.
(y - y1) / (y2 - y1) = (x - x1) / (v2 - x1)
Dove la y è il valore rosso scuro e la x la distanza di scorrimento.
Sui dispositivi mobili, il browser non risponde agli eventi nello stesso modo del desktop.
Per esempio, l’evento scroll sul desktop è eseguito pixel per pixel, sui tablet e smartphone,
al contrario, è eseguito solo nel momento in cui lo scorrimento s’interrompe.
Se il comportamento della pagina deve dipendere dallo scostamento graduale della
viewport, si deve correggere la diversa reattività del browser gestendo gli eventi
touchstart, touchmove e touchend.
TS (TYPESCRIPT)
È un nuovo linguaggio di programmazione basato su JavaScript.
Progettato per estendere le funzionalità di JavaScript aggiungendo tipi, classi e moduli per
consentire ai programmatori di realizzare applicazioni più complesse compatibili con ogni
browser e ogni SO.
Utilizza codice sorgente JavaScript e la compilazione fornisce gli stessi risultati.
Nel corso degli ultimi anni la velocità di JavaScript è raddoppiata ogni nove mesi.
Nonostante ciò è aumentato l’utilizzo di HTML 5.0 per realizzare applicazioni web in grado
di fornire una migliore esperienza d’uso agli utenti.
I programmatori hanno cercato di espandere JavaScript oltre il browser per includere
anche app native per i dispositivi, come quelle presenti sul Windows Store o app per il
cloud, come quelle in esecuzione su Windows Azure.
Creare applicazioni su larga scala con JavaScript è però molto complicato, per cui
Microsoft ha deciso di creare il linguaggio TS.
TS è un un linguaggio di scripting client side per pagine web che integra tutti i tool per
l’analisi e l’ottimizzazione del codice JavaScript in un unico linguaggio, adatto sia per
applicazioni client side sia server side.
TS garantisce l’interoperabilità con JavaScript perché funziona con gli stessi framework e
le stesse librerie, il programmatore deve solo fare il copia/incolla del codice JavaScript
all’interno di un file TS.
Compilazione CLI (Command Line Interface)
C:\Program Files (x86)\Microsoft SDKs\TypeScript\1.0>tsc
Version 1.0.1.0
Syntax: tsc [options] [file ..]
Examples: tsc hello.ts
tsc --out foo.js foo.ts
tsc @args.txt
Options:
--codepage NUMBER
Specify the codepage to use when opening source files.
-d, --declaration
Generates corresponding .d.ts file.
-h, --help
Print this message.
--mapRoot LOCATION
Specifies the location where debugger should locate map files
Server side
um 236 di 243
instead of generated locations.
-m KIND, --module KIND Specify module code generation: 'commonjs' or 'a md'
--noImplicitAny
Warn on expressions and declarations with an imp lied 'any' type.
--out FILE
Concatenate and emit output to single file.
--outDir DIRECTORY
Redirect output structure to the directory.
--removeComments
Do not emit comments to output.
--sourcemap
Generates corresponding .map file.
--sourceRoot LOCATION
Specifies the location where debugger should loc ate
TypeScript files instead of source locations.
-t VERSION, --target VERSION Specify ECMAScript target version: 'ES3' (default), or
'ES5'
-v, --version
Print the compiler's version: 1.0.1.0
@<file>
Insert command line options and files from a fil
e.
File PRIMO.TS
function greeter(person)
{ return "Hello, " + person; }
var user = "Jane User";
document.body.innerHTML = greeter(user);
I risultato della compilazione è il file seguente.
File PRIMO.JS
function greeter(person)
{ return "Hello, " + person; }
var user = "Jane User";
document.body.innerHTML = greeter(user);
Server side
um 237 di 243
Compilazione MDE (Microsoft Development Environment)
Per creare un nuovo progetto, fare clic su File/Nuovo/Progetto… (CTRL+MAIUSC+N).
Nella finestra di dialogo Nuovo Progetto selezionare Modelli/TypeScript, quindi
selezionare il tipo di applicazione, Applicazione HTML con TypeScript.
Immettere il nome del progetto nel campo Nome: quindi per creare il progetto, premere
OK.
Visual C# crea una soluzione costituita da un progetto dallo stesso nome, composto a sua
volta da una finestra vuota denominata FORM1.CS.
File APP.CSS
body {
font-family: 'Segoe UI', sans-serif;
}
span {
font-style: italic;
}
File APP.TS
class Greeter {
element: HTMLElement;
span: HTMLElement;
Server side
um 238 di 243
timerToken: number;
constructor(element: HTMLElement) {
this.element = element;
this.element.innerHTML += "The time is: ";
this.span = document.createElement('span');
this.element.appendChild(this.span);
this.span.innerText = new Date().toUTCString();
}
start() {
this.timerToken = setInterval(() => this.span.innerHTML = new Date().toUTCString(),
500);
}
stop() {
clearTimeout(this.timerToken);
}
}
window.onload = () => {
var el = document.getElementById('content');
var greeter = new Greeter(el);
greeter.start();
};
File INDEX.HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>TypeScript HTML App</title>
<link rel="stylesheet" href="app.css" type="text/css" />
<script src="app.js"></script>
</head>
<body>
<h1>TypeScript HTML App</h1>
<div id="content"></div>
</body>
</html>
Server side
um 239 di 243
CAPCTHA
(COMPLETELY AUTOMATED PUBLIC TURING
TEST TO TELL COMPUTERS AND HUMANS APART)
INTRODUZIONE
Letteralmente, test di Turing completamente automatizzato e pubblico per distinguere
computer dagli umani.
Un malintenzionato potrebbe progettare uno script per l’invio automatico di dati,
eseguendo così un attacco di tipo flooding, in pratica inondando l’applicazione di dati
fasulli.
Un attacco di questo tipo può avere conseguenze disastrose: il sovraccarico
dell’applicazione, il collasso del DB con la scrittura di numerosi dati spuri e l’attivazione di
servizi non richiesti.
Un possibile rimedio è un test per verificare la presenza di un operatore umano al
momento dell’inserimento dei dati in un form.
In pratica, sono codici di sicurezza informatica per distinguere tra umani e bot (robot).
Un codice CAPTCHA è solitamente formato da stringhe alfanumeriche case sensitive, di
lunghezza variabile.
La particolarità sta nella maniera in cui queste stringhe sono “stampate a video”: le lettere
sono distorte e semi cancellate tramite trasformazioni geometriche, così da renderle
difficilmente comprensibili a occhio umano e in pratica indecifrabile per un qualsiasi S/W di
tipo OCR (Optical Character Recognition).
Per riuscire a superare il test, bisognerà trascrivere esattamente le stringhe all’interno del
campo posto immediatamente sotto l’immagine.
Un’evoluzione di questa tecnica è il reCAPTCHA sviluppato da Google, le stringhe
alfanumeriche sono parole e numeri tratte da libri antichi e rari presenti in Google Books,
vecchi giornali come le copie dell’archivio storico del New York Times o copioni di vecchi
show radiofonici.
L’intento di questo test è evitare che i bot possano emulare il comportamento dell’utente,
per esempio il riempimento e l’invio di un form.
Intorno alle tecniche di test CAPTCHA e in particolare al meccanismo di ripetizione di testo
distorto contenuto in immagini, c’è un acceso dibattito che ne contesta i limiti
all’accessibilità dei servizi da parte di non vedenti o ipo vedenti.
BATTERE I CAPTCHA
Tre tecniche.
1. Usare manodopera a basso costo con il solo scopo di decifrare anche centinaia di
codici ogni ora, così facendo, si aggirano le restrizioni provocate dal CAPTCHA e si
può portare avanti la propria azione fraudolenta.
2. Sfruttare eventuali falle di sicurezza nell’implementazione del S/W CAPTCHA
all’interno del sito web.
3. Sviluppare S/W di riconoscimento testuale sempre più preciso e potente.
Server side
um 240 di 243
ASP.NET E CAPTCHA
Per implementare in ASP.NET il CAPTCHA è disponibile un controllo open source
scaricabile dal sito www.guru4.net.
È una libreria che si chiama GURU4.NET.WEB.CONTROLS.CAPTCHALIBRARY.DLL.
Per avere a disposizione i controlli, in maniera visuale, nell’IDE di Visual Studio fare clic
con il tasto destro nella Casella degli strumenti e scegliere l’opzione Scegli elementi….
Nella finestra di dialogo che si aprirà selezionare il percorso su disco della libreria.
Una volta aggiunta la libreria nella casella degli strumenti si hanno due nuovi controlli.
VisualCaptcha: si riferisce all’immagine di test.
VisualCaptchaValidator: gestisce la validazione dell’input dell’utente.
Esempio, progettare un codice CAPTCHA.
File WEB.CONFIG
Inserire <httpHandlers> per abilitare l’handler della libreria che crea dinamicamente
l’immagine CAPTCHA.
Server side
um 241 di 243
Un indirizzo di tipo AXD non deve necessariamente corrispondere ad un file fisico su
disco, infatti si può assegnare l’indirizzo ad una classe che implementa HttpHandler che
può essere definita in una libreria.
Da ciò se ne deduce che l’indirizzo VISUALCAPTCHA.AXD è gestito dalla classe
GURU4.NET.WEB.CONTROLS.CAPTCHALIBRARY.VISUALCAPTCHAHANDLER.
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" />
<authentication mode="Windows" />
<httpHandlers>
<add verb="GET" path="visualcaptcha.axd"
type="GURU4.net.Web.Controls.CaptchaLibrary.VisualCaptchaHandler" />
<add verb="GET" path="captcha.axd"
type="GURU4.net.Web.Controls.CaptchaLibrary.BasicCaptchaHandler"
validate="false"/>
</httpHandlers>
</system.web>
</configuration>
File DEFAULT.ASPX
Inserire in un Panel i seguenti controlli.
1. VisualCaptcha: dispone di alcune proprietà per regolare il tempo di validità della stringa
CAPTCHA, proprietà Expiration, il numero dei caratteri della stringa,
ChallengeTextLength e l’URL usato per l’handler, RenderUrl che deve corrispondere a
quello indicato nel WEB.CONFIG, nell’esempio VISUALCAPTCHA.AXD.
2. TextBox per la convalida del testo.
3. VisualCaptchaValidator che gestirà la validazione dell’input, occorre impostare la
proprietà AssociatedVisualCaptchaControlId, ovvero l’ID del controllo VisualCaptcha
cui è associato il Validator, nell’esempio ImgCaptcha; ControlToValidate è l’ID del
controllo da validare, la TextBox.
4. Pulsante per eseguire il test.
Inserire in un altro Panel, inizialmente non visibile, Visible = false, il messaggio di
superamento del test e un link per ricaricare la pagina.
File STYLESHEET.CSS
body {
font:12px verdana,sans-serif;
}
h2 {
font:bold 16px arial,sans-serif;
}
Server side
um 242 di 243
Server side
um 243 di 243
UBERTINI MASSIMO
http://www.ubertini.it
massimo@ubertini.it
Dip. Informatica Industriale
I.T.I.S. "Giacomo Fauser"
Via Ricci, 14
28100 Novara Italy
tel. +39 0321482411
fax +39 0321482444
http://www.fauser.edu
massimo@fauser.edu