Come ogni nuova versione di qualunque prodotto, ASP.NET 2.0 si presenta con tante novità. Sul web e in molti eventi discutibilmente tecnici vengono sbandierate soprattutto le caratteristiche visibili fino dalla prima occhiata superficiale. Ci sono nuovi web controls, nuovi controlli per fare data binding senza scrivere una riga di codice, nuove caratteristiche del nuovo Visual Studio 2005 per semplificare il codice. Personalmente credo che queste novità rappresentino le cosiddette minor changes, cioè modifiche di minor importanza rispetto a modifiche architetturali, nuove modalità di gestione del codice, nuovi strumenti amministrativi e diverse modalità di compilazione. Solitamente il tutto viene presentato accompagnato dal supporto in Visual Studio 2005 per i nuovi controlli. In questo articolo ragioneremo al contrario, sottolineando il fatto che Visual Studio 2005 è un ottimo alleato per la scrittura di applicazioni ASP.NET 2.0, ma è importante capire il prodotto in se e per se prima di utilizzare un ambiente di sviluppo visuale.
Una delle caratterische che accompagna anche la prima versione di ASP.NET è la possibilità di estendere, personalizzare e modficare il comportamento di default: queste possibilità di concretizzano nella scrittura di codice in risposta a eventi scatenati a livello application, nella scrittura di HttpModule o HttpHandler, nella definizione di un proprie classi Page da cui derivare il funzionamento delle varie pagine reali dell’applicazione. La nuova versione si presenta con un’architettura estenbile basata su Provider: un provider è un “gestore” di informazioni. Esiste un provider denominato Membership che si incarica di gestire le login all’applicazione e interagisce con gli attuali moduli di autenticazione; Role Manager è il provider per la gestione (inserimento/modifica/cancellazione) dei ruoli applicativi e l’associazione di tali ruoli agli utenti; Profile è il provider che gestisce tutte le informazioni (tranne quelle di login gestite da Membership) sull’utente, dai dati personali fino alle informazioni per la personalizzazione del look & feel del sito; Site Navigation consente di gestire il modello logico per la navigazione dell’applicazione e il map di tale modello con la gerarchia fisica della pagine presenti.
Tali provider astraggono lo store dove vengono appoggiano le informazioni da gestire. E’ possibile infatti memorizzare tali dati su database diversi, con strutture proprietarie, oppure su file di configurazione XML. Con qualche riga di codice è possibile costruire le proprie classi (per derivazione dalle classi base o per implementazione di interfacce) per una gestione completamente custom. Proviamo a concretizzare con un esempio su Membership, applicabile comunque agli altri provider:
Da codice si utilizza Membership.CreateUser(username, password) per creare un nuovo utente, Membership.ValidateUser(username, password) per validare l’utente dalla pagina di login, il tutto indipendentemente dalla configurazione del provider Membership. Utilizzando i provider di default (sono disponibili SqlServer e Access nella versione Beta1) non è richiesta nessun altra configurazione. Vengono create automaticamente le strutture strandard nel db di riferimento (Access è il default) per ospitare le informazioni di login. Lo stesso paradigma di applica a Role Manager e Profile. E’ sufficiente abilitare tali provider dal web.config dell’applicazione. Per applicazioni semplici, e con un numero relativo di utenti, i provider di default rappresentano un’ottima soluzione per evitare di dover costruire la struttura dati e le relative classi necessarie alla gestione dei dati. Come sempre dai meccanismi totalmente automatizzati non possiamo aspettarci il massimo in termini di efficienza, elasticità e soprattutto riutilizzo; di conseguenza in tutti i casi in cui si vuole avere il controllo sulle strutture dati, dei metodi di accesso ad esse, o più semplicemente, quando tali strutture esistono già e sono in uso da vari applicazioni aziendali, sarà sufficiente implementare il proprio provider. In altre parole si implementa una classe con i metodi necessari all’infrastruttura per la gestione di tali informazioni. Nel caso di Membership è necessario derivare la nostra classe da MembershipProvider implementando i metodi ValidateUser, CreateUser, DeleteUser e così via. Una volta configurato il nostro provider nel web.config potremmo usare ancora una volta il codice precedentemente citato (Membership.CreateUser, Membership.ValidateUser) che andrà a interagire con la nostra classe. Lo stesso discorso si applica a Profile e Role Manager. In altri articoli, sui prossimi numeri, andremo a presentare esempi completi di implementazione di un provider custom.
Un’altra novità, a mio avviso importante, è rappresentata dalle nuove modalità di compilazione. Nella versione attuale, le pagine vengono sempre compilate a run-time (in modalità batch o non-batch a seconda dei parametri di configurazione); anche il build fatto da Visual Studio .NET 2003 compila solo i sorgenti C# o VB.NET dell’applicazione e non i file .aspx; nella versione 2.0 è possibile invece decidere di precompilare l’intera applicazione (per adesso con un tool a riga di comando) distribuendo solo gli assembly risultanti dal processo: questo consente di non dover distribuire anche i sorgenti aspx sulle macchine in produzione. Inoltre, la fase di compilazione delle risorse, che oggi viene effettuata all’interno degli handler che gestiscono le varie estensioni, viene demandata ai BuildProvider. Ad esempio, a fronte di una richiesta per una pagina aspx, viene prima chiamato in causa il PageBuildProvider il quale si occupa solo di compilare (prima generando la classe corrispondente su disco) la risorsa. L’handler (PageHandlerFactory in questo caso) si occupa solo di eseguire la risorsa. Chi si occupa di prelevare il sorgente aspx da disco e fornirlo al BuildProvider è il File System Provider di default. Ancora una volta è possibile definire un comportamento diverso agendo sulla configurazione oppure scriversi un proprio Provider per fornire il sorgente da compilare. E’ possibile ad esempio memorizzare i sorgenti aspx in un database.
Un’altra caratteristica, meno apparente, è rappresentata dall’unificazione dei controlli tradizionali con i controlli mobile: nella versione attuale si utilizzano Web Form e Web Control (
Le modalità di caching sono state notevolmente ampliate, rendendo finalmente possibile impostare una dipendenza dell’elemento in cache dalla struttura dati da cui proviene. Spesso ha senso inserire in cache DataSet o DataTable ADO.NET il cui contenuto è stato prelevato da un database e sarebbe sensato invalidare i dati in cache a fronte della modifica della loro sorgente. La classe SqlCacheDependency consente di impostare dipendenze verso una fonte dati SQL Server e lavora in modo profondamente diverso a seconda che il database sia SQL Server 7/2000 e Yukon (SQL Server 2005). In SQL Server 7/2000 è possibile impostare dipendenze solo su entità (tabelle) e è necessario usare il tool aspnet_regsqlcache.exe. Tale utility crea alcuni trigger sulle tabelle da tenere sotto controllo e utilizza una tabella di appoggio (ChangeNotification Table) dove i trigger andranno a inserire le modifiche effettuate alle tabelle in esame. ASP.NET, purtroppo tramite polling (unica soluzione possibile) andrà a verificare eventuali modifiche alla tabella Change Notification e invalidare gli oggetti in cache. Come noto, le tecniche di polling non sono così efficienti e soprattutto non possono per definizione lavorare in real-time. Il tutto cambia se la base di dati risiede su SQL Server 2005: è possibile impostare una dipendenza direttamente sul comando ADO.NET 2.0 che estrae le informazioni, non è richiesto nessun setup sulla macchina SQL e soprattutto non vengono usate tecniche di polling. Vengono sfruttati i servizi di notifica di SQL 2005 per segnalare a HTTP.SYS (il cuore di IIS 6) una modifica ai result set tenuti sotto controllo. HTTP.SYS informerà Http Listener dell’avvenuta modifica e ASP.NET invaliderà la cache (gli oggetti o le pagine). E’ possibile anche lavorare con dipendenze custom. Per definire una dipendenza custom è sufficiente crearsi una propria classe, derivata da CacheDependency e implementare le proprie politiche per tenere sott’occhio le dipendenze e notificare ASP.NET della modifica a una di esse.
Sopra a queste modifiche strutturali troviamo alcune nuove caratterische per le applicazioni. E’ possibile definire finalmente lauoyt da condividere a più pagine: si costruiscono Master Page consentono di dare le impostazioni globali di layout, e poi si associano alle varie pagine dell’applicazione: ogni modifica alla master page si riflette su tutte le pagine che la referenziano.
Queste modifiche strutturali e nuove componenti hanno portato alla scrittura di oltre 40 nuovi controlli. Alcuni di questi lavorano con Membership per validare l’utente, creare o modificare informazioni di login dell’utente, altri lavorano con Site Navigation per generare i menu di navigazione, altri ancora servono per gestire le Web Part.
Altri nuovi controlli sono invece semplicemente destinati alla generazione di interfaccia utente e non si appoggiano ai provider: Wizard, ContentPager, Hidden Field, MultiView, View, Substitution e per finire una nuova DataGrid denominata GridView.
Concludendo in ordine di importanza, ASP.NET 2.0 si presenta con molte novità architetturali, molti nuovi moduli per gestire utenti, ruoli e profili. Tutta l’architettura è aperta a personalizzazioni. Oltre a queste modifiche sostanziali troviamo anche modifiche per gestire il layout e lo stile delle applicazioni. Inoltre sono presenti molti nuovi controlli. Ovviamente tutto questo viene accompagnato dal pieno supporto di Visual Studio 2005 per gestire le nuove feature.