Interfacciamento di database su web con ASP ed ADO Introduzione Una applicazione web utilizza un sito web come front end per una tradizionale applicazione. La distinzione tra sito ed applicazione web risiede nella capacità del client di attuare la logica (business logic) implementata sul server. La business logic fondamentalmente specifica quale è il comportamento dell’applicazione, e quindi la sua uscita, a fronte di certi ingressi applicati. Un’applicazione web è tale se è possibile modificarne lo stato, dove lo stato è qui inteso come l’insieme dei dati gestiti dall’applicazione stessa. Un altro punto di vista è quello di considerare lo stato del client. Chiariamo meglio questo concetto. Innanzitutto l’interazione tra browser e server web è, come accennato, tipicamente costituita dalle richieste effettuate dal client e dalle risposte ritornate dal server. E questo grazie ad un protocollo di comunicazione, il protocollo HTTP, il quale però per natura non tiene traccia delle connessioni precedenti. Tali richieste possono essere pensate come ingressi indirizzati all’applicazione. Se gli ingressi sono accompagnati da dati aggiuntivi (vedremo quali), è possibile comunicare al programma un’informazione che consente, come detto, di specificarne il comportamento. L’architettura tipica delle applicazioni Web è quella denominata 3-tier, a tre livelli, formata essenzialmente da tre unità logiche, ossia: Un Web Browser (client) Un Web Server (server) Un Database In questi appunti verrà illustrato come con la tecnologia ASP la realizzazione di un’applicazione web con uso di Database sia qualcosa di semplice ed immediato. ODBC e ADO ODBC (Open Database Connectivity) è una interfaccia di programmazione (una API Application Program Interface) standard ed aperta per l’accesso a database. Originariamente rilasciata nel 1992, consente di accedere a database di numerosissimi costruttori, inclusi Microsoft (jet, Access, SQLServer); Oracle, IBM, Informix e numerosi altri. Si tratta, sostanzialmente, di uno strato software che si interpone tra l’applicazione e i driver specifici del database. Consente quindi ai programmi applicativi di usare richieste standard SQL, che accederanno al database, senza necessità di conoscere la particolare interfaccia proprietaria. ODBC è stato sicuramente un grande progresso nella programmazione di DB, ma richiede una certa familiarità di programmazione con le API ed è sostanzialmente procedurale (Scritta in C). Successivamente Microsoft ha introdotto altre due API, questa volta orientate agli oggetti, che vanno sotto il nome di DAO (Data Access Object) e RDO (Remote Data Object), che sono sostanzialmente interfacce per il motore ODBC. Esse definiscono interfacce ActiveX (originariamente COM Component Object Model). Più recentemente Microsoft ha presentato ADO (Active Data Object), basata su una nuova tecnologia di programmazione delle interfacce per DB nota come OLE DB (Object Linking and Embedding for DataBases). La differenza sostanziale con ODBC è che in questo ogni ogni tipo di DB deve avere una DLL (Dynamic Link Library), un driver ODBC, che viene utilizzata dal motore ODBC per accedere allo specifico DB. In OLE DB is hanno ancora dei driver, ma questi sono implementazioni ActiveX, cioè definizioni di classi che implementano delle interfacce, eliminando così i livelli interposti tra il programma e lo specifico DBMS che si sta utilizzando. Attualmente è comunque possibile utilizzare un driver ODBC da OLE DB. ADO e ASP ASP fornisce tutte le funzionalità delle applicazioni CGI e ISAPI in modo più efficiente: con le CGI il server crea un numero di processi pari al numero delle richieste del client causando un aumento dell’utilizzo della RAM e impiegando in modo critico tutte le risorse del sistema con conseguente caduta di performance e aumento del tempo di attesa; le applicazioni che usano ISAPI sono compilate come link dinamici a delle librerie e sono caricate dal servizio WWW. Le applicazioni ISAPI risiedono in memoria e sono più veloci rispetto a quelle scritte tramite la tecnica CGI. Le applicazioni ISAPI richiedono meno overhead perché ogni richiesta non parte come un singolo processo; ma supportano un grado di complessità più elevato a differenza delle active server page quindi più difficili da gestire. ASP utilizza tecniche multithread per consentire l’accesso ad un numero maggiore di utenti eseguendo nello stesso processo più richieste. ASP include supporti nativi per eseguire script in VBscript e Javascript, supporta inoltre l’uso di un qualunque linguaggio di scripting, introducendo uno scripting engine, e di componenti scritti in un qualunque linguaggio incluso Java, C++, Cobol, Visual Basic. Un linguaggio di scripting è necessario per gestire la logica di collegamento, tra i vari elementi della pagina. Gli script e i componenti che sono processati sul server forniscono in output un documento html standard in modo tale che gli active server page possono lavorare con un qualunque browser; inoltre non viene effettuata nessuna compilazione manuale: compilatori Just-in-time automaticamente ricompilano un file asp quando richiesto caricandolo nella cache del server, in modo che i cambiamenti al file possono essere resi visibili immediatamente. Quando si creano oggetti con ASP si creano in pratica oggetti OLE (Object Linking and Embedding) o ActiveX Component. Tramite gli OLE gli utenti possono creare documenti "contenitori" che comprendono parti gestite da altri programmi, gli OLE si basano sul modello COM (Component Object Model). Tutta la specifica di ActiveX, essendo integrata nella specifica OLE, si basa su questo modello. COM fornisce l’architettura e il meccanismo per creare component che saranno condivisi tra applicazioni. Sulla base del modello COM è stato definito DCOM (Distribuited Component Object Model) che definisce una specifica e una implementazione delle interfacce tra oggetti attraverso la rete. ActiveX Server Component conosciuti anche come OLE Automation Servers sono parte dell’applicazione web ma possono essere usati al di fuori del contesto web favorendo il riuso del codice. Il concetto è che è possibile utilizzare un component non solo da un ambiente di sviluppo visuale o in un’applicazione OLE-enabled ma anche in una pagina web, i programmi scritti per il web potranno essere utilizzati in una qualunque altra applicazione OLE-enabled. I component sono oggetti con una piccola differenza: il component è sempre un package separato dall’applicazione come una dll o come un oggetto COM e può essere immediatamente integrato nello script per un suo utilizzo creando un’istanza. ASP lavora con Active Server Object e Component già pre-costruiti fornendo un ambiente per costruirne dei propri. Di seguito vengono analizzati una serie di Active Server Object inclusi nell’ambiente Active Server Page: Request : fornisce l’accesso a qualunque informazione passata in uno script command con una richiesta http proveniente da una forms, una query URL o da un’intestazione http. Response: è responsabile della gestione dell’interazione del server con il client, è usato per costruire i messaggi di risposta verso il browser. Application: permette di settare le proprietà di un oggetto in modo da preservare lo stato quando più utenti accedono contemporaneamente, è usato per memorizzare informazioni comuni che sono condivise tra tutti gli utenti di una singola applicazione. Session: permette di memorizzare e gestire tutte le informazioni necessarie ad un utente in una particolare sessione. Il ciclo di vita di una sessione non si esaurisce saltando da una pagina all’altra bisogna effettuare un richiesta diretta. Le variabili memorizzate nell’oggetto session non vengono perse quando l’utente salta da una pagina all’altra nell’applicazione, ma sono persistenti per l’intera sessione utente. L’obiettivo dell’oggetto session deve essere capito nel contesto in cui è inserito. Le transizioni tra un browser ed un web server sono indipendenti (state less) e mantenere un tracking di un utente risulta un compito arduo: Una proprietà di un oggetto definito come session può essere referenziata su una qualsiasi pagina, in un qualunque momento all’interno del ciclo di vita di una sessione utente; è un modo per correlare le informazioni da una pagina all’altra. Server: permette ad un script di creare un’istanza di un ActiveX Server Components, indispensabile per accedere a qualsiasi component da un’applicazione web. I components sono una delle caratteristiche più importanti delle Active Server Page. Essi sono dll che vengono eseguiti nello spazio di indirizzi di un file asp e di IIS, ed offrono direttamente l’accesso al sistema operativo. Di seguito una serie di components di base forniti insieme alla Active Server Page: Content Linking Component: Gestisce una lista di URL cosicché si possono trattare le pagine di un sito web come se fossero pagine di un libro. Filesystem Component: Fornisce accesso in lettura a un file di testo memorizzato sul server. Browser Capabilities Component: Consente di determinare la capacità, il tipo e la versione dei browser che accedono al web server in modo da ottimizzare dinamicamente il contenuto delle pagine diversificando le risposte, proprio in funzione del browser connesso. Advertisement Rotator Component: automaticamente rende visibile diversi cartelloni pubblicitari in una pagina web in accordo a specifiche impostate dall’utente. Semplifica la gestione delle immagini e produce notevoli effetti visivi come ad esempio la rotazione delle figure. ActiveX Data Object Component: Fornisce l’accesso a un database da un’applicazione web mediante Active database Object (ADO). ADO fornisce un semplice accesso per mezzo di ODBC standard a Micorsoft Access, SQL Server, Oracle, Informix , Sybase. I web browser inoltrano la richiesta di accesso ai dati usando il protocollo HTTP su cui si basa Internet. La risposta consiste in un documento formattato in html. L’accesso al database è ottenuto attraverso l’utilizzo di ODBC. Bisogna tenere presente che ODBC lavora con una connessione diretta mentre Internet è una rete a pacchetti senza connessione (connection less): un browser si appoggia ad un web server il tempo necessario per scaricare un file, mentre Active Server rimane in contatto il tempo necessario per effettuare due compiti: connettersi al database e produrre un recordset; abilitare l’applicazione ad effettuare successive chiamate e ad accedere ai dati precedentemente ritrovati. OLE DB accedono ai dati in maniera diretta e molto più rapidamente di DAO o RDO che invece passano attraverso il livello ODBC. ADO usa un linguaggio di alto livello appoggiandosi direttamente sulle OLE DB che sono di più basso livello. In tal modo possiamo utilizzare ADO per accedere al database. ADO sono solo una possibile implementazione dei ActiveX Component per accedere al database, usando un qualsiasi linguaggio possiamo costruire component personalizzati conformi alle specifiche del COM. ADO lavora meglio delle tecniche tradizionali che usano Data Access Object (DAO) o Remote Data Object (RDO) per accedere al database specialmente in tutti quei casi dove non abbiamo una connessione orientata come in Internet. ADO può trattare efficacemente le transizioni verso il database usando appositi metodi BeginTrans, CommitTrans, Rollback Trans. ADO è composto essenzialmente da tre oggetti primari: Connection Object, Command Object, RecordSet Object: Connection Object è responsabile di raccogliere tutte le informazioni necessarie alla creazione del RecordSet; Command Object fornisce un secondo metodo per creare un RecordSet, ed è stato esplicitamente progettato per passare i parametri alle stored procedure; RecordSet fornisce la struttura atta a contenere i dati e i metodi necessari per accedere ai dati presenti nel RecordSet, tutte le funzionalità dei cursori sono rappresentati nell’interfaccia del RecordSet. Di seguito è riportato un esempio per costruire un RecordSet: /* Creo un’istanza del component e lo assegno Obj */ Set Obj = Server.CreateObject("ADODB.Connection") /* Apertura connessione al database */ Obj.Open ("nameOfIstanza") /* Impostazione interrogazione */ SQLQuery = " SELECT * from Table " /* Il risultato della selezione viene posto in un RecordSet, la cui struttura è determinata dall’impostazione della selezione */ Set ObjRst = Obj.Execute (SQLQuery) I vantaggi di ADO risiedono nella abilità di riuscire a lavorare in ambienti senza stato, in tutti quei casi dove il server non ha memoria, non tiene traccia, delle richieste che ha servito e che sono pervenute dai vari client. ADO permette di creare robuste applicazioni client/server verso database in modo che più persone possono accedere contemporaneamente alla stessa base dati nello stesso istante. Microsoft metterà a punto dei servizi per rendere più agevole il coordinamento delle transizioni. Poiché il servizio transazionale deve essere in grado di interagire con altri sistemi transazionali eterogenei, Microsoft ha realizzato un’architettura capace non solo di integrarsi perfettamente in Internet ma anche di interoperare con sistemi transazionali già esistenti. Immaginiamo di avere il nostro file CINETECA.MDB che contiene informazioni relative alle videocassette di una videonoleggio. Soffermiamoci su due tabelle di cui riportiamo la struttura: Tabella ATTORI_REGISTI: Nome datoIDInteroNOMETestoCOGNOMETestoDATA_NASCITADataDATA_SCOMPDataNAZIONETesto campoTipo Tabella FILM: Nome campoTipo datoIDInteroTITOLOTestoID_REGISTAInteroANNODataQUANTITAInteroID_ATTOREIntero Per semplicità abbiamo supposto di riportare un solo attore e un solo regista per ogni film. Un attore può essere anche regista e viceversa, ecco perché una sola tabella ATTORI_REGISTI con doppia relazione con la tabella FILM. La nostra pagina ASP dovrà visualizzare l’elenco completo dei film disponibili nella videoteca, e quindi con quantità in magazzino maggiore di zero, con nomi e cognomi di attori e registi. La query SQL che faremo su queste tabelle sarà: SELECT FILM.*, Attori.COGNOME as attore_Cogn, Attori.NOME as attore_Nome, Registi.COGNOME as regista_Cogn, Registi.NOME as regista_Nome FROM FILM, ATTORI_REGISTI Attori, ATTORI_REGISTI Registi WHERE Attori.ID=FILM.ID_ATTORE AND Registi.ID=FILM.ID_REGISTA AND FILM.QUANTITA>0; Dal Pannello di Controllo di Windows lanciamo dunque l’ODBC Manager (Origini Dati ODBC) e selezioniamo la voce DSN di sistema. A questo punto possiamo aggiungere in nostro DSN di tipo Microsoft Access Driver (*.mdb), selezionando il file cineteca.mdb e dandogli il nome che vogliamo, ad esempio VIDEO. Ora possiamo scrivere il codice VBScript della nostra pagina ASP. Per prima cosa occorre creare l’oggetto ADODB.Connection: <% set myConn = Server.CreateObject("ADODB.Connection") %> dopodiché occorrerà collegarlo al DSN: <% myConn.Open "VIDEO" %> Adesso ci serve preparare la stringa con l’istruzione SQL che esegue la query: <% SQLString = "SELECT FILM.*, Attori.COGNOME as attore_Cogn, " SQLString = SQLString & "Attori.NOME as attore_Nome, " SQLString = SQLString & "Registi.COGNOME as regista_Cogn, Registi.NOME " SQLString = SQLString & "as regista_Nome FROM FILM, ATTORI_REGISTI " SQLString = SQLString & "Attori, ATTORI_REGISTI Registi WHERE " SQLString = SQLString & "Attori.ID=FILM.ID_ATTORE AND " SQLString = SQLString & "Registi.ID=FILM.ID_REGISTA AND " SQLString = SQLString & "FILM.QUANTITA>0;" %> Possiamo ora eseguire l’istruzione conservando i dati di output in una struttura dati apposita: <% set rsElenco = myConn.Execute(SQLString) %> Recordset Come si vede in queste ultime due istruzioni, il metodo Execute della classe Connection restituisce un oggetto di tipo Recordset. Un Recordset è come una collezione di record ed è quindi composta di righe (i record) e colonne (i campi). Per muoversi da un record al successivo del Recordset è necessario invocare il metodo MoveNext, mentre per leggere il valore di un campo del record si deve utilizzare la sintassi Recordset("nome_campo") Noi vogliamo visualizzare una tabella HTML con il risultato della query. Quindi per prima cosa scriviamo il codice HTML per disegnare l’intestazione della tabella. <TABLE CELLPADDING=1 CELLSPACING=0 BORDER=1 WIDTH=90%> <TR> <TH BGCOLOR=GREEN> TITOLO </TH> <TH BGCOLOR=GREEN> REGISTA </TH> <TH BGCOLOR=GREEN> ATTORE </TH> <TH BGCOLOR=GREEN> ANNO </TH> </TR> <!-Inserire codice ASP di popolazione tabella à </TABLE> Tale codice equivale a disegnare una tabella con la sola intestazione, senza dati: TITOLOREGISTAATTOREANNO Ora inseriamo, in luogo del commento, il codice VBScript per la scritture delle righe della tabella: <% while (rsElenco.EOF<>True) %> <TR> <TD> <%=rsElenco("TITOLO")%> </TD> <TD> <%=rsElenco("regista_Nome")%> &nbsp; <%=rsElenco("regista_Cogn")%> </TD> <TD> <%=rsElenco("attore_Nome")%> &nbsp; <%=rsElenco("attore_Cogn")%> </TD> <TD> <%=rsElenco("ANNO")%> </TD> </TR> <% rsElenco.MoveNext wend %> Ora avremo la nostra visualizzazione. Non dimentichiamoci, però, di chiudere e distruggere gli oggetti Connection e Recordset che altrimenti resterebbero in memoria: <% set rsElenco = Nothing set myConn = Nothing %> L’effetto finale sarà del tipo seguente: TITOLOREGISTAATTOREANNOLa dolce vitaFederico FelliniMarcello Mastroianni1958C’era una volta in AmericaSergio LeoneRobert De Niro1982Harry a pezziWoody AllenWoody Allen1998 E’ ovviamente possibile inserire dati in un database remoto attraverso, per esempio una form, come esemplificato più avanti. PAGINA PER L'INVIO DEI DATI <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> <title>INSERIMENTO DI DATI IN UN DATABASE</title> </head> <body style="font-family: verdana; font-size: 10pt"> <h2 align="center">INSERIMENTO DI DATI IN UN DATABASE</h2> <p>Questo esempio consente di inserire i dati un database.</p> <form method="POST" action="Inserimento1b.asp"> <p>Nome: <input type="text" name="nome" size="20"></p> <p>Cognome: <input type="text" name="cognome" size="20"></p> <p>Email: <input type="text" name="email" size="20"></p> <p><input type="submit" value="Salva i dati nel database"></p> </form> </body> </html> PAGINA PER IL SALVATAGGIO DEI DATI <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> <title>INSERIMENTO DI DATI IN UN DATABASE</title> </head> <body style="font-family: verdana; font-size: 10pt"> <h2 align="center">INSERIMENTO DI DATI IN UN DATABASE</h2> <p>Questo esempio consente di inserire i dati un database.</p> <% on error resume next nome = Request.form("nome") cognome = Request.form("cognome") email = Request.form("email") dim conn dim rs set conn = Server.CreateObject("ADODB.Connection") set rs = Server.CreateObject("ADODB.Recordset") conn.Open "tutorial", "", "" SQL = "INSERT INTO insertData (nome, cognome, email) " SQL = SQL & "VALUES ('" & nome & "','" & cognome & "','" & email & "')" rs.Open SQL, conn If err.number>0 then response.write "<p>¼ - Attenzione, hai commesso un errore nello script, controlla e riprova.</P>" elseif conn.errors.count> 0 then response.write "<p>Attenzione!</P>" response.write "<p>I dati inseriti non sono corretti, controllare se i campi obbligatori sono stati compilati.</P>" Else response.write "<p>Ok, i dati sono stati inseriti correttamente!!!!</p>" End if conn.Close %> <hr> <p> <% Response.Write("<a href="""&Request.ServerVariables("HTTP_REFERER")&""">Torna alla pagina precedente</a>") %> </p> </body> </html>