34
Capitolo 1 Il modello di programmazione ASP.NET In questo capitolo: Cos’è ASP.NET, in definitiva?............................................................................ 4 Il modello di componente ASP.NET.................................................................... 15 Lo stack di sviluppo ASP.NET........................................................................... 20 Il modello di provider ASP.NET......................................................................... 27 Conclusioni ................................................................................................ 34 ASP.NET è una piattaforma di sviluppo Web che fornisce servizi, un modello di program- mazione, e l’infrastruttura software necessaria a realizzare applicazioni di livello enterprise. Benché la sintassi sia in gran parte compatibile con il popolare predecessore, Active Server Pages (ASP), ASP.NET è un nuovo rivoluzionario framework di programmazione progettato per consentire uno sviluppo rapido di applicazioni Web. Essendo parte della piattaforma Microsoft .NET, ASP.NET fornisce un approccio basato su componenti, estensibile e facile da utilizzare per l’implementazione, il deployment e l’esecuzione di applicazioni Web desti- nate a qualsiasi browser o dispositivo mobile. ASP.NET rappresenta l’apice delle tecnologie di sviluppo Web che si sono rapidamente susseguite negli ultimi dieci anni, ciascuna basata sulla precedente tecnologia, e ciascuna a colmare le lacune del proprio predecessore. Di conseguenza, ASP.NET è al momento la piattaforma più tecnologicamente avanzata, sofisticata e potente per realizzare applicazioni distribuite trasportate dal protocollo HTTP. Nonostante la crescita sorprendentemente in diffusione e l’essere impiegata proficuamente in migliaia di progetti reali, ASP.NET 1.1 è solo il primo passo di una strada chiaramente più lunga. Più si lavora con ASP.NET, più ci si rende conto che è necessario ancora altro. ASP.NET semplifica diversi task e rappresenta una sorta di paradiso della programma- zione, in particolare per gli sviluppatori che provengono da ASP classico, dalla program- mazione Internet Server Application Programming Interface (ISAPI) o da altre piattaforme Web. ASP.NET 1.1 ha semplicemente stimolato l’appetito della comunità degli sviluppatori. Così, dopo i primi mesi di lavoro e valutazione con ASP.NET, i membri di questa community hanno iniziato a chiedere e a desiderare altre funzionalità: in effetti, molte di più. ASP.NET 2.0 rappresenta un principale upgrade alla piattaforma, anche se non introduce alcun para- digma di programmazione nuovo o rivoluzionario. A prima vista, non vi è alcun approccio radicalmente nuovo alla progettazione e all’implementazione del codice, e non vi è alcun nuovo modello di sintassi con cui acquisire familiarità.

Capitolo 1 Il modello di programmazione ASP - Mondadori Informatica

  • Upload
    others

  • View
    2

  • Download
    0

Embed Size (px)

Citation preview

Capitolo 1

Il modello diprogrammazione ASP.NET In questo capitolo:

Cos’è ASP.NET, in definitiva?............................................................................ 4

Il modello di componente ASP.NET.................................................................... 15

Lo stack di sviluppo ASP.NET........................................................................... 20

Il modello di provider ASP.NET......................................................................... 27

Conclusioni ................................................................................................ 34

ASP.NET è una piattaforma di sviluppo Web che fornisce servizi, un modello di program-

mazione, e l’infrastruttura software necessaria a realizzare applicazioni di livello enterprise.

Benché la sintassi sia in gran parte compatibile con il popolare predecessore, Active Server

Pages (ASP), ASP.NET è un nuovo rivoluzionario framework di programmazione progettato

per consentire uno sviluppo rapido di applicazioni Web. Essendo parte della piattaforma

Microsoft .NET, ASP.NET fornisce un approccio basato su componenti, estensibile e facile

da utilizzare per l’implementazione, il deployment e l’esecuzione di applicazioni Web desti-

nate a qualsiasi browser o dispositivo mobile. ASP.NET rappresenta l’apice delle tecnologie

di sviluppo Web che si sono rapidamente susseguite negli ultimi dieci anni, ciascuna basata

sulla precedente tecnologia, e ciascuna a colmare le lacune del proprio predecessore.

Di conseguenza, ASP.NET è al momento la piattaforma più tecnologicamente avanzata,

sofisticata e potente per realizzare applicazioni distribuite trasportate dal protocollo HTTP.

Nonostante la crescita sorprendentemente in diffusione e l’essere impiegata proficuamente

in migliaia di progetti reali, ASP.NET 1.1 è solo il primo passo di una strada chiaramente più

lunga. Più si lavora con ASP.NET, più ci si rende conto che è necessario ancora altro.

ASP.NET semplifica diversi task e rappresenta una sorta di paradiso della programma-

zione, in particolare per gli sviluppatori che provengono da ASP classico, dalla program-

mazione Internet Server Application Programming Interface (ISAPI) o da altre piattaforme

Web. ASP.NET 1.1 ha semplicemente stimolato l’appetito della comunità degli sviluppatori.

Così, dopo i primi mesi di lavoro e valutazione con ASP.NET, i membri di questa community

hanno iniziato a chiedere e a desiderare altre funzionalità: in effetti, molte di più. ASP.NET

2.0 rappresenta un principale upgrade alla piattaforma, anche se non introduce alcun para-

digma di programmazione nuovo o rivoluzionario. A prima vista, non vi è alcun approccio

radicalmente nuovo alla progettazione e all’implementazione del codice, e non vi è alcun

nuovo modello di sintassi con cui acquisire familiarità.

4 Parte I Realizzare una pagina ASP .NET

Ciò nondimeno, ASP.NET 2.0 è una pietra miliare della roadmap Microsoft sullo

sviluppo Web, sia per gli architetti delle applicazioni sia per gli sviluppatori. Molte

delle classi costituenti sono state modificate, e alcune hanno subito degli interventi di

lifting estetico. Sono stati aggiunti diversi nuovi controlli per migliorare la produttività,

e alcuni moduli di sistema, nuovi o migliorati, rendono ora la pipeline di runtime più

personalizzabile, flessibile, robusta e sicura. Di conseguenza, nuove pratiche emergono

come “best practice”, sono disponibili nuove tecniche di programmazione per architetti e

sviluppatori, e nuove caratteristiche di sistema forniscono soluzioni native a noti problemi

con le precedenti versioni. Per massimizzare i vantaggi nell’utilizzo di ASP.NET, si deve

prima osservare il modello complessivo: componenti, programmabilità e infrastruttura.

Un’occhiata da vicino al modello complessivo è esattamente ciò che questo capitolo

fornisce. Per iniziare, esaminiamo alcuni concetti essenziali della piattaforma ASP.NET

e del relativo modello di programmazione.

Cos’è ASP.NET, in definitiva?

Prima dell’avvento di ASP.NET, erano disponibili tre principali tecnologie e

piattaforme per sviluppare applicazioni Web: ASP, Java Server Pages (JSP) e la

piattaforma Web opensource comunemente riferita come LAMP (Linux più Apache più

MySQL più Perl, Python o PHP come linguaggio di programmazione).

[Nota] Per completezza, vanno anche menzionate un paio di tecnologie di livello più basso, specifi che delle piattaforme, su cui si basano ASP e JSP. ASP è in effetti una estensione ISAPI, mentre JSP viene implementata come una speciale applicazione servlet. Le estensioni ISAPI su piattaforme basate su IIS e le servlet su sistemi basati su Java, permettono di creare applicazioni lato server, con un deployment Web, utilizzando un approccio più classico. Si scrive un modulo che costruisce e renderizza la pagina piuttosto che progettare la pagina in modo dichiarativo utilizzando un mix di testo di markup e di codice embedded.

Benché ciascuna abbia caratteristiche specifiche al linguaggio e all’architettura, tutte

queste piattaforme di sviluppo Web sono progettate per creare pagine interattive che costi-

tuiscono una parte di una applicazione Web. Entro certi limiti, tutte permettono agli svilup-

patori di separare la logica di programmazione dal layout di pagina attraverso l’utilizzo di

componenti che la pagina stessa è responsabile di invocare e renderizzare. A parte questo

comune obiettivo finale, esistono importanti differenze tra queste piattaforme, gran parte

delle quali sono relative al modello di programmazione e ai linguaggi che promuovono e

supportano. Ad esempio, JSP sfrutta il framework Java di classi e, con JavaBeans, fornisce

un efficace modello di estensibilità per il riutilizzo dei componenti. Inoltre, JSP supporta la

personalizzazione dei tag e permette agli sviluppatori di associare del codice a una defini-

zione di tag custom. Infine, essendo un elemento chiave della piattaforma Java 2 Enterprise

Edition (J2EE), JSP si basa sul linguaggio Java, un vero linguaggio compilato, al contrario

dei linguaggi di scripting utilizzati da entrambe le piattaforme ASP e LAMP. Pertanto come

si posiziona esattamente ASP.NET?

Capitolo 1 Il modello di programmazione ASP .NET 5

Analogamente a ASP e ad altri ambienti di sviluppo Web, anche ASP.NET utilizza il pro-

tocollo HTTP e sfrutta i comandi HTTP e le policy per impostare una comunicazione e una

cooperazione bidirezionale tra browser e server. Ciò che realmente distingue ASP.NET dalla

pletora delle altre tecnologie di sviluppo Web è il modello di programmazione astratto che

propone, il modello Web Forms. Inoltre, l’intera piattaforma ASP.NET è parte nativa del

Microsoft .NET Framework. Per essere certi di afferrare l’importanza di questo ultimo pun-

to, permettetemi di chiarirlo. Le applicazioni ASP.NET sono blocchi di codice compilato,

sono costituite da componenti riusabili e estensibili, possono essere create con linguaggi

di tutto rispetto (tra cui C#, Microsoft Visual Basic .NET, Microsoft JScript .NET, e J#), e

possono accedere all’intera gerarchia di classi del .NET Framework.

In sintesi, ASP.NET riunisce il meglio dei diversi approcci. È semanticamente compatibi-

le (e vi è, entro certi limiti, anche una compatibilità di linguaggio) con ASP. Fornisce le stes-

se caratteristiche object-oriented delle applicazioni JSP (personalizzazione dei tag, linguaggi

compilati, componenti, estensibilità e riusabilità). E come ciliegina sulla torta, ASP.NET of-

fre una notevole scelta di squisitezze, tool e potenti caratteristiche di sistema che possono

essere effettivamente riassunte con l’espressione generica tool per astrarre il modello di

programmazione HTTP. Una gran quantità di classi di facile utilizzo per i programmatori

permettono di sviluppare pagine utilizzando i tipici metodi da applicazione desktop. Il mo-

dello Web Forms promuove un approccio complessivo a eventi, ma è distribuito sul Web.

[Nota]ASP.NET è supportato su una varietà di piattaforme, compreso Microsoft Windows 2000 con almeno il Service Pack 2, Windows XP Professional e Windows Server 2003. Per sviluppare applicazioni server ASP.NET, è anche necessario Internet Information Services (IIS) versione 5.0 o successiva. Altro software necessario, ad esempio Microsoft Data Access Components (MDAC) 2.7, viene automaticamente installato quando si installa il .NET Framework. In termini di prestazioni, robustezza e sicurezza, la combinazione ideale di software di sistema per ospitare applicazioni ASP.NET sembra essere Windows Server 2003 (preferibilmente con Service Pack 1) e IIS 6.0.

La programmazione nell’era delle Web Forms

La motivazione alla base del modello ASP.NET Web Forms è direttamente connessa

alla ricerca di una migliore strategia per gestire la crescente richiesta di una interazione

Web economica ma potente. Difatti, il protocollo HTTP rappresenta la maggiore forza

e debolezza delle applicazioni Web. La natura stateless del protocollo HTTP introduce

concetti di programmazione del tutto differenti, estranei a molti sviluppatori desktop:

innanzitutto, tra questi concetti, la gestione dello stato di sessione. D’altro canto,

l’intrinseca semplicità e scalabilità di HTTP è la chiave della sua adozione universale e

della sua efficacia: in sintesi, probabilmente non potremmo avere Internet per come la

conosciamo senza un protocollo come HTTP. Eppure, man mano che aumenta la richiesta

di applicazioni sofisticate e potenti, i programmatori devono escogitare dei modi migliori

per stabilire una facile ed efficace comunicazione dal client al server e viceversa.

6 Parte I Realizzare una pagina ASP .NET

Col tempo, sono state sperimentate varie tecniche per agevolare la comunicazione tra

pagine differenti e tra più invocazioni alla stessa pagina. Gran parte dei programmatori

sono abituati a pensare in termini di azione generata dal client che produce una

reazione lato server. Questo pattern essenziale e fondamentale non può essere seguito

sul Web, perlomeno non alla lettera. È necessario un certo grado di astrazione e alcuni

servizi di sistema perché si abbia una comunicazione agevole.

ASP, molto più di JSP, pensa in modo dichiarativo ed ha un modello a oggetti

abbastanza esiguo e inadeguato. In generale, i programmatori che sono diventati

programmatori Web sono costretti ad adottare una mentalità differente e a scaraventare

dalla porta il comune paradigma di azione/reazione.

Programmazione a eventi su HTTP

I Web Forms ASP.NET estendono al Web il modello di interazione a eventi.

L’implementazione di un modello a eventi sul Web richiede che qualsiasi dato relativo al-

l’attività dell’utente lato client sia inoltrato al server per una elaborazione corrispondente e

stateful. Il server processa l’output delle azioni del client e scatena delle reazioni. Lo stato

dell’applicazione contiene due tipi di informazioni: lo stato del client e lo stato della sessio-

ne. Lo stato del client, per lo più il contenuto dei campi di input del form collegialmente ri-

feriti come stato della pagina, è facilmente accessibile attraverso le collection lato server che

memorizzano i valori postati. E per quanto riguarda lo stato complessivo della sessione? Il

client si aspetta che l’invio di informazioni al server attraverso una pagina sia naturalmente

correlato a qualsiasi altra pagina che può visualizzare in seguito, così come avviene quando

si aggiungono articoli a un carrello. Chi ricorda cosa un particolare utente ha nel carrello?

Di per sé, HTTP non è in grado di tener di traccia di queste informazioni; ed è qui che entra-

no in gioco lo stato della sessione e una opportuna infrastruttura lato server che circonda e

integra HTTP. Non è mai abbastanza enfatizzare l’importanza della comprensione dei con-

cetti coinvolti nella programmazione stateless nello sviluppo di applicazioni Web. Come

già detto, HTTP è un protocollo stateless, il che significa che due richieste successive duran-

te la stessa sessione non hanno alcuna conoscenza reciproca. Vengono risolte da ambienti

appena istanziati in cui non viene mantenuta alcuna informazione specifica di sessione, ad

eccezione delle informazioni che l’applicazione stessa può aver memorizzato negli oggetti

globali. In ASP, i form rientranti rappresentavano un modo comune per aggirare questa

limitazione di sistema. Un form rientrante è un elemento HTML <form> che esegue il post

alla stessa pagina che lo contiene. I form rientranti di per sé non risolvono pienamente il

problema. Tuttavia, combinandoli con blocchi di codice e campi nascosti che memorizzano

le informazioni di stato critiche per la pagina, molti sviluppatori superano elegantemente

l’ostacolo. Ciò che rappresentava una best-practice ASP è stata standardizzata e integrata

nel runtime ASP.NET per diventare la caratteristica principale che dota le applicazioni

ASP.NET di una manutenzione automatica dello stato. Il runtime ASP.NET trasporta lo stato

di pagina avanti e indietro unitamente alle richieste di pagina. Nel generare codice HTML

per una determinata pagina, ASP.NET codifica e inserisce lo stato degli oggetti lato server

in alcuni campi nascosti, creati in modo del tutto trasparente. Quando viene richiesta la

pagina, lo stesso motore del runtime ASP.NET ricerca le informazioni di stato embedded,

ossia i campi nascosti, e utilizza qualsiasi informazione decodificata per impostare le istanze

Capitolo 1 Il modello di programmazione ASP .NET 7

appena create degli oggetti lato server. L’effetto finale di tale meccanismo non è diverso dal

modello Windows Forms sul desktop ed è riassunto nella Figura 1-1.

Figura 1-1 Confronto tra i modelli Windows Forms e Web Forms del .NET Framework.

Il modello Windows Forms deriva dal tipico stile di programmazione a eventi desktop.

Non importa che connettività esista tra i componenti client e server, il server opera sempre

in reazione all’input del client. Il server è consapevole dello stato complessivo dell’appli-

cazione e opera in una modalità two-tier, connessa. Il modello Web Forms necessita di

qualche meccanismo per supportare lo stesso modello di programmazione a eventi. In

Figura 1-1, il meccanismo necessario viene rappresentato dalla deserializzazione dello stato

che si verifica quando viene richiesta la pagina, e dalla serializzazione dello stato eseguita

quando sta per essere generata la risposta HTML. A farsi carico di questo lavoro di filtraggio

è il runtime HTTP di ASP.NET, un blocco di codice che estende e specializza le funzionalità

complessive del Web server ospite. I form rientranti e i campi nascosti rappresentano gli

strumenti di basso livello utilizzati per eseguire il trucco. Un tale modello non sarebbe tanto

efficace senza un sofisticato modello a oggetti di backend, che abbraccia l’intero contenuto

della pagina server. Cruciale alla realizzazione e al funzionamento efficace della piattaforma

di sviluppo ASP.NET è il modello a componenti. Il modello a componenti ASP.NET identi-

fica e descrive i blocchi fondamentali delle pagine ASP.NET. Viene implementato attraverso

un modello a oggetti che fornisce un equivalente lato server a, virtualmente, qualsiasi ele-

mento della pagina HTML, tra cui i tag HTML come <form> e <input>. Inoltre, il model-

lo a oggetti ASP.NET comprende numerosi componenti (detti controlli server o controlli

Web) che rappresentano elementi più complessi dell’interfaccia utente (UI). Alcuni di que-

sti controlli non hanno alcuna mappatura diretta con singoli elementi HTML ma vengono

implementati combinando più tag HTML. Esempi tipici di complessi elementi UI sono il

controllo Calendar e il controllo DataGrid.

8 Parte I Realizzare una pagina ASP .NET

Alla fine, una pagina ASP.NET è costituita da un certo numero di controlli server

mescolati con testo letterale, markup e immagini. I dati sensibili estratti dalla pagina e

lo stato dei controlli vengono memorizzati in modo non intrusivo in campi nascosti,

e formano il contesto di questa richiesta di pagina. L’associazione tra una istanza

della pagina e il relativo stato è inequivocabile, non modificabile da programma, ed è

controllato dal runtime HTTP ASP.NET. Il modello a componenti ASP.NET è la prima

sosta verso una completa comprensione della piattaforma ASP.NET. Il modello a

componenti vi scorta attraverso l’intero ciclo di sviluppo, compresa la fase di creazione

della pagina e la configurazione di sistema a runtime, come mostrato nella Figura 1-2.

Figura 1-2 Una vista dello stack di sviluppo ASP.NET. La freccia indica la tipica prospettiva top-down dell’applicazione, che va dall’interfaccia utente ai servizi di sistema.

Prima di addentrarci nei vari elementi mostrati nella Figura 1-2, esaminiamo bre-

vemente i fondamenti del protocollo HTTP, che rimane la base dell’interazione Web.

Dopodiché, passeremo a descrivere la struttura di una pagina ASP.NET e come scrivere

e distribuire le applicazioni ASP.NET.

Il protocollo HTTP

Questo paragrafo fornisce una rapida panoramica su come operano applicazioni

Web. Se si ha già una conoscenza operativa dell’infrastruttura Web, si può saltare

al successivo paragrafo “Struttura di una pagina ASP.NET”. L’acronimo HTTP è

diventato così comune per noi sviluppatori che talvolta non ricordiamo esattamente

Capitolo 1 Il modello di programmazione ASP .NET 9

cosa significa. Effettivamente, HTTP significa Hypertext Transfer Protocol. HTTP è un

protocollo testuale che definisce come comunicano i browser Web e i server Web. Il

formato dei pacchetti HTTP è descritto completamente nel documento RFC 2068 ed è

disponibile all’indirizzo http://www.w3.org/Protocols/rfc2068/rfc2068.txt. I pacchetti

HTTP viaggiano su una connessione Transmission Control Protocol (TCP) diretta di

default verso la porta 80 dell’indirizzo Internet Protocol (IP) di destinazione.

La richiesta HTTP

Quando si fa puntare il browser a una URL, il browser utilizza il Domain Name

System (DNS) disponibile per tradurre il nome del server fornito nella URL in un

indirizzo IP. Successivamente, il browser apre un socket e si connette alla porta 80 di

questo indirizzo. Il pacchetto con la richiesta di download per http://www.contoso.com/

default.aspx può assumere la seguente semplice forma:

GET /default.aspx HTTP/1.1Host: www.contoso.com

La prima riga di testo in una richiesta è la start line della richiesta. Deve contenere

il nome del comando HTTP da eseguire (GET in questo caso), la URL della risorsa, più

la versione del protocollo HTTP che si vuole utilizzare.

Una richiesta HTTP può contenere, e di solito contiene, alcuni header. Un header

HTTP è una riga di testo che fornisce ulteriori informazioni sulla richiesta. Nella

richiesta HTTP appena mostrata, la riga che inizia con “Host:” è un header HTTP. Gli

header che si possono trovare in una richiesta HTTP comprendono i seguenti:

• User-Agent Identifica il tipo di browser che ha originato la richiesta

• Connection Chiude una connessione o mantiene attiva una connessione

• If-Modified-Since Fornisce una validazione della cache lato client

GET e POST rappresentano i comandi o verbi HTTP più comunemente utilizzati. Il

verbo GET significa recuperare qualsiasi informazione sia identificata dalla URL richiesta.

Il verbo POST viene utilizzato per richiedere che il server di origine accetti il contenuto

racchiuso nella richiesta e lo processi. Tipicamente, il verbo POST viene utilizzato per

fornire un blocco di dati (ossia, il risultato di un invio di un form) a un processo di

gestione dati.

La risposta HTTP

La risposta del server comprende una status line costituita dalla versione del

protocollo del messaggio e dal cosiddetto “exit code” (che indicano l’esito positivo

o che si è verificato un errore). La status line è seguita da un gruppo di header,

tipicamente il tipo di contenuto e la lunghezza della pagina, e dal contenuto del body.

Una riga vuota separa il contenuto del body dal resto del messaggio, come mostrato

nella seguente risposta:

HTTP/1.1 200 OKServer: Microsoft-IIS/5.0Content-Type: text/html

10 Parte I Realizzare una pagina ASP .NET

Content-Length: 51

<html><body><h1>ASP.NET is cool!</h1></body></html>

Il codice precedente illustra il semplice output HTML restituito dal Web server.

Richieste e risposte sono stringhe formattate in base allo schema HTTP, e viaggiano

su una connessione TCP. Il codice 200 significa che l’elaborazione della richiesta

ha avuto esito positivo. Il Web server specificato processa la richiesta e restituisce

un contenuto di una certa lunghezza espresso in un determinato tipo Multipurpose

Internet Mail Extensions (MIME), (text/html). I codici HTTP che possono essere

restituiti vengono elencati nella specifica HTTP, disponibile alla suddetta URL.

Inoltre, va notato che la riga vuota tra l’ultimo header e il contenuto della risposta

HTTP non è semplice formattazione: la coppia carriage-return/line-feed è richiesta

ed è una parte precisa dello standard.

Cosa accade dopo, dipende in gran parte dal tipo MIME e dalle funzionalità del

browser locale. Finché il tipo MIME è text/html, il browser visualizza il contenuto come

HTML. Se il tipo MIME è, ad esempio, text/xml, alcuni browser renderizzeranno il

contenuto come semplice testo, mentre altri (ad esempio, Microsoft Internet Explorer

6.0) applicheranno uno stylesheet predefinito.

Realizzare un livello di astrazione lato server

Ogni conversazione tra browser e Web server è costituita da uno scambio di

pacchetti simile a quella che abbiamo appena esaminato. Se la URL richiesta è una

pagina HTML, il server Web tipicamente legge il contenuto del file .html e lo inietta nel

corpo del pacchetto di risposta. Se la URL è una pagina ASP.NET, viene coinvolto uno

speciale modulo IIS. Il modulo è un plug-in IIS ISAPI.

Una estensione ISAPI è una dynamic-link library (DLL) registrata per gestire

una determinata estensione di file. Una estensione ISAPI registrata per gestire file

.aspx viene coinvolta ogni qualvolta giunge una richiesta per questo tipo di risorsa.

L’estensione ISAPI analizza la richiesta e configura l’ambiente lato server che processerà

effettivamente il sorgente della pagina. Quando lo stato della richiesta è stato recuperato

con esito positivo ed è stato completamente ripristinato, alla pagina viene permesso di

passare in esecuzione e di produrre l’output HTML.

Invio di form

Il tag HTML <form> è l’unico elemento autorizzato a trasmettere al server dati lato

client. Quando l’utente clicca su un pulsante di tipo “submit”, per progetto il browser

inserisce il contenuto corrente di tutti i controlli che appartengono al form in una stringa.

La stringa viene quindi passata al server come parte del comando GET o POST.

Il seguente frammento HTML illustra un semplice form che contiene una textbox e un

pulsante submit. Come si può vedere, al form viene associato il comando POST e la URL

default.aspx:

<form method=”post” action=”default.aspx”> <input type=”text” name=”EmpCode” /> <input type=”submit” value=”Send” /></form>

Capitolo 1 Il modello di programmazione ASP .NET 11

La seguente richiesta mostra il comando POST che raggiunge il server Web quando

l’utente clicca il pulsante submit:

POST /default.aspx HTTP/1.1Host: www.contoso.comContent-Type: application/x-www-form-urlencodedContent-Length: 12

EmpCode=1001

Mentre elabora la richiesta di pagina, l’estensione ISAPI scandisce il body della

richiesta ed espone qualsiasi informazione trovata attraverso un modello a oggetti più

agevole per il programmatore. Ad esempio, invece di rimanere una semplice stringa

nome/valore, la variabile EmpCode viene spostata all’interno di una collection a livello

di applicazione: la collection Request.Form. Ciò rappresenta un primo livello di

astrazione implementato sul grezzo modello di programmazione HTTP. Oggetti come

Request, Response e Server formano il contesto HTTP della invocazione e, in quanto tali,

rappresentano l’insieme minimo di oggetti che si trovano in gran parte delle piattaforme

di sviluppo Web, compreso JSP e ASP. In ASP.NET, tuttavia, se ne trovano molti altri.

Struttura di una pagina ASP.NET

Una pagina ASP.NET è un file di testo lato server salvato con estensione .aspx.

La struttura interna della pagina è estremamente modulare e comprende tre sezioni

distinte: direttive di pagina, codice e layout di pagina:

• Direttive di pagina Le direttive di pagina impostano l’ambiente in cui verrà

eseguita la pagina, specificano come il runtime HTTP dovrà processare la pagina,

e determinano quali assunzioni è sicuro fare sulla pagina. Le direttive permettono

anche di importare i namespace per semplificare la codifica, caricare gli assembly

al momento non presenti nella Global Assembly Cache (GAC), e registrare nuovi

controlli con nomi di tag e prefissi di namespace personalizzati.

• Sezione di codice La sezione di codice contiene gli handler degli eventi di pagina

e dei controlli, più delle routine di supporto opzionali. Qualsiasi codice sorgente

pertinente alla pagina può essere inserito inline o allegato alla pagina attraverso un

file separato. Se inserito inline, il codice viene inserito in un tag con il fuorviante nome

di <script>. (Il nome <script> è stato scelto per motivi di compatibilità all’indietro).

I tag <script> lato server vengono distinti dai tag <script> lato client per mezzo

dell’utilizzo dell’attributo runat=server. (Torneremo su ciò a breve). Qualsiasi codice

di pagina viene sempre compilato prima dell’esecuzione. In ASP.NET 2.0, può anche

essere precompilato e distribuito sotto forma di assembly binario.

• Layout di pagina Il layout di pagina rappresenta lo scheletro della pagina. Comprende

i controlli server, il testo letterale e i tag HTML. L’interfaccia utente dei controlli

server può essere rimpolpata un po’ utilizzando gli attributi dichiarati e le proprietà

dei controlli.

12 Parte I Realizzare una pagina ASP .NET

Perché la pagina funzioni, non è necessario specificare tutte le sezioni. Benché le

pagine reali comprendano tutte le sezioni menzionate, pagine perfettamente valide e

funzionali possono comprendere solo la sezione di codice o il layout di pagina. In alcuni

casi speciali, si può anche avere una pagina ASP.NET costituita da una singola direttiva.

Nel Capitolo 2, e ancor più nel Capitolo 3, tratteremo a fondo le caratteristiche di

una pagina e i blocchi costituenti.

Una pagina ASP.NET d’esempio

È il momento di vedere come appare una pagina ASP.NET. Per iniziare, sarà suffi-

ciente un semplice editor di testo; pertanto apriamo Notepad e lasciamo riposare il

gigante addormentato (Microsoft Visual Studio .NET).

Il codice seguente implementa una semplice pagina ASP.NET che permette di inse-

rire una stringa e quindi di trasformarla in maiuscolo dopo aver premuto un pulsante.

Per semplicità, utilizziamo del codice inline. (Come si vedrà in seguito, non è così che

si farà nelle applicazioni reali e in qualsiasi pagina di una certa complessità).

<!-- Direttive -->

<% @Page Language=”C#” %>

<!-- Sezione Codice -->

<script runat=”server”>private void MakeUpper(object sender, EventArgs e){ string buf = TheString.Value; TheResult.InnerText = buf.ToUpper();}</script>

<!-- Layout -->

<html><head><title>Pro ASP.NET (Ch 01)</title></head><body><h1>Make It Upper</h1><form runat=”server”> <input runat=”server” id=”TheString” type=”text” /> <input runat=”server” id=”Button1” type=”submit” value=”Proceed...” OnServerClick=”MakeUpper” /> <hr> <h3>Results:</h3> <span runat=”server” id=”TheResult” /></form></body></html>

Le righe vuote e i commenti nel listato precedente separano le tre sezioni:

direttive, codice e layout di pagina. Si noti l’utilizzo generoso dell’attributo runat: è

uno dei blocchi più importanti dell’intero mosaico ASP.NET. Nel paragrafo successivo,

discuteremo runat in maggior dettaglio. Per ora, basti dire che l’attributo runat

promuove un altrimenti inerte tag lato server al rango di istanza di un componente.

Il layout di pagina è costituito da testo letterale e tag HTML, alcuni dei quali

contengono il suddetto attributo runat. Tutto ciò che viene contrassegnato in

Capitolo 1 Il modello di programmazione ASP .NET 13

questo modo, nonostante le apparenze, non è realmente un elemento HTML. Più

precisamente, è il segnaposto di markup di un componente lato server, un controllo

ASP.NET, che è effettivamente responsabile del markup finale servito al browser. In

un sorgente ASP.NET, ogni tag contrassegnato con l’attributo runat non è output

così come è, ma subisce un processo di trasformazione sul server al termine del quale

viene generato il markup reale. Il runtime ASP.NET è responsabile della mappatura

dei tag in istanze del controllo. Esaminiamo rapidamente il codice.

Un rapido esame del codice

Grazie all’attributo runat il campo di input di testo diviene una istanza della

classe HtmlInputControl quando la pagina viene processata sul server. La proprietà

Value della classe determina il testo di default da assegnare al campo di input.

Quando l’utente clicca il pulsante submit, la pagina esegue automaticamente un

post a se stessa. La magia viene eseguita dall’attributo runat impostato dal tag

<form>. Una volta sul server, il valore postato del campo di input viene letto e

assegnato automaticamente alla proprietà Value di una istanza appena creata di

HtmlInputControl. Successivamente, viene eseguito il codice associato all’evento

OnServerClick. Questo codice prende il contenuto corrente del textbox, la stringa

postata, e lo converte in lettere maiuscole. Infine, la stringa in maiuscolo viene

assegnata alla proprietà InnerText del controllo lato server collegato al tag HTML

<span>. Quando termina il gestore d’evento MakeUpper, la pagina è pronta per il

rendering. A questo punto, il codice HTML aggiornato viene inviato al browser.

Per testare la pagina, bisogna copiare il file .aspx nella directory root del proprio

Web server. Normalmente, è c:\inetpub\wwwroot. Volendo, si può creare una directory

virtuale ad hoc. Supponiamo che la pagina si chiami hello.aspx. Successivamente, si fa

puntare il browser alla pagina. La Figura 1-3 mostra il risultato.

Figura 1-3 La prima (e piuttosto semplice) pagina ASP.NET in azione.

14 Parte I Realizzare una pagina ASP .NET

Sarebbe utile dare un’occhiata al sorgente HTML della pagina quando viene

visualizzata la prima volta all’utente, ossia prima che l’utente clicchi per rendere il

testo in maiuscolo.

<!-- Direttive -->

<!-- Sezione Codice -->

<!-- Layout --><html><head><title>Pro ASP.NET (Ch 01)</title></head><body><h1>Make It Upper</h1><form method=”post” action=”hello.aspx” id=”Form1”>

<div> <input type=”hidden” name=”__EVENTTARGET” value=”” /> <input type=”hidden” name=”__EVENTARGUMENT” value=”” /> <input type=”hidden” name=”__VIEWSTATE” value=”/wEPDwUJNzM4N…==” /></div>

<script type=”text/javascript”>

<!--

var theForm = document.forms[‘Form1’];

if (!theForm) {

theForm = document.Form1;

}

function __doPostBack(eventTarget, eventArgument) {

if (!theForm.onsubmit || (theForm.onsubmit() != false)) {

theForm.__EVENTTARGET.value = eventTarget;

theForm.__EVENTARGUMENT.value = eventArgument;

theForm.submit();

}

}

// -->

</script>

<input name=”TheString” type=”text” id=”TheString” value=”Hello, world” /><input name=”Button1” type=”submit” id=”Button1” value=”Proceed ...” /><hr><h3>Results:&nbsp;</h3><span id=”TheResult”></span></form></body></html>

Nel tag <form>, è stato aggiunto un attributo action cablato per forzare il

posting alla stessa pagina. Ciò avviene per progetto ed è uno degli aspetti più

caratteristici di ASP.NET. I vari campi nascosti che si osservano sono essenziali

per l’implementazione del meccanismo di postback e vengono generati

automaticamente. La stessa cosa può essere detta per il codice di script inglobato. I

tag <input> sono pressoché identici ai relativi equivalenti nel sorgente .aspx: solo

l’attributo runat è scomparso.

Dopo esserci sporcati le mani con il codice ASP.NET, facciamo un passo indietro

e esaminiamo gli strati che effettivamente fanno funzionare le pagine ASP.NET nel

contesto di una applicazione.

Capitolo 1 Il modello di programmazione ASP .NET 15

Il modello a componenti ASP.NET

ASP.NET è la principale tecnologia abilitante di tutte le funzionalità orientate

al Web fornite dal .NET Framework. Il .NET Framework è costituito interamente

da una gerarchia object oriented di classi che abbracciano tutti gli argomenti di

programmazione dei sistemi operativi Windows. In termini generali, una applicazione

Web è costituita da pagine che l’utente richiede da un server e che il server processa e

restituisce come codice di markup, per la maggior parte HTML. Come la risorsa richiesta

venga processata, e perciò come viene generato il markup, è un aspetto specifico del

server. In particolare, quando la risorsa ha una estensione .aspx, IIS delega qualsiasi

ulteriore elaborazione al sistema runtime ASP.NET.

Il runtime ASP.NET trasforma il codice sorgente della pagina .aspx richiesta

nell’istanza attiva di una classe del .NET Framework che deriva da una classe base

denominata Page. Alla fin fine, una pagina ASP.NET in esecuzione è un oggetto, e

pertanto lo è per alcuni dei suoi componenti: i controlli lato server.

Un gran numero di nuove caratteristiche ASP.NET sono semplicemente una

propagazione diretta o indiretta della infrastruttura .NET. ASP.NET trae vantaggio dalla

integrazione inter-linguaggio e dalla gestione delle eccezioni, dalla garbage collection e

dalla Code Access Security, dal deployment e dalla configurazione, e da una libreria di

classi incredibilmente sofisticata. Tutte queste caratteristiche non sono il prodotto di un

motore auto-contenuto, sono disponibili poiché le applicazioni ASP.NET rappresentano

una varietà speciale di applicazione .NET.

Un modello di interazione del componente

A qualsiasi elemento in una pagina ASP.NET contrassegnato con l’attributo runat può

essere attribuito un ID univoco, permettendo di accedere a questo elemento dal proprio

codice lato server. L’accesso agli elementi attraverso l’ID è un approccio naturale sul client

(come l’utilizzo di pagine Dynamic HTML), ma rappresenta uno schema del tutto nuovo

per le applicazioni server. Due fattori rendono possibile questo approccio rivoluzionario:

• L’architettura basata su componenti della piattaforma .NET, e il fatto che ASP.NET è

una parte integrante di questa piattaforma

• Il meccanismo predefinito ASP.NET di gestione dello stato dell’applicazione

Il design a componenti di .NET rende l’interazione del componente agevole ed

efficace in tutti gli ambienti, comprese le applicazioni ASP.NET. I componenti ASP.NET

accedono alle caratteristiche della pagina e interagiscono reciprocamente invocando

metodi e impostando proprietà.

Il fatto che tutti gli elementi della pagina siano veri componenti, e non semplicemente

testo scandibile, fornisce un modello di estensibilità flessibile e potente. La creazione

di nuovi controlli è agevole quanto la derivazione di una nuova classe; realizzare una

gerarchia di ereditarietà di pagina è agevole quanto specificare una classe genitore

differente dalla classe di base Page.

16 Parte I Realizzare una pagina ASP .NET

[Attenzione] Visual Studio .NET 2005 restituisce un errore in fase di progettazione se non si assegna esplicitamente a ciascun controllo ASP.NET un ID univoco. Tuttavia, la pagina funzionerà a dovere a runtime.

L’attributo runat

L’attributo runat è ciò che determina se un blocco di testo di markup deve essere

emesso alla lettera al momento del rendering o deve essere trasformato in una istanza

stateful di una particolare classe .NET. In quest’ultimo caso, la classe si assume la

responsabilità di emettere il relativo markup. In una pagina ASP.NET, tutti gli elementi

di markup il cui attributo runat è impostato a server vengono considerati controlli lato

server. La classe del controllo espone metodi e proprietà che permettono di configurare

lo stato del componente. Il controllo è responsabile di emettere il codice HTML quando

la pagina viene renderizzata al browser. Consideriamo il seguente semplice codice che

renderizza un elemento ancora nella pagina client:

Response.Write(“<A id=myAnchor href=www.asp.net>Click me</A>”)

L’elemento ancora viene creato da programma e non viene definito nel layout di

pagina. In ASP classico, i blocchi di codice e il metodo Response.Write rappresentano

gli unici modi disponibili per creare o configurare dinamicamente i controlli. In alcuni

ambienti di sviluppo, tra cui Microsoft Visual InterDev, i controlli design-time fornivano

un modo a oggetti per emettere in output HTML generato dinamicamente. I controlli

design-time, tuttavia, rappresentavano appunto ciò che il nome indica: ossia, controlli

che si possono utilizzare a design-time per generare markup e codice script. In ASP.NET,

è disponibile una nuova varietà di controlli che potremmo chiamare controlli run-time

per evidenziare il contrasto con i controlli design-time.

Lavorare con i controlli lato server

In una pagina ASP, non vi è modo per associare codice all’elemento myAnchor.

Si tratta solo di testo congelato, inerte, utile solo da inviare al browser. Una volta su

un client, l’elemento myAnchor riprende vita e può accettare istruzioni di scripting.

Si supponga ora di dover impostare l’attributo href dell’ancora in base a condizioni a

runtime. In ASP classico, si potrebbe prima ottenere il valore dell’attributo href e quindi

invocare Response.Write:

strHref = “www.asp.net”strHtml = “<A id=myAnchor “strHtml = strHtml + “href=” + strHrefstrHtml = strHtml + “>Click me</A>”Response.Write(strHtml)

Questo codice funzionerà immutato in una pagina ASP.NET ma di certo non è

quanto di meglio si possa fare. Dichiarando il tag <A> con l’attributo runat, si può dar

vita all’elemento ancora anche sul server:

<A runat=”server” id=”myAnchor”>Click me</A>

Capitolo 1 Il modello di programmazione ASP .NET 17

Quando la pagina viene caricata, il runtime ASP.NET scandisce il codice sorgente e

crea le istanze di tutti i controlli contrassegnati con l’attributo runat. In tutta la pagina,

l’ID di myAnchor identifica una istanza del controllo lato server mappato al tag <A>.

Il codice seguente può essere utilizzato per impostare da programma l’attributo href

quando la pagina viene caricata:

<script runat=”server” language=”C#”>void Page_Load(object sender, EventArgs e){ myAnchor.HRef = “http://www.asp.net”;}</script>

Gli elementi di markup il cui nome corrisponde a un elemento HTML vengono

mappati al corrispondente controllo server HTML. Si noti che non tutti i possibili

tag HTML hanno dei corrispondenti controlli ASP.NET; per quelli sprovvisti, viene

utilizzato un controllo generico. L’elenco dei tag e dei relativi controlli associati è

cablato nel runtime ASP.NET. Gli elementi che appartengono al namespace <asp>

vengono mappati ai controlli Web server. Altri elementi di markup vengono mappati

all’assembly e al nome di classe dichiarato utilizzando una direttiva @Register.

Tag a livello di pagina

L’attributo runat può essere utilizzato anche con tag a livello di pagina come

<head> e <body>. Questi tag vengono rappresentati attraverso una istanza della

classe HtmlGenericControl. HtmlGenericControl è la classe .NET utilizzata per

rappresentare un tag HTML lato server non direttamente rappresentato da una classe

del .NET Framework. L’elenco di questi tag comprende anche <span>, <font> e

<iframe>.

Nella pagina seguente, il colore di sfondo viene impostato da programma quando la

pagina viene caricata:

<%@ Page Language=”C#” %><script runat=”server”>private void Page_Load(object sender, EventArgs e)

{

TheBody.Style[HtmlTextWriterStyle.BackgroundColor] = “lightblue”;

}

</script><html><body id=”TheBody” runat=”server”>

<h3>The background color of this page has been set programmatically. Open View|Source menu to see the source code.</h3></body></html>Il codice HTML risultante è il seguente:

<html><head><title>Pro ASP.NET (Ch 01)</title></head><body id=”TheBody” style=”background-color:lightblue;”>

<form method=”post” action=”Body.aspx” id=”Form1”> <div> <input type=”hidden” name=”__VIEWSTATE” value=”/wEPD… RVC+” /> </div>

18 Parte I Realizzare una pagina ASP .NET

<h3>The background color of this page has been set programmatically. Open View|Source menu to see the source code.</h3></form></body></html>

Analogamente, si può impostare uno qualsiasi degli attributi del tag <body>, decidendo

così da programma, ad esempio, quale stylesheet o immagine di sfondo utilizzare. Per

creare gli attributi del tag si utilizza la collection Attributes di HtmlGenericControl. Per

impostare il valore inner text di un tag si utilizza la proprietà InnerText.

TheBody.Attributes[“Background”] = “/proaspnet20/images/body.gif”;

Discuteremo in maggior dettaglio l’interfaccia di programmazione della classe

HtmlGenericControl nel Capitolo 4.

[Nota] In ASP.NET 2.0, si può accedere al contenuto del tag <head> da programma fi nché è contrassegnato con l’attributo runat. La classe Page espone un gruppo di metodi e proprietà ad-hoc che esploreremo nel Capitolo 3.

Tag incogniti

Nel caso di tag incogniti, cioè tag che non sono né predefiniti nello schema corrente

né definiti dall’utente, il runtime ASP.NET può comportarsi in due modi differenti. Se

il tag non contiene informazioni sul namespace, ASP.NET lo tratta come un generico

controllo HTML. Il namespace vuoto, infatti, viene valutato in namespace HTML,

inducendo perciò il runtime ASP.NET a credere che il tag sia realmente un elemento

HTML. Non viene generata nessuna eccezione, e il testo di markup viene generato sul

server. Ad esempio, consideriamo la seguente pagina ASP.NET:

<%@ Page Language=”C#” %><script runat=”server”>void Page_Load(object sender, EventArgs e)

{

dinoe.Attributes[“FavoriteFood”] = “T-bone steak”;

}

</script><html><head><title>Pro ASP.NET (Ch 01)</title></head><body><form runat=”server”> <Person id=”dinoe” runat=”server” />

Click the <b>View|Source</b> menu item...</form></body></html>

Il tag <Person> viene comunque processato come se fosse un ordinario tag HTML,

e viene aggiunto l’attributo FavoriteFood. La Figura 1-4 mostra qual è effettivamente

il codice HTML di questa pagina. Nell’esempio precedente, il tipo dell’oggetto dinoe è

HtmlGenericControl.

Capitolo 1 Il modello di programmazione ASP .NET 19

Figura 1-4 ASP.NET processa anche tag custom privi di namespace, mappandoli alla classe HtmlGenericControl.

Se il tag contiene informazioni sul namespace, è accettabile finché il namespace

è <asp> o è un namespace esplicitamente associato al nome del tag utilizzando una

direttiva @Register. Se il namespace è incognito, si verifica un errore di compilazione.

Controlli Server ASP.NET

Sostanzialmente, esistono due famiglie di controlli server ASP.NET. Si tratta dei controlli

server HTML e dei controlli server Web. System.Web.UI.HtmlControls è il namespace dei

controlli server HTML. System.Web.UI.WebControls raggruppa tutti i controlli server Web.

Controlli Server HTML

I controlli server HTML sono classi che rappresentano un tag HTML standard

supportato da gran parte dei browser. L’insieme delle proprietà di un controllo

server HTML corrisponde a un insieme utilizzato comunemente di attributi del tag

corrispondente. Il controllo espone proprietà come InnerText, InnerHtml, Style e

Value più alcune collection come Attributes. Ogni volta che nel sorgente della pagina

viene trovato il corrispondente tag HTML contrassegnato con runat=“server” vengono

create automaticamente dal runtime ASP.NET istanze di controlli server HTML.

Come già detto, l’insieme disponibile di controlli server HTML non copre tutti i

possibili tag HTML di una determinata versione dello schema HTML. Solo i tag più

comunemente utilizzati hanno trovato posto nel namespace System.Web.UI.HtmlCont

rols. Tag come <iframe>, <frameset>, <body> e <hn> sono stati lasciati fuori alla

pari di tag meno frequentemente utilizzati come <fieldset>, <marquee> e <pre>.

L’assenza di un controllo server specializzato, tuttavia, non limita la propria potenza

di programmazione quando si tratta di utilizzare e configurare questi tag sul server.

Bisogna solo utilizzare una interfaccia di programmazione più generica, la classe

HtmlGenericControl, che abbiamo descritto brevemente in questo paragrafo.

20 Parte I Realizzare una pagina ASP .NET

Controlli Server Web

I controlli server Web sono controlli con più caratteristiche dei controlli server

HTML. I controlli server Web comprendono non solo i controlli di input come pulsanti

e textbox, ma anche controlli di uso particolare come un calendario, un ad rotator, un

elenco a discesa, un treeview e una griglia dati. I controlli server Web comprendono

anche componenti che assomigliano molto ad alcuni controlli server HTML. I controlli

server Web, tuttavia, sono più astratti dei corrispondenti controlli server HTML nel

senso che il relativo modello a oggetti non riflette necessariamente la sintassi HTML.

Ad esempio, confrontiamo il controllo testo HTML server e il controllo server Web

TextBox. Il controllo testo HTML server ha il seguente markup:

<input runat=”server” id=”FirstName” type=”text” value=”Dino” />

Il controllo server Web TextBox ha il seguente markup:

<asp:textbox runat=”server” id=”FirstName” text=”Dino” />

Entrambi i controlli generano lo stesso codice di markup HTML. Tuttavia,

l’interfaccia di programmazione del controllo server testo HTML corrisponde

moltissimo a quella del tag HTML <input>, mentre metodi e proprietà del

controllo server Web TextBox sono denominati in un modo più astratto. Ad

esempio, per impostare il contenuto di un controllo server testo HTML si deve

utilizzare la proprietà Value poiché Value è il nome corrispondente dell’attributo

HTML. Se si lavora con il controllo server Web TextBox, si deve ricorrere a Text.

Salvo pochissime eccezioni (di cui discuterò nel Capitolo 3), l’utilizzo dei controlli

server HTML o dei controlli server Web per rappresentare elementi HTML è solo

una questione di preferenza, di facilità di sviluppo e di manutenzione.

Lo stack di sviluppo ASP.NET

Al livello più alto di astrazione, lo sviluppo di una applicazione ASP.NET

attraversa due fasi: creazione delle pagine e configurazione runtime. Si realizzano le

pagine che formano l’applicazione, si implementano i relativi prerequisiti d’utente,

e quindi si esegue una ottimizzazione fine del circostante ambiente di runtime per

far sì che serva le pagine in modo efficace e sicuro. Come mostra la Figura 1-2, il

modello di componente ASP.NET è la base di tutte le applicazioni ASP.NET e dei

relativi blocchi costituenti. Tenendo presente la Figura 1-2, esaminiamo i vari strati

logici per vedere cosa contengono e perché.

Lo strato di Presentazione

Una pagina ASP.NET è costituita da controlli, testo e markup. Quando il codice

sorgente viene trasformato in una istanza attiva di una classe di pagina, il runtime

ASP.NET non fa alcuna ulteriore distinzione tra testo letterale, markup e controlli

server: tutto è un controllo, compreso il testo letterale e i caratteri carriage-return. In

fase di esecuzione, qualsiasi pagina ASP.NET è un semplice grafo di controlli.

Capitolo 1 Il modello di programmazione ASP .NET 21

Controlli sofisticati

La sofisticata programmazione di ASP.NET scaturisce dall’ampia libreria di controlli

server che abbracciano i task fondamentali dell’interazione HTML, ad esempio,

raccogliendo il testo attraverso i tag input, ma anche funzionalità più avanzate come la

visualizzazione di dati basata su una griglia. Il set nativo dei controlli è abbastanza grande da

permettere di soddisfare virtualmente qualsiasi insieme di prerequisiti. Inoltre, la recente

versione di ASP.NET aggiunge alcuni nuovi controlli sofisticati per portare la produttività

dello sviluppatore in prossimità del massimo livello possibile. In ASP.NET 2.0, si trovano

controlli per creare wizard Web, viste collassabili di dati gerarchici, avanzati report di dati,

form comunemente utilizzati, data binding dichiarativo, menu, navigazione del sito. Si trova

anche una sottile API per creare pagine in stile portale. La disponibilità di controlli sofisticati

significa una riduzione del tempo di sviluppo e degli errori di codifica, più “best practice”

implementate e più funzionalità avanzate a disposizione degli utenti finali. Tratteremo

specificamente i controlli nel Capitolo 4, nel Capitolo 6 e in seguito nel Capitolo 10.

Controlli custom

I controlli principali di ASP.NET forniscono un insieme completo di tool per

realizzare funzionalità Web. L’insieme standard di controlli può essere esteso

e migliorato aggiungendo dei controlli personalizzati. Il sottostante modello di

componente ASP.NET semplifica notevolmente il compito applicando i principi e le

regole comuni della programmazione object-oriented.

Si possono costruire nuovi controlli migliorando un controllo esistente o

aggregando assieme due o più controlli per formarne uno nuovo. ASP.NET 1.x è dotato

di un piccolo set di classi di base su cui implementare controlli del tutto nuovi. Questo

set di classi è stato esteso in ASP.NET 2.0, in particolare per semplificare lo sviluppo di

nuovi controlli data-bound.

Rendering adattivo

A partire dalla versione 2.0, ASP.NET mette a disposizione una nuova architettura

di control adapter che permette a qualsiasi controllo server di creare renderizzazioni

alternative per una varietà di browser. Si noti, tuttavia, che il nuovo modello di adapter

ASP.NET 2.0 non si applica ai controlli mobile. I controlli mobile sono una particolare

famiglia di controlli Web progettati per realizzare applicazioni per dispositivi mobile.

I controlli mobile ASP.NET 2.0 utilizzano ancora il vecchio modello di adapter,

disponibile sin da ASP.NET 1.1, per controlli che derivano da MobileControl e sono

ospitati su pagine che derivano da MobilePage. In breve, se si deve scrivere una

applicazione mobile con ASP.NET 2.0, si devono utilizzare i controlli mobile, come si

sarebbe fatto con ASP.NET 1.1.

Pertanto qual è il valore aggiunto del nuovo modello di adapter? Con questa

forma di rendering adattivo, si possono scrivere control adapter per personalizzare

i controlli server per singoli browser. Ad esempio, si può scrivere un control

adapter per generare un differente markup HTML per il controllo Calendar per un

determinato browser desktop.

22 Parte I Realizzare una pagina ASP .NET

Il framework della pagina

Qualsiasi pagina ASP.NET funziona come istanza di una classe che ha origine dalla

classe Page. La classe Page è il punto terminale di una pipeline di moduli che processa

qualsiasi richiesta HTTP. I vari componenti di sistema che operano sulla richiesta

originale costruiscono passo per passo tutte le informazioni necessarie a localizzare

l’oggetto pagina per generare il markup. Il modello a oggetti della pagina presenta

diverse caratteristiche e funzionalità che potrebbero essere raggruppate in termini di

eventi, scripting, personalizzazione, stile e prototipizzazione.

Eventi di pagina

Il ciclo di vita di una pagina nel runtime ASP.NET è contrassegnato da una serie di

eventi. Collegando il proprio codice a questi eventi, gli sviluppatori possono modificare

dinamicamente l’output di pagina e lo stato dei controlli di cui si compone. In ASP.NET

1.x, una pagina scatena eventi come Init, Load, PreRender e Unload che sottolineano i

momenti principali della vita della pagina. ASP.NET 2.0 aggiunge parecchi nuovi eventi

per permettere di seguire più da vicino e con precisione l’elaborazione della richiesta. In

particolare, si trovano nuovi eventi per segnalare l’inizio e la fine della fase di inizializzazione

e caricamento. Il ciclo di vita di pagina verrà esaminato in modo esaustivo nel Capitolo 3.

Scripting di pagina

Il modello a oggetti di scripting di pagina permette agli sviluppatori di gestire il codice di

scripting, e ai campi nascosti di essere iniettati nelle pagine client. Questo modello a oggetti

genera codice JavaScript utilizzato per tenere assieme gli elementi HTML generati dai controlli

server, fornendo così caratteristiche altrimenti impossibili da programmare sul server. Ad

esempio, in questo modo si può impostare il focus di input ad un particolare controllo quando

la pagina viene visualizzata nel browser client. Le pagine ASP.NET possono essere architettate

per inoltrare le invocazioni client a metodi server senza eseguire un completo postback e

successivamente eseguire il refresh dell’intera pagina visualizzata. Questa sorta di engine di

scripting remoto viene implementato attraverso un meccanismo di callback che offre un chiaro

vantaggio agli sviluppatori. Quando si utilizzano gli script callback, i risultati dell’esecuzione di

un metodo lato server vengono passati direttamente a una funzione JavaScript che può quindi

aggiornare l’interfaccia utente attraverso Dynamic HTML. Un roundtrip si verifica ancora, ma la

pagina non viene del tutto completamente sottoposta a un refresh. Gli script callback, tuttavia,

non rappresentano l’unica buona notizia. Il posting cross-page è una ulteriore caratteristica

che la comunità degli sviluppatori ASP.NET ha richiesto a gran voce. Questa caratteristica

permette il posting del contenuto di un form a una ulteriore pagina. Suona come insegnare

dei vecchi trucchi a un nuovo cane? Forse. Come già detto prima in questo capitolo, uno degli

aspetti più caratteristici di ASP.NET è che ciascuna pagina contiene un solo tag <form>, che

continuamente esegue il post a sé stesso. Questo è il modo in cui ASP.NET è stato progettato, e

produce diversi vantaggi. Nelle precedenti versioni di ASP.NET, il posting cross-page potrebbe

essere implementato allo stesso modo di ASP classico, ossia, eseguire il posting attraverso un

puro <form> HTML non contrassegnato con l’attributo runat. Questo metodo funziona

bene, ma vi lascia fuori dal mondo object-oriented e a tipizzazione forte di ASP.NET. Il posting

cross-page, come è implementato in ASP.NET 2.0, colma il gap.

Capitolo 1 Il modello di programmazione ASP .NET 23

Personalizzazione di pagina

In ASP.NET 2.0, si possono memorizzare e recuperare informazioni e preferenze spe-

cifiche all’utente senza l’onere di dover scrivere il codice di infrastruttura. L’applicazione

definisce il proprio modello di dati personalizzati, e il runtime ASP.NET si occupa del resto

scandendo e compilando questo modello in una classe. Ciascun membro dei dati della clas-

se personalizzata corrisponde a un blocco di informazioni specifiche all’utente corrente. Il

caricamento e il salvataggio dei dati personalizzati è del tutto trasparente agli utenti finali e

non richiede neanche all’autore della pagina di dover conoscere troppo sull’infrastruttura

interna. Le informazioni personalizzate dell’utente sono disponibili all’autore della pagina

attraverso una proprietà di pagina. Ciascuna pagina può consumare le informazioni prece-

dentemente salvate e salvare nuove informazioni per ulteriori richieste.

Stilizzazione di pagina

In modo molto simile ai temi di Microsoft Windows XP, i temi ASP.NET assegnano un

insieme di stili e di attributi visuali agli elementi personalizzabili del sito. Questi elementi

comprendono le proprietà dei controlli, i fogli stile di pagina, le immagini e i template della

pagina. Un tema è l’unione di tutti gli stili visuali di tutti gli elementi personalizzabili delle pa-

gine: una sorta di file super-CSS (Cascading Style Sheet). Un tema è identificato dal nome ed

è costituito da file CSS, immagini e dai cosiddetti “control skin”. Un control skin è un file di

testo che contiene le dichiarazioni di default del controllo in cui vengono impostate le pro-

prietà visuali del controllo. Con questa caratteristica abilitata, se lo sviluppatore aggiunge, ad

esempio, un controllo DataGrid a una pagina, il controllo viene renderizzato con l’aspetto

di default definito nel tema. I temi rappresentano un’importante nuova caratteristica, poiché

permettono di modifica il look&feel delle pagine in un unico colpo e, aspetto forse ancor più

importante, di dare a tutte le pagine un aspetto consistente.

Prototipizzazione di pagina

Quasi tutti gli odierni siti Web contengono pagine con un layout simile. Per alcuni siti, il

layout è semplicemente un header e un footer; altri siti possono contenere sofisticati menu

di navigazione e vari “gadget” che racchiudono il contenuto. In ASP.NET 1.x, l’approccio

raccomandato per gli sviluppatori era di racchiudere questi blocchi di UI in controlli utente

e referenziarli in ciascuna pagina di contenuto. Come si può immaginare, questo modello

funziona abbastanza bene quando il sito contiene solo alcune pagine; sfortunatamente,

diventa ingestibile se il sito contiene centinaia di pagine. Un approccio basato sui controlli

utente presenta diversi problemi importanti per siti ricchi di contenuto. Per dirne uno,

si deve replicare il codice nelle pagine dei contenuti per referenziare i controlli utente.

Inoltre, l’applicazione di nuovi template richiede che lo sviluppatore ritocchi ogni pagina.

Infine, gli elementi HTML presenti nell’area dei contenuti sono probabilmente divisi da

controlli utente. In ASP.NET 2.0, la prototipizzazione di pagina è notevolmente migliora-

ta grazie alle pagine master. Gli sviluppatori che lavorano a siti Web in cui molte pagine

condividono una parte di layout e di funzionalità, invece di aggiungere le informazioni di

layout a ciascuna pagina o di separare il layout tra diversi controlli utente, ora possono

creare qualsiasi funzionalità condivisa in un file master. Basandosi sul file master condiviso,

gli sviluppatori possono creare qualsiasi numero di pagine di contenuto dall’aspetto simile

24 Parte I Realizzare una pagina ASP .NET

semplicemente referenziando la pagina master attraverso un nuovo attributo. Tratteremo

le pagine master nel Capitolo 6.

L’ambiente di runtime HTTP

Il processo attraverso cui una richiesta Web diventa semplice testo HTML per il browser

non è molto differente in ASP.NET 2.0 rispetto a ASP.NET 1.1. La richiesta viene selezionata da

IIS, a partire da un identity token, e passata all’estensione ASP.NET ISAPI (aspnet_isapi.dll), il

punto di ingresso di qualsiasi elaborazione inerente a ASP.NET. Questo è il processo generale,

ma alcuni importanti dettagli dipendono dalla versione sottostante di IIS e dal modello di

processo in uso. Il modello di processo è la sequenza di operazioni necessarie a elaborare

una richiesta. Quando il runtime ASP.NET viene eseguito su IIS 5.x, il modello di processo si

basa su un processo worker separato, denominato aspnet_wp.exe. Questo processo Microsoft

Win32, riceve il controllo direttamente da IIS attraverso l’estensione ASP.NET ISAPI ospitata.

All’estensione viene passata qualsiasi richiesta di risorse ASP.NET, che la consegna al processo

worker. Il processo worker carica il Common Language Runtime (CLR) e avvia la pipeline di

oggetti managed che trasforma la richiesta originale da un payload HTTP in una pagina completa

per il browser. Il modulo aspnet_isapi e il processo worker implementano caratteristiche

avanzate come il process recycling, il caching dell’output di pagina, il monitoraggio della

memoria, e il pooling dei thread. Ciascuna applicazione Web viene eseguita in un AppDomain

distinto all’interno del processo worker. Per default, il processo worker è in esecuzione sotto

un account limitato, scarsamente privilegiato, denominato ASPNET.

[Nota] Nel CLR, un application domain (AppDomain) fornisce i limiti di isolamento, di scaricamento e di sicurezza per l’esecuzione di codice managed. Un AppDomain è un tipo di processo lightweight, specifi co del CLR, in cui più assembly vengono caricati e protetti per eseguire il codice. Più AppDomain possono essere in esecuzione in un singolo processo di CPU. Non vi è una correlazione uno a uno tra AppDomain e thread. Diversi thread possono appartenere a un singolo AppDomain, e mentre un determinato thread non è confi nato a un singolo application domain, in un determinato momento, un thread viene eseguito in un singolo AppDomain.

Quando ASP.NET viene eseguito sotto IIS 6.0, il modello di processo di default è

differente e non viene utilizzato il processo aspnet_wp.exe. Il processo worker utilizzato

è il processo worker standard IIS 6.0 (w3wp.exe). Questo analizza l’URL della richiesta

e carica una specifica estensione ISAPI. Ad esempio, carica aspnet_isapi.dll per richieste

inerenti a ASP.NET. Nel modello di processo IIS 6.0, l’estensione aspnet_isapi è responsabile

del caricamento del CLR e dell’avvio della pipeline HTTP. Una volta nella pipeline HTTP

ASP.NET, la richiesta passa attraverso vari componenti, di sistema e definiti dall’utente, che

operano su di essa finché non viene trovata e istanziata con esito positivo una classe di pagina

valida. Gli sviluppatori possono modificare e adattare l’ambiente di run-time entro certi

limiti. Ciò può accadere in tre modi: modificando l’elenco dei moduli HTTP installati, i file di

configurazione, i provider di stato e di personalizzazione, e altri servizi di applicazione.

Capitolo 1 Il modello di programmazione ASP .NET 25

Moduli HTTP di sistema

I moduli HTTP rappresentano l’equivalente ASP.NET dei filtri ISAPI. Un modulo

HTTP è una classe del .NET Framework che implementa una particolare interfaccia.

Tutte le applicazioni ASP.NET derivano da alcuni moduli HTTP di sistema come

definiti nel file machine.config. I moduli preinstallati forniscono caratteristiche come

l’autenticazione, l’autorizzazione e i servizi inerenti alla sessione. In termini generali,

un modulo HTTP può preprocessare e postprocessare una richiesta, e intercetta e

gestisce sia gli eventi di sistema sia gli eventi generati da altri moduli.

La buona notizia è che si possono scrivere e registrare i propri moduli HTTP,

collegarli nella pipeline di runtime ASP.NET, gestire gli eventi di sistema e scatenare dei

propri eventi. Inoltre, si può adattare a livello di applicazione l’elenco dei moduli HTTP

di default. Si possono aggiungere moduli custom e rimuovere quelli non necessari.

Configurazione dell’applicazione

Il comportamento delle applicazioni ASP.NET è soggetto a una varietà di parametri;

alcuni sono impostazioni a livello di sistema, alcuni dipendono dalle caratteristiche

dell’applicazione. L’insieme comune dei parametri di sistema viene definito nel file

machine.config. Questo file contiene i valori di default e quelli specifici alla macchina

di tutte le impostazioni supportate. Le impostazioni di macchina di solito vengono

controllate dall’amministratore di sistema, e alle applicazioni non dovrebbe essere

concesso l’accesso in scrittura al file machine.config. Il file machine.config è posizionato

all’esterno dello spazio Web dell’applicazione e, in quanto tale, non può essere raggiunto

anche se un intruso riesce a iniettare del codice subdolo nel sistema.

Qualsiasi applicazione può ridefinire gran parte dei valori di default memorizzati

nel file machine.config creando uno o più file web.config specifici dell’applicazione.

Come minimo, una applicazione crea un file web.config nella propria cartella root. Il file

web.config è un subset del file machine.config, scritto in base allo stesso schema XML.

L’obiettivo del web.config è ridefinire alcune delle impostazioni di default. Attenzione,

tuttavia, che non tutte le impostazioni definite nel machine.config possono essere

ridefinite in un file di configurazione figlio. In particolare, le informazioni sul modello

di processo ASP.NET possono essere definite solo a livello di macchina utilizzando

il file machine.config. Se l’applicazione contiene directory figlie, può definire un file

web.config per ciascuna cartella. L’ambito di visibilità di ciascun file di configurazione

viene determinato in una modalità gerarchica, top-down. Le impostazioni valide per una

pagina vengono determinate dalla somma delle modifiche dei vari file web.config trovati

strada facendo applicati alla configurazione originale di macchina. Un file web.config

può estendere, ridurre e ridefinire qualsiasi tipo di impostazioni definite a un livello

superiore, compreso il livello macchina. Se non esiste alcun file di configurazione in una

cartella dell’applicazione, vengono applicate le impostazioni valide al livello superiore.

Servizi di applicazione

L’autenticazione, la gestione dello stato, e il caching sono tutti esempi di servizi

essenziali che l’ambiente di runtime ASP.NET fornisce alle applicazioni in esecuzione.

Con ASP.NET 2.0, sono stati aggiunti all’elenco altri servizi, compresa l’amministrazione,

26 Parte I Realizzare una pagina ASP .NET

la gestione delle membership, la gestione dei ruoli e la personalizzazione, come

mostrato nella Figura 1-5.

Figura 1-5 Una vista più dettagliata dello stack di sviluppo ASP.NET. La freccia indica la tipica prospettiva top-down dell’applicazione, andando verso il basso dalla interfaccia utente ai servizi di sistema.

Gran parte dei servizi di applicazione devono persistere e recuperare alcuni dati

per scopi interni. Nel farlo, un servizio sceglie un modello di dati e un supporto di

memorizzazione, e ottiene i dati attraverso una particolare sequenza di passi. Le

applicazioni basate su questi servizi vengono vincolate per progetto a utilizzare queste

impostazioni, che di solito comprendono uno schema dati prefissato, un supporto

di memorizzazione predefinito, e un comportamento cablato nel codice. Cosa

accade se non si gradiscono o non si vogliono queste restrizioni? La configurazione

a run-time, ottenuta attraverso i file machine.config e web.config, aggiunge un po’

di flessibilità in più al proprio codice. Tuttavia, la configurazione a run-time non

fornisce una soluzione definitiva abbastanza flessibile da permettere una completa

personalizzazione del servizio tale da renderla estensibile e lineare da implementare.

Una soluzione più definitiva viene fornita da ASP.NET 2.0, che formalizza e integra nel

complessivo framework di classi un design pattern che è stato in origine sviluppato e

utilizzato in diversi ASP.NET Starter Kit. Noto come modello di provider, questo pattern

definisce una API comune per una varietà di operazioni, ciascuna nota come provider.

Al contempo, l’interfaccia del provider contiene diversi hook perché gli sviluppatori

possano avere un controllo completo del comportamento interno dell’API, dello

schema dati utilizzato e del supporto di memorizzazione.

Capitolo 1 Il modello di programmazione ASP .NET 27

[Importante] Il modello di provider è uno degli aspetti più importanti e critici di ASP.NET. Una buona comprensione di questo pattern è cruciale per eseguire un effi cace design e per l’implementazione di applicazioni di punta. Il modello di provider viene formalizzato in ASP.NET 2.0, ma è semplicemente l’implementazione di un design pattern. Come tale, è del tutto slegato come concetto da qualsiasi piattaforma e framework. Pertanto una volta compresa l’idea di base, si può iniziare a utilizzarla in qualsiasi applicazione, anche al di là del contesto ASP.NET.

Il modello di provider ASP.NETVi è un ben noto design pattern dietro il modello di provider ASP.NET: il pattern

strategy. Per definizione, il pattern strategy indica un comportamento previsto (ad

es., l’ordinamento) che può essere implementato attraverso una varietà di algoritmi

interscambiabili (ad es., Quicksort, Mergesort). Ciascuna applicazione seleziona quindi

l’algoritmo più idoneo, pur mantenendo intatto il comportamento pubblico osservabile

e l’API di programmazione. La caratteristica più considerevole del pattern strategy è che

fornisce a un oggetto, o a un intero sottosistema, un modo per esporre i propri dettagli

in modo che un client possa scollegare l’implementazione di default di una determinata

caratteristica e collegarne una propria. È esattamente ciò che accade in ASP.NET per molti

servizi, tra cui membership, ruoli, gestione dello stato, personalizzazione, navigazione del

sito. Il modello di provider ASP.NET è l’implementazione ASP.NET del pattern strategy.

La motivazione alla base del modello di provider

Il modello di provider non è una caratteristica dell’applicazione che gli utenti finali

possono vedere con i propri occhi. Di per sé, non fa sì che una applicazione mostri un

contenuto più sofisticato, che venga eseguita più velocemente o che sia più responsiva.

Il modello di provider è una caratteristica infrastrutturale che migliora l’architettura di

una applicazione abilitando gli sviluppatori e gli architetti a operare dietro le quinte di

alcuni componenti di sistema. Al contempo, abilita gli sviluppatori a realizzare nuovi

componenti che espongono degli hook, a cui i client possono collegarsi e personalizzare

comportamento e impostazioni. L’implementazione del pattern strategy non trasforma

una applicazione in un progetto open-source, permettendo a chiunque di modificare

qualcosa. Significa semplicemente che si ha un semplice, raffinato e efficace pattern per

rendere certe parti della propria applicazione personalizzabili dai client. Al contempo,

l’implementazione ASP.NET del pattern (il modello di provider), vi rende in grado di

personalizzare certe parti dell’ambiente di runtime ASP.NET attraverso classi speciali

denominate provider dalle quali si può derivarne una propria.

Esemplificazione del modello di provider

Per vedere un esempio del modello di provider e dei relativi vantaggi principali,

osserviamo la Figura 1-6. La figura riassume il classico schema per l’autenticazione di

un utente. I blocchi del diagramma seguono strettamente il flusso delle operazioni in

ASP.NET 1.1.

28 Parte I Realizzare una pagina ASP .NET

Figura 1-6 Il classico schema di membership delle applicazioni ASP.NET 1.1.

All’utente che tenta di connettersi a una pagina protetta viene mostrata una pagina di

login e viene invitato a digitare le credenziali. Successivamente, nome e password vengono

passate a una funzione, che è in definitiva responsabile della validazione dell’utente.

ASP.NET 1.x può verificare automaticamente gli utenti rispetto agli account Windows o

a un elenco di nomi presenti nel file web.config. Nessuno di questi approcci funziona

bene in una applicazione Web realistica; in gran parte dei casi, gli sviluppatori finiscono

per scrivere un blocco di codice custom per validare le credenziali rispetto a un proprio

data source artigianale. Lo schema e il supporto di memorizzazione del data source sono

prefissati e determinati dallo sviluppatore. Analogamente, l’algoritmo impiegato per validare

le credenziali viene vincolato dal progetto. C’è qualcosa di errato in questa soluzione? Non

necessariamente. Funziona bene, permette di controllare tutto, e può essere adattata per

funzionare in altre applicazioni. L’ostacolo è che non vi è alcun pattern ben definito che

emerge da questa soluzione. Certo, si può portarla da una applicazione a un’altra, ma

complessivamente la soluzione è correlata al pattern adapter quasi come il cut&paste è

correlato all’ereditarietà nell’approccio object-oriented. Consideriamo brevemente un

ulteriore scenario: la gestione dello stato della sessione. In ASP.NET 1.x, si può memorizzare

lo stato della sessione in un processo separato dall’applicazione in esecuzione: può essere

SQL Server o un servizio Windows (il server di stato ASP.NET). Così facendo, tuttavia, si è

vincolati a utilizzare lo schema dati che ASP.NET cabla per vostro conto. Inoltre, si immagini

di non essere un utente di SQL Server. In questo caso, o si abbandona l’idea di memorizzare

lo stato di sessione in un database o si acquista un set di licenze per SQL Server. Infine, non

c’è niente che si può fare sul comportamento intrinseco del modulo di sessione ASP.NET. Se

non si gradisce il modo in cui, ad esempio, serializza i dati nello storage out-of-process, non

si può modificarlo. Prendere o lasciare: non vi è alcuna scelta intermedia.

Siete in grado di vedere il quadro complessivo? Vi sono moduli in ASP.NET che vi

costringono a prendere (o lasciare) un determinato schema di dati, un determinato

supporto di memorizzazione, un determinato comportamento intrinseco. Il più che si

Capitolo 1 Il modello di programmazione ASP .NET 29

può fare è (talvolta) evitare l’utilizzo di questi moduli e scriverne uno proprio da zero,

come abbiamo delineato nell’esempio sulla membership. Tuttavia, implementare una

propria sostituzione non è necessariamente una mossa astuta. Ci si trova con un sistema

proprietario e dipendente dall’applicazione che non è automaticamente portabile da una

applicazione a un’altra. Inoltre, se si assume del nuovo personale, è necessario formarlo

prima che si abitui a utilizzare la vostra API. Infine, si deve profondere un notevole impegno

per rendere una tale API proprietaria abbastanza generale da essere riusabile ed estensibile

in una varietà di contesti. (Altrimenti, si dovrà reinventare ogni volta la ruota). In che modo

il modello di provider è una soluzione migliore? In primo luogo, fornisce un’interfaccia di

programmazione ben documentata e comune per eseguire dei compiti comuni. Inoltre, si

ottiene la capacità di controllare completamente l’attività interna e la logica di accesso ai dati

di ciascuna API che ricade sotto questo ombrello. Alla fin fine, in ASP.NET 1.1 spesso non si

ha alcuna altra scelta se non scrivere una propria API per disporre di certe funzioni nel modo

in cui si vuole. In ASP.NET 2.0, il modello di provider offre una alternativa molto migliore.

Tanto migliore che è praticamente un crimine non utilizzarla.

Figura 1-7 L’esempio di membership rivisitato per utilizzare il modello di provider di ASP.NET 2.0.

La Figura 1-7 rivisita la Figura 1-6 alla luce del modello di provider. ASP.NET 2.0

rende disponibile un gruppo di metodi statici di una classe globale, Membership.

(Tratteremo la API di membership in maggior dettaglio nel Capitolo 15). A livello di

applicazione, si invoca sempre lo stesso metodo per eseguire la stessa operazione (ad

esempio, validazione delle credenziali utente, creazione di nuovi utenti, modifica delle

password). Sotto questa API comune, tuttavia, si può collegare il proprio provider per

svolgere il lavoro nel modo voluto. Scrivere un nuovo provider è facile come derivare

una nuova classe da una classe base nota e ridefinire alcuni metodi ben noti. La selezione

del provider corrente per un determinato compito avviene nel file di configurazione.

30 Parte I Realizzare una pagina ASP .NET

Vantaggi del modello di provider

Nella implementazione ASP.NET, il pattern strategy comporta due principali vantag-

gi: un’estensiva personalizzazione dell’ambiente run-time dell’applicazione e la riusa-

bilità del codice. Diverse aree in ASP.NET vengono interessate dal modello di provider.

Si possono scrivere provider per gestire membership e ruoli dell’utente, persistere lo

stato della sessione, gestire i profili utente attraverso la personalizzazione, e caricare

informazioni sulla mappa del sito da diverse fonti. Ad esempio, scrivendo un provider si

può modificare lo schema dei dati utilizzato per persistere le credenziali, memorizzare

questi dati in un database Oracle o DB2, e memorizzare le password in formato hash

piuttosto che in testo in chiaro. Questo livello di personalizzazione dei componenti di

sistema è del tutto nuovo, e spalanca un nuovo mondo di possibilità per gli sviluppatori

di applicazioni. Al contempo, fornisce un eccellente punto di partenza per la scrittura di

nuovi provider ed anche per estendere il modello ai propri componenti. Se si osserva

ASP.NET 2.0 dalla prospettiva delle applicazioni esistenti, il modello di provider ottiene

anche più rilevanza tecnica poiché è la chiave per il riuso del codice e per una suc-

cessiva conservazione degli investimenti in termini di programmazione e di tempo di

sviluppo. Come abbiamo evidenziato, un sistema di membership realistico in ASP.NET

1.1 richiede di dover fornire una propria API quando si tratta di validazione e gestione

dell’utente. Cosa si dovrebbe fare dopo aver deciso di eseguire l’upgrade a ASP.NET

2.0? Si deve scartare tutto questo codice per abbracciare la nuova impressionante API

di membership di ASP.NET 2.0? O si farebbe meglio a restare incollati all’antiquata e

proprietaria API di membership? Il modello di provider fornisce la risposta (ed è, effetti-

vamente, una buona risposta) grazie alla straordinaria capacità di scambiare l’algoritmo

sottostante pur preservando il comportamento complessivo. Tuttavia, questa capacità

di per sé non sarebbe sufficiente. Si deve anche adattare il proprio codice esistente per

renderlo collegabile al nuovo ambiente runtime. In questo caso, un ulteriore pattern

popolare viene in soccorso: il pattern adapter. L’intento dichiarato del pattern adapter

è convertire una classe A in una interfaccia B che un client C comprende. Si racchiu-

de il codice esistente in una nuova classe provider che può essere collegata in modo

trasparente nel framework ASP.NET 2.0 esistente. Si modifica l’implementazione sot-

tostante della API di membership, e si utilizza il proprio schema e il proprio supporto

di memorizzazione pur lasciando intatta l’interfaccia di massimo livello. E, aspetto più

importante, si può riusare completamente il proprio codice.

Una rapida panoramica all’implementazione di ASP.NET

L’implementazione del modello di provider di ASP.NET consiste di tre elemen-

ti distinti: la classe provider, lo strato di configurazione e lo strato di storage. La

classe provider è il componente che si collega nel framework esistente per fornire

una funzionalità desiderata nel modo voluto. Lo strato di configurazione fornisce

informazioni utilizzate per identificare e istanziare il provider effettivo. Lo strato di

storage è il supporto fisico in cui sono memorizzati i dati. In base alla particolare

caratteristica, può essere Active Directory, una tabella Oracle o SQL Server, un file

XML, o qualcos’altro.

Capitolo 1 Il modello di programmazione ASP .NET 31

La classe Provider

Una classe provider implementa un’interfaccia nota ai suoi client. In questo modo, la

classe fornisce ai client la funzionalità promessa da quella interfaccia. Ai client non è richiesto

conoscere ogni aspetto sui dettagli di implementazione dell’interfaccia. Questa opacità del

codice permette la magia di far sì che del codice guidi dell’altro codice di cui non è neanche

consapevole. Nel modello di provider ASP.NET, la sola variazione rispetto alla definizione

originale del pattern strategy è che al posto delle interfacce vengono utilizzate le classi base.

In ASP.NET, una classe provider non può essere semplicemente qualsiasi classe che imple-

menta una determinata interfaccia. In effetti, è vero piuttosto il contrario. Una classe provider

deve derivare da una classe base ben nota. Esiste una classe base per ciascun tipo supportato

di provider. La classe base definisce l’interfaccia di programmazione del provider attraverso

un gruppo di metodi astratti. Tutte le classi base provider derivano da una classe comune

denominata ProviderBase. Questa classe base fornisce un metodo overridable, Initialize,

attraverso cui l’ambiente di run-time passa qualsiasi impostazione pertinente dai file di confi-

gurazione. La Figura 1-8 riassume la gerarchia delle classi provider di membership.

Figura 1-8 La gerarchia delle classi provider di membership.

Interfacce vs. classi base

Alzi la mano chi, in qualità di sviluppatore, non è mai stato coinvolto in ore e ore di

dibattito sull’argomento interfacce versus classi base. È una discussione che raramente

giunge a un termine e lascia sempre chi proviene da fazioni differenti fermamente ag-

grappati alle rispettive posizioni. Si dovrebbero utilizzare le interfacce, o sono migliori

le classi base? Su quali considerazioni si basa la vostra risposta? Consideriamo, innan-

32 Parte I Realizzare una pagina ASP .NET

zitutto, la seguente realtà di fatto. Le versioni pre-beta di ASP.NET 2.0 implementavano il

modello di provider alla lettera rispetto alla definizione del pattern strategy: ossia, attraverso

interfacce. Al momento della Beta 1, le interfacce furono sostituite con classi base, e così è

nella versione rilasciata. Il team ASP.NET è giunto apparentemente a una conclusione sul

problema, o no? Un’interfaccia è una collezione di metodi logicamente correlati che contie-

ne solo definizioni di membro e nessun codice. Un tipo interfaccia è una descrizione parziale

di un tipo, che più classi possono potenzialmente supportare. In altri termini, una buona

interfaccia è un’interfaccia che viene implementata da diversi tipi differenti e incapsula un

blocco di funzionalità, utile e generalizzato, che i client vogliono utilizzare. Ecco perché

molte interfacce terminano proprio con il suffisso “able”, come accade per IDisposable,

IComparable e IFormattable. Se un’interfaccia ha una sola classe di implementazione utile,

è probabilmente il frutto di una pessima scelta di design. Come regola pratica, delle nuove

interfacce devono essere introdotte con parsimonia e con una dovuta riflessione. Una classe

base definisce un comportamento comune e una comune interfaccia di programmazione

per un albero di classi figlie. Le classi sono più flessibili delle interfacce e supportano il ver-

sioning. Se si aggiunge un nuovo metodo alla versione 2.0 di una classe, ogni classe derivata

esistente continua a funzionare immutata, purché il nuovo metodo non sia astratto. Ciò

non è vero per le interfacce. Alla luce di queste considerazioni, la regola emergente è che

si dovrebbero utilizzare le classi base invece delle interfacce ogni qualvolta sia possibile (il

che non va interpretato come “utilizzare sempre le classi base”). A mio avviso, le classi base

appaiono come una scelta eccellente, per quanto concerne il modello di provider.

Lo strato di configurazione

A ciascun tipo di provider supportato viene assegnata una sezione nel file

di configurazione, dove viene impostato il provider di default della specifica

caratteristica e dove vengono elencati tutti i provider disponibili. Se il provider

espone proprietà pubbliche, i valori di default di queste proprietà possono essere

specificati attraverso attributi. Il contenuto della sezione viene passato come

argomento al metodo Initialize della classe ProviderBase: l’unico metodo che tutti

i provider hanno in comune. All’interno di questo metodo, ciascun provider utilizza

le informazioni passate per inizializzare il proprio stato. Ecco un’istantanea della

sezione di configurazione del provider di membership.

<membership defaultProvider=”AspNetSqlProvider”> <providers> <add name=”AspNetSqlProvider” type=”System.Web.Security.SqlMembershipProvider, System.Web” connectionStringName=”LocalSqlServer” enablePasswordRetrieval=”false” enablePasswordReset=”true” requiresQuestionAndAnswer=”true” ... passwordFormat=”Hashed” /> ... </providers></membership>

Capitolo 1 Il modello di programmazione ASP .NET 33

Lo strato storage

Tutti i provider devono leggere e scrivere informazioni su un supporto persistente di

memorizzazione. In molti casi, due provider dello stesso tipo differiscono solo per lo storage

che impiegano. I dettagli del supporto di storage vengono impacchettati negli attributi del

provider nella sezione <providers>, come mostrato nel precedente esempio di codice. Ad

esempio, il precedente provider AspNetSqlProvider è il provider di membership predefinito

che legge e scrive su una tabella SQL Server. La stringa di connessione del provider viene

specificata attraverso l’attributo connectionStringName, che a sua volta si riferisce a un’altra

sezione centralizzata dei file di configurazione che elencano tutte le stringhe di connessione

disponibili. Perché il provider possa operare, deve esistere ogni infrastruttura necessaria

(ossia, database, tabelle, relazioni). L’impostazione dell’ambiente di lavoro è un compito

tipicamente eseguito al momento del deployment. ASP.NET semplifica molto questo

compito grazie alla console di amministrazione del sito Web, mostrata nella Figura 1-9.

Figura 1-9 La console ASP.NET di amministrazione del sito Web invocabile da Visual Studio .NET 2005.

Tipi di provider disponibili

Il modello di provider viene utilizzato per conseguire diversi compiti, i più

importanti dei quali sono i seguenti:

• L’implementazione di un meccanismo read/write per persistere il profilo utente

• La creazione di un repository definito dall’utente di credenziali utente che supporta

le più comuni operazioni, tra cui il controllo dell’esistenza di un utente, l’aggiunta

e la cancellazione di utenti, e la modifica delle password

• La creazione di un repository definito dall’utente per i ruoli utente

• La definizione della mappa del sito

• L’introduzione di tipi più recenti di storage dei dati per lo stato della sessione

34 Parte I Realizzare una pagina ASP .NET

La Tabella 1-1 mostra l’elenco delle classi provider disponibili in ASP.NET.

Tabella 1-1. Classi base provider ASP.NET disponibili

Classe Descrizione

MembershipProviderClasse base dei provider di membership utilizzata per gestire le informazioni dell’account utente.

Profi leProviderClasse base dei provider di personalizzazione utilizzata per persistere e recuperare le informazioni sul profi lo dell’utente.

RoleProviderClasse base dei provider di ruolo utilizzata per gestire le informazioni sul ruolo dell’utente.

SessionStateStoreProviderBaseClasse base dei provider di memorizzazione dello stato di sessione. Questi provider vengono utilizzati per salvare e recuperare le informazioni sullo stato di sessione da supporti persistenti di memorizzazione.

SiteMapProvider Classe base per la gestione delle informazioni sulla mappa del sito.

Le classi elencate nella Tabella 1-1 definiscono un metodo astratto per ciascun aspetto

personalizzabile della caratteristica che rappresentano. Ad esempio, riguardo alla gestione

della membership, la classe MembershipProvider espone metodi come ValidateUser,

CreateUser, DeleteUser, ChangePassword e via dicendo. Si noti che non si utilizzerà mai

MembershipProvider nel codice, proprio perché è una classe astratta. Invece, si utilizzerà

una classe derivata come SqlMembershipProvider o, probabilmente, ActiveDirectoryMem

bershipProvider. La stessa considerazione vale per altri tipi di provider.

Infine, se si deve scrivere un provider di membership custom che avvolge il proprio

codice esistente, se sono coinvolte altre caratteristiche basate sul provider si deve creare

una classe che deriva da MembershipProvider o da classi simili.

[Nota] L’architettura dei provider è una delle nuove caratteristiche più importanti di ASP.NET 2.0 ed è anche una delle più delicate per quanto concerne le applicazioni. Per impedire che gli sviluppatori producano provider difettosi, il team ASP.NET fornisce un ap-posito provider toolkit che dettaglia ciò che si può e non si può fare in un provider oltre a un gran quantità di codice d’esempio da utilizzare come guida. La scrittura di provider custom può essere complicata, almeno per un paio di motivi. Primo, i provider ASP.NET devono essere thread-safe. Secondo, la fase di inizializzazione del provider può condurvi dritto drit-to a una rientranza letale. Assicuratevi di scaricare il provider toolkit ASP.NET dall’ASP.NET Developer Center prima di imbarcarvi in un nuovo progetto di provider.

ConclusioniEssendo parte integrante del .NET Framework, ASP.NET permette di sfruttare

appieno il vantaggio delle caratteristiche del Common Language Runtime (CLR), tra cui

la type safety, l’ereditarietà, l’interoperabilità di linguaggio e il versioning. Essendo la

più recente piattaforma per le applicazioni Web, ASP.NET si basa sul successo di diverse

Capitolo 1 Il modello di programmazione ASP .NET 35

altre piattaforme, tra cui ASP classico, JSP e LAMP. ASP.NET promuove un modello di

programmazione che, benché sia implementato sul protocollo HTTP che è stateless,

appare ai programmatori come stateful e a eventi.

In questo capitolo, abbiamo prima descritto il modello di componente che supporta

le pagine Web ASP.NET e poi abbiamo analizzato lo stack di sviluppo dall’alto (strato di

presentazione e controlli sofisticati) in basso (infrastruttura e provider). Il modello di

provider, in definitiva un’implementazione del pattern strategy, è un elemento chiave

nella nuova architettura ASP.NET e un pilastro di supporto per le nuove applicazioni.

Applicato in modo estensivo, permette di personalizzare diversi aspetti di basso livello

dell’ambiente di run-time dell’applicazione e di riusare grosse porzioni del codice

esistente. Compreso a fondo, fornisce un modo per implementare nuovi componenti

flessibili e estensibili al di là di ogni immaginazione e, in quanto tali, collegarli in modo

omogeneo in una varietà di progetti e più facili da personalizzare da parte dei client.

In sintesi

• In ASP.NET, si sfrutta appieno il vantaggio di ogni caratteristica del CLR, tra cui la type safety, l’ereditarietà , la Code Access Security e l’interoperabilità tra linguaggi

• In fase di esecuzione, le pagine ASP.NET vengono rappresentate da una istanza di una classe che deriva dalla classe Page

• La classe Page è il punto terminale di una pipeline di moduli che processano ogni richiesta HTTP

• Solo agli elementi di una pagina ASP.NET contrassegnati con l’attributo runat si può accedere da programma quando la pagina viene eseguita sul server

• Gli elementi di pagina privi dell’attributo runat non vengono processati sul server e vengono emessi verbatim

• L’attributo runat si applica virtualmente a ogni tag possibile che si può utilizzare in una pagina ASP.NET, compresi i tag custom e quelli incogniti

• Il modello di processo è la sequenza di operazioni necessarie a processare una richiesta. Il modello di processo è determinato da IIS e determina quale processo worker si fa carico dell’esecuzione delle applicazioni ASP.NET e sotto quale account

• Le applicazioni ASP.NET vengono eseguite con un account non privilegiato

• Il comportamento delle applicazioni ASP.NET può essere confi gurato per mezzo di un gruppo di fi le d confi gurazione

• Il modello di provider ASP.NET è una caratteristica infrastrutturale che migliora l’architettura di una applicazione abilitando gli sviluppatori e gli architetti a operare dietro le quinte di alcuni componenti di sistema

• Il modello di provider ASP.NET comporta due principali vantaggi: una vasta personalizzazione dell’ambiente run-time dell’applicazione e la riusabilità del codice