Tutorial ASP.NET 2.0 - Parte prima: Lavorare con le Master Page
a cura di Antonio Catucci e Mario De Ghetto (requisiti: nessuno)Premessa
Questa serie di articoli si propone di creare un sito web utilizzando Visual Studio 2005, il linguaggio Visual Basic e la tecnologia ASP.NET 2.0.Introduzione
Le applicazioni per il web, nel tempo, si sono articolate sempre di più utilizzando molte tecnologie, l'una diversa dall'altra, ma sempre in stretta interrelazione tra loro. Infatti, ad oggi, questo è l'elenco di ciò che viene utilizzato (e sicuramente avremo dimenticato qualcosa: per questo abbiamo incluso la voce "e molto altro"!):
- web server (IIS, Apache, Cassini, ecc.)
- HTML
- ASP.NET 2.0
- linguaggi VB.NET, C#, JavaScript, VBScript, PHP...
- CSS (fogli di stile) per il layout delle pagine
- ADO.NET 2.0 per l'interazione con i database
- estensioni AJAX 1.0 per ASP.NET 2.0
- animazioni Macromedia Flash
- e molto altro...
Questo panorama di tecnologie, apparentemente caotico, può portare l'aspirante programmatore web a non sapere da che parte iniziare e questo è sicuramente frustrante. Questa serie di articoli è stata pensata proprio per chi vuole iniziare da zero, ma speriamo che alcune tecniche possano essere utili anche a qualche programmatore più esperto.
Per il codice di esempio abbiamo pensato di presentarlo sotto forma di mini sito web navigabile suddiviso per sezioni, dove in ciascuna sezione troverete uno o più esempi relativi all'argomento trattato. Dunque, ad ogni puntata, rilasceremo il sito completo, aggiornato con l'ultima parte ovviamente.
Dato che non sempre sarà possibile spiegare dettagliatamente tutti gli esempi vi consigliamo di scaricare sempre il codice allegato perché, oltre al codice completo e commentato, potreste trovarci anche qualche esempio in più :).
Partire da zero
Bene, iniziamo! Siamo davanti al monitor, con Visual Studio 2005 già pronto per lavorare con noi: cosa possiamo fare?
Prima di tutto creiamo un nuovo progetto web: menu File > New Web Site... e selezioniamo il modello ASP.NET Web Site.
Figura 1 - Finestra di dialogo per la creazione di un nuovo sito webIl modello ASP.NET Web Site è nuovo in .NET 2.0 e si differenzia dal precedente modello di ASP.NET 1.x dal fatto che il sito non viene compilato in un assembly, ma ciascuna pagina viene compilata a runtime solo quando viene richiesta e/o modificata.
Nella finestra di dialogo indichiamo dove salvare il nostro sito web (File System, HTTP o FTP) e il linguaggio scelto per lo sviluppo.
L'opzione File System è un'altra novità di ASP.NET 2.0 e consente di sviluppare un sito web indicando semplicemente un percorso senza necessariamente avere IIS installato sul pc. In realtà il sito web viene eseguito con un server web ridotto (Cassini) gestito da Visual Studio 2005 consentendo, in questo modo, di sviluppare applicazioni web anche su pc senza IIS. Trattandosi, però, di un server web con funzionalità ridotte è consigliabile testare il sito web su IIS prima della sua distribuzione.
Specifichiamo il nome del nostro sito web e premiamo OK. Visual Studio crea una struttura minima di base da cui partire composta da alcuni file (come mostrato in figura 2).
Vediamo brevemente quali file vengono aggiunti.
Il primo è Default.aspx. Si tratta della pagina di avvio di un sito web, il cui nome può essere scelto a piacimento (tipicamente però è Default o Index).
Ogni pagina è composta da due file: una con estensione aspx contenente il codice di markup e l'altro con estensione .vb (o .cs a seconda del linguaggio scelto), contenente tutto il codice di funzionamento chiamato anche code-behind. E' possibile tuttavia avere tutto all'interno del file .aspx evitando di avere due file per pagina. Noi utilizzeremo sempre il code behind negli esempi, perché consentono una migliore organizzazione e separazione del markup dal codice.
La relazione tra la pagina aspx ed il relativo code-behind viene specificata nella pagina aspx mediante gli attributi CodeFile e Inherits della direttiva @Page che indicano rispettivamente il nome del file code-behind e il tipo (classe) della pagina (tipicamente ha stesso nome della pagina):
Figura 2 - Struttura iniziale di un'applicazione web<%@ Page Language="VB" AutoEventWireup="false" CodeFile="Default.aspx.vb" Inherits="_Default" %>Il file code-behind si prensenta nel modo seguente:
Partial Class _Default Inherits System.Web.UI.Page End ClassL'altro file creato è web.config. Si tratta di un file in formato xml contenente tutti i parametri di configurazione dell'applicazione (dall'autenticazione alla gestione degli errori, dall'accesso ai dati alla localizzazione e così via). Analizzeremo in dettaglio come utilizzarlo durante la costruzione del sito.
Infine viene creata la cartella App_Data. Si tratta di una cartella speciale (ne esistono diverse) che assume un significato speciale, appunto, per il runtime di ASP.NET. Per il momento ci basta sapere questo sulle cartelle speciali: riprenderemo l'argomento più approfonditamente quando se ne presenterà l'occasione.
Non ci resta che iniziare a sviluppare il nostro sito web iniziando da una delle novità introdotte in ASP.NET 2.0: le MasterPage.Master Page
Prima di tutto cos'è una Master Page?
Chi ha già programmato (o programma) in ASP.NET 1.x, avrà constatato come sia difficile cambiare il layout delle pagine una volta completato il sito: la modifica del layout comporta, nella migliore delle ipotesi, mettere mano alla maggior parte delle pagine.
Qualche meccanismo per migliorare questa situazione lo si ha con gli UserControl, che consentono di realizzare porzioni di pagina da condividere nella varie pagine del sito, ma resta un escamotage e non una funzionalità nativa del Framework.
Finalmente Microsoft ha introdotto il concetto di Master Page: si tratta di una pagina template (modello) da usare come base per tutte le altre. Tipicamente, in questa pagina viene inserito tutto il testo statico come il titolo del sito, mentre le parti dinamiche sono definite con dei controlli "segnaposto" chiamati <asp:ContentPlaceHolder />. Le pagine di contenuto forniranno solamente i contenuti veri e propri, presentandoli secondo le impostazioni della Master Page a cui fanno riferimento.Aggiungiamo una master page al nostro sito facendo click con il pulsante destro del mouse sul nome del progetto nella finestra Solution Explorer e selezioniamo Add New Item.... Nella finestra di dialogo che appare selezioniamo l'icona Master Page e specifichiamone il nome (il default è MasterPage.master). L'opzione Place code in separate file (attiva di default) permette di separare il codice dall'html e, come detto in precedenza, sceglieremo sempre questa soluzione. Denominiamo la pagina TutorialMasterPage.master e premiamo il pulsante Add.
Figura 3 - Inserimento di una MasterPageIl markup della pagina TutorialMasterPage.master è il seguente:
<%@ Master Language="VB" CodeFile="TutorialMasterPage.master.vb" Inherits="TutorialMasterPage" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>Untitled Page</title> </head> <body> <form id="form1" runat="server"> <div> <asp:contentplaceholder id="ContentPlaceHolder1" runat="server"> </asp:contentplaceholder> </div> </form> </body> </html>Come si vede, le differenze da una pagina tradizionale sono minime. Innanzitutto la direttiva @Master anzhichè @Page, con i vari attributi che definiscono il code-behind e la classe, e poi la presenza del controllo <asp:ContentPlaceHolder /> che definisce l'area in cui verrà inserito il contenuto delle varie pagine. Naturalmente è possibile avere diversi ContentPlaceHolder ed è quello che faremo. In questo esempio, infatti, creeremo due ContentPlaceHolder, uno per il menu e uno per i contenuti veri e propri, specifici di ciascuna pagina. Ecco qui il markup della master page modificato:
<%@ Master Language="VB" CodeFile="TutorialMasterPage.master.vb" Inherits="TutorialMasterPage" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>Untitled Page</title> </head> <body> <form id="form1" runat="server"> <div> <asp:contentplaceholder id="CPH_Menu" runat="server"> </asp:contentplaceholder> <asp:contentplaceholder id="CPH_Centrale" runat="server"> </asp:contentplaceholder> </div> </form> </body> </html>Ecco come si presenta la pagina nell'IDE:
Figura 4 - La MasterPage in modalità designPerché mettiamo il menu in un ContentPlaceHolder? Non potremmo lasciarlo come elemento fisso della pagina master? E' presto detto: in questo modo potremo avere un menu uguale in tutte le pagine, tranne in quelle in cui decidiamo di modificarlo o... farlo sparire.
Per spiegare meglio quest'ultima affermazione, è bene precisare un fatto: all'interno di un ContentPlaceHolder della pagina master è possibile inserire qualsiasi cosa, cioè componenti, testo fisso ecc.. In questo caso la pagina dei contenuti potrà sostituire integralmente il contenuto del ContentPlaceHolder (basta un carattere qualsiasi e il contenuto fornito dalla pagina master viene reso invisibile) oppure si potrà decidere di lasciare invariato il contenuto.Aggiungere una pagina collegata alla MasterPage
Una volta che è stata aggiunta almeno una pagina master al sito, l'IDE ci aiuta a definire per ogni nuova pagina la MasterPage alla quale deve fare riferimento. Aggiungiamo una pagina Index.aspx collegata alla master page selezionando il menu Website e, successivamente, Add New Item.... Nella finestra di aggiunta di un nuovo elemento, selezioniamo l'icona Web form, specifichiamo il nome della pagina e attiviamo la casella di controllo Select master page per scegliere la master page da usare:
![]()
Figura 5 - Inserimento di una pagina legata ad una MasterPage
Figura 6 - Scelta della Master Page da utilizzareDato l'OK, viene creata una pagina come questa:
<%@ Page Language="VB" AutoEventWireup="false" title="Untitled Page" MasterPageFile="~/TutorialMasterPage.master" CodeFile="Index.aspx.vb" Inherits="Index" %> <asp:Content ID="Content1" ContentPlaceHolderID="CPH_Menu" Runat="Server"> </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="CPH_Centrale" Runat="Server"> </asp:Content>Una pagina collegata ad una pagina master si presenta diversamente rispetto ad una pagina tradizionale. La direttiva @Page ha l'attributo MasterPageFile contenente il path della pagina master a cui è collegata, mentre gli altri attributi identificano il file del code behind e il nome della classe della pagina. Notate la totale assenza dei tag <html>, <body> e <asp:Form>: questo perché sono già contenuti nella master. Al loro posto troviamo dei controlli server <asp:Content />, uno per ciascun ContentPlaceHolder definito nella master page. La relazione avviene tramite la proprietà ContentPlaceHolderID cioè l'id del ContentPLaceHolder a cui ciascun Content si riferisce come mostrato di seguito:
Figura 7 - Relazione MasterPage e PageCome vedete, il runtime ASP.NET non fa altro che fondere l'html delle due pagine in una unica pagina che viene restituita al browser.
Ora che abbiamo una pagina collegata alla master page possiamo disfarci della pagina default.aspx creata da Visual Studio in fase di creazione del progetto. Prima di farlo, però, mostriamo brevemente come collegare manualmente una pagina tradizionale (la default.aspx) ad una master page.Collegare manualmente una pagina alla master page
La prima operazione è aggiungere l'attributo MasterPageFile nella direttiva @Page selezionando la master page a cui collegare la pagina:
Figura 8 - Supporto Intellisense per le MasterPageQuesto però non è sufficiente. Infatti, la pagina Default.aspx definita durante la creazione del nuovo sito è una pagina completa di tutti i tag previsti per una pagina autonoma, ma noi non vogliamo una pagina autonoma: vogliamo una pagina che abbia solo i contenuti della pagina.
Pertanto dobbiamo modificare il codice come segue:
- togliamo tutte le righe dall'inizio del file (esclusa la direttiva @Page) fino al tag "body" compreso;
- togliamo tutte le righe dal tag "</body>" compreso fino alla fine;
- all'inizio del file modifichiamo la direttiva @Page:
<%@ Page Language="VB" AutoEventWireup="false" MasterPageFile="~/TutorialMasterPage.master" CodeFile="~/Default.aspx.vb" Inherits="_Default" title="Home Page" %>- infine racchiudiamo il contenuto della pagina (prima contenuto nel tag <body>) nel controllo asp:Content:
<asp:Content ID="C_Centrale" ContentPlaceHolderID="CPH_Centrale" Runat="Server"> <div> Pagina di contenuti </div> </asp:Content>In questo modo avremo la pagina di contenuti effettivamente legata alla pagina master:
<%@ Page Language="VB" MasterPageFile="~/TutorialMasterPage.master" AutoEventWireup="false" CodeFile="~/Default.aspx.vb" Inherits="_Default" title="Home Page" %> <asp:Content ID="C_Menu" ContentPlaceHolderID="CPH_Menu" Runat="Server" /> <asp:Content ID="C_Centrale" ContentPlaceHolderID="CPH_Centrale" Runat="Server"> <div> Pagina di contenuti </div> </asp:Content>Un metodo alternativo
Mediante l'attributo MasterPageFile della direttiva @Page è possibile definire la pagina Master per ogni singola pagina. Il vantaggio di questa scelta è dato dal fatto che è possibile creare diverse pagine Master e quindi associare quella appropriata per ciascuna pagina del sito.Se la pagina master è una sola o se le poche pagine master gestite sono ciascuna per una cartella diversa dell'applicazione, è possibile fare in modo che tutte le pagine dell'applicazione o della singola cartella facciano riferimento alla stessa pagina master per default. E' possibile ottenere questo risultato con la modifica della seguente riga al file web.config:
<configuration> <system.web> <pages masterpagefile="TutorialMasterPage.master"> ... </pages> </system.web> </configuration>Avvio dell'applicazione
E' venuto il momento di avviare il programma: alla pressione del tasto F5 comparirà un messaggio di avviso. Tale messaggio ci avvertirà che non è possibile eseguire l'applicazione in modalità debug, perché tale modalità non è impostata nel file web.config. Per modificare automaticamente il web.config basta rispondere con "OK". A questo punto partirà il browser con una pagina del sito oppure con l'elenco dei file che fanno parte dell'applicazione web (se non è stata definita una pagina di avvio).La modifica automatica del file web.config consiste nella modifica del relativo attributo:
<compilation debug="true"> </compilation>Nel momento in cui l'applicazione viene definitivamente pubblicata sul web, è opportuno disabilitare il debug dal file web.config, in modo da migliorare le prestazioni dell'applicazione stessa.
Master page annidate
Possiamo descrivere con la relazione
[Master page] <-- [Content page]
la struttura a due livelli che abbiamo utilizzato in questo tutorial e che indubbiamente porta enormi vantaggi, come già abbiamo descritto.
Tuttavia è possibile pensare e realizzare anche strutture di pagine master "multiple", annidate le une all'interno di altre.
In questo caso la struttura diventa a tre o più livelli:
[Master page] <-- [Master/content page] <-- [Content page]L'elemento rappresentato con [Master/content page], cioè uno dei livelli annidati nella pagina master principale o in una pagina master secondaria, è definito anch'esso come vera e propria pagina master, ma è allo stesso tempo anche una pagina di contenuti. Un esempio di tale applicazione è la suddivisione del sito in più aree tematiche, dove ciascuna area è rappresentata da una MasterPage, le quali fanno parte della MasterPage principale del sito. Sarà comunque lo sviluppatore a decidere quali elementi devono essere fissi nella pagina master principale, quali elementi devono essere fissi e quali contenuti devono essere presenti nella pagina master intermedia e, infine, quali devono essere i contenuti della pagina dei contenuti.
Prima di continuare occorre fare una importante precisazione: l'IDE di Visual Studio 2005 non è in grado di rappresentare pagine master annidate in modalità di design visuale. Questo fatto comporta un problema: non potendo visualizzare la pagina non è nemmeno possibile sfruttare le comode funzionalità dell'IDE per l'inserimento di nuovi componenti sulla pagina o per modificare le caratteristiche degli elementi già inseriti. Un modo per aggirare questo problema è quello di lavorare con pagine web tradizionali e poi trasformarle in master. Vi farà sicuramente piacere il fatto che in Visual Studio 2008 questa limitazione non ci sarà.
Vediamo un esempio di pagine master annidate, distinto dal progetto generale di questo tutorial che andremo a creare in una cartella apposita chiamata 1_MasterPageAnnidate come mostrato nella figura accanto.
Iniziamo:
- Aggiungete una master page MasterPage.master (e questo ormai sapete farlo)
- rinominiamo cph_Main l'unico controllo ContentPlaceHolder;
- aggiungiamo una pagina di tipo Web form e di nome MasterPage2.aspx e colleghiamola alla pagina master MasterPage.master; questa pagina diventerà la master page annidata alla master creata al punto (1);
- modificate la pagina MasterPage2.aspx inserendo i contenuti opportuni (testo e quant'altro);
- concluse le modifiche possiamo trasformare la pagina in una master page. Rinominiamo "MasterPage2.aspx" in "MasterPage2.master". Automaticamente cambierà anche il nome di "MasterPage2.aspx.vb" in "MasterPage2.master.vb";
- In modalità source modifichiamo la direttiva:
<%@ Page Language="VB" MasterPageFile="~/MasterPage.master" AutoEventWireup="false" CodeFile="MasterPage2.aspx.vb" Inherits="MasterPage2" %>in:
<%@ Master MasterPageFile="~/MasterPage.master" Language="VB" CodeFile="MasterPage2.master.vb" Inherits="MasterPage2" %>Notare che la direttiva Page è cambiata in Master, l'attributo CodeFile fa riferimento al nuovo nome del file di codice associato
- Modifichiamo anche il code-behind (MasterPage2.master.vb):
Partial Class MasterPage2 Inherits System.Web.UI.Page End Classin:
Partial Class MasterPage2 Inherits System.Web.UI.MasterPage End Class- l'ultima modifica da fare è aggiungere un ContentPlaceHolder all'interno del Content:
<asp:ContentPlaceHolder id="cph_Main_2" runat="server"> </asp:ContentPlaceHolder>La pagina finale è la seguente:
<%@ Master MasterPageFile="~/MasterPage.master" Language="VB" CodeFile="MasterPage2.master.vb" Inherits="MasterPage2" %> <asp:Content ID="Content1" ContentPlaceHolderID="cph_Main" Runat="Server"> Questa è la sezione "Content1" della MasterPage2.aspx<br /> Inseriamo qui un nuovo ContentPlaceHolder:<br /> <br /> <asp:ContentPlaceHolder id="cph_Main_2" runat="server"> </asp:ContentPlaceHolder> <br /> </asp:Content>Ora abbiamo due master page, che possiamo usare a seconda della sezione del sito che intendiamo sviluppare, tenendo a mente che, nel caso scegliessimo la MasterPage2, non potremo lavorare in modalità progettazione, ma solo in modalità Source. L'alternativa è realizzare la pagina a parte, per poi collegarla manualmente, come spiegato sopra.
Aggiungiamo una pagina chiamata PaginaCon1ContentPlaceHolder.aspx collegata alla MasterPage2 con il contenuto mostrato di seguito:
<%@ Page Language="VB" MasterPageFile="~/MasterPage2.master" AutoEventWireup="false" CodeFile="PaginaCon1ContentPlaceHolder.aspx.vb" Inherits="PaginaCon1ContentPlaceHolder" %> <asp:Content ID="Content2" ContentPlaceHolderID="cph_Main_2" Runat="Server"> <br /> Questo è il contenuto di ContentPlaceHolder2 <br /> </asp:Content>Fate click con il tasto destro del mouse sulla pagina appena creata e selezionate View in a browser.... Ecco qui il risultato (con qualche motivo grafico in più che potete trovare nell'esempio allegato):
![]()
Per dimostrare le possibilità delle pagine master nidificate, aggiungiamo una nuova MasterPage (MasterPage3.master) contenente il seguente codice:
<%@ Master MasterPageFile="~/1_MasterPageAnnidate/MasterPage.master" Language="VB" CodeFile="MasterPage3.master.vb" Inherits="MasterPage3" %> <asp:Content ID="Content1" ContentPlaceHolderID="cph_Main" Runat="Server"> Questa è la sezione "Content1" della MasterPage3.aspx<br /> Inseriamo qui un nuovo ContentPlaceHolder (cph_Main_3A):<br /> <br /> <asp:contentplaceholder id="cph_Main_3A" runat="server"> </asp:contentplaceholder> <br /> Qui è di nuovo la MasterPage3.aspx <br /> Inseriamo qui un nuovo ContentPlaceHolder (cph_Main_3B):<br /> <br /> <asp:contentplaceholder id="cph_Main_3B" runat="server"> </asp:contentplaceholder> <br /> </asp:Content>Aggiungiamo poi anche un'altra pagina (PaginaCon2ContentPlaceHolder.aspx), basata sulla MasterPage3.master:
<%@ Page Language="VB" MasterPageFile="~/1_MasterPageAnnidate/MasterPage3.master" AutoEventWireup="false" CodeFile="PaginaCon2ContentPlaceHolder.aspx.vb" Inherits="PaginaCon2ContentPlaceHolder" %> <asp:Content ID="Content2" ContentPlaceHolderID="cph_Main_3A" Runat="Server"> =================================<br /> Questo è il contenuto di ContentPlaceHolder2<br /> ================================= </asp:Content> <asp:Content ID="Content3" ContentPlaceHolderID="cph_Main_3B" Runat="Server"> =================================<br /> Questo è il contenuto di ContentPlaceHolder3<br /> =================================<br /> <br /> Questa pagina si basa sulla MasterPage3.master, che a sua volta si basa sulla MasterPage.master.<br /> Anche la MasterPage2.master si basa sulla stessa MasterPage.master, ma ha un ContentPlaceHolder in meno rispetto a questa pagina. </asp:Content>Ecco quindi come si presenta questa pagina:
![]()
Si potrà così constatare che la pagina master principale fornisce un'impostazione generale al sito, mentre ciascuna pagina master intermedia può aggiungere ulteriori elementi che dovessero rendersi necessari per personalizzare le diverse aree del sito.
Conclusioni
Avviando gli esempi di questo tutorial, nel browser vedremo tutti gli elementi fissi impostati nella pagina master e i contenuti personalizzati per ciascuna area. Certamente non è ottimale, si può fare di meglio.
Per ottenere risultati migliori bisogna intervenire a livello di presentazione della pagina e di rendering dei controlli con le seguenti tecniche:
- creando un file CSS, che è il cosiddetto foglio di stile della pagina, dove si possono impostare numerosi attributi della pagina, del testo e di molti altri elementi;
- utilizzando i "temi" (themes) o per meglio dire gli "stili" per gli elementi che compongono la pagina.
Vedremo come, utilizzando entrambe le tecniche, si possono ottenere i risultati migliori.
Vedremo anche come è possibile aggiungere un menu un po' più sofisticato dei semplici link alle varie pagine.
Tutto il codice relativo a questo esempio è scaricabile dall'area download.
In merito a questo articolo, potete scrivere agli autori Antonio Catucci e Mario De Ghetto.