Visual Basic Simple
Lettura di un DataBase Remoto con ADO tramite XML
Sincronizza Indice
Sincronizza Indice
Scarica il progetto
Scarica il progetto
Scarica il testo dell'articolo
Testo dell'articolo
Stampa l'articolo
Stampa l'articolo
Ricerca personalizzata

Richiesta di: Antonio - 16 Giugno 2001
Difficoltà: 4 / 5

Come fare per leggere il contenuto di una tabella che si trova su un sito Internet remoto?


Questo articolo implementa una soluzione sviluppata da Moreno Sirri e pubblicata sul suo sito (http://www.msvbsite.net).

Con il sempre più crescente sviluppo della tecnologia Microsoft COM (Component Object Model) aumentano i programmi che utilizzano risorse distribuite su vari server.
Le ultime versioni di ADO (ActiveX Data Objects) permettono l'apertura di un Recordset senza connessione attraverso la chiamata di un indirizzo Internet HTTP o FTP. Naturalmente è necessario che l'indirizzo Internet richiamato restituisca in uscita un Recordset.
Nota bene: abbiamo detto Recordset, non Database. Non dovremo inserire la posizione in cui si trova l'archivio dati ma dovremo provvedere una sequenza dati in una forma comprensibile all'ADO.

Tale forma di scambio di dati è l'XML (Extended Markup Language), un linguaggio di marcatura in grado di trasferire dati di qualunque genere, nato come evoluzione dell'HTML utilizzato per disegnare le pagine Web.

Il nostro progetto si compone di due parti: la prima è scritta in ASP (Active Server Pages) e servirà come interfaccia tra il nostro programmino scritto in VB ed il database remoto. La pagina ASP interrogherà il Database per noi e restituirà un Recordset XML. Il nome del Recordset richiesto sarà passato attraverso il metodo GET.
La seconda parte è un semplicissimo programma in Visual Basic che richiama la pagina ASP sul server e mostra in una griglia il contenuto del Recordset ricevuto.
Iniziamo a vedere il codice della pagina ASP:

  1. <%
  2.   Option Explicit
  3.   Const adLockPessimistic = 2
  4.   Const adOpenkeyset = 1
  5.   Const adPeRSistXML = 1
  6.   Const adStateOpen = 1
  7.   Const adVarChar = 200
  8.   Const adInteger = 3
  9.   Const NOMEDB = "Libri.mdb"
  10.   Dim CONN
  11.   Dim RS
  12.   Dim XMLStream

Alle righe 3-8 sono dichiarate alcune costanti di ADO. In Visual Basic normalmente non sono ncessarie, ma poiché stiamo utilizzando ASP esse non sono presenti. Suppliamo alla loro mancanza dichiarandole manualmente.
Alla riga 9 dichiariamo la variabile NOMEDB che conterrà il nome del database da aprire nella cartella in cui si trova la nostra pagina ASP.

Seguono le dichiarazioni di tre variabili: CONN sarà la connessione al database da aprire, RS sarà il Recordset che verrà aperto dalla connessione ed i cui dati saranno restituiti alla chiamata della pagina ASP; XMLStream è invece uno stream che verrà utilizzato per trasformare il Recordset in XML da inviare al browser.

  1.   On Error Resume Next
  2.   Set RS = Server.CreateObject("ADODB.Recordset")
  3.   Set CONN = Server.CreateObject("ADODB.Connection")
  4.   CONN.ConnectionString = "Driver={Microsoft Access Driver (*.mdb)}; DBQ=" & Server.MapPath(NOMEDB)
  5.   CONN.Open
  6.   RS.Open "SELECT * FROM " & Request.QueryString("TableName"), CONN, adOpenkeyset, adLockPessimistic

È necessario dedicare una nota particolare alla possibilità che si verifichi un errore durante l'apertura del Recordset richiesto. Dall'altro lato dell'applicazione si trova un programmino Visual Basic, che si aspetta comunque dei dati in una forma corretta. Sarà pertanto necessario verificare la presenza di errori ed in questo caso restituire comunque un Recordset. Ecco perché alla riga 14 abbiamo inserito la funzione di gestione degli errori.

Istanziate le due variabili CONN ed RS, segue la normale sequenza di istruzioni per l'apertura di una connessione ADO e del Recordset richiesto (righe 17-19).

  1.   If Err Then
  2.     If RS Is Nothing Then Set RS = Server.CreateObject("ADODB.Recordset")
  3.     With RS
  4.       If .State = adStateOpen Then .Close
  5.       .Fields.Append "Type", adVarChar, 9
  6.       .Fields.Append "Source", adVarChar, 50
  7.       .Fields.Append "Description", adVarChar, 255
  8.       .Fields.Append "Code", adInteger
  9.       .Source = ""
  10.       .ActiveConnection = Nothing
  11.       .Open
  12.       .AddNew
  13.       .Fields("Type") = "##Error##"
  14.       .Fields("Source")= Err.Source
  15.       .Fields("Description") = Server.URLEncode(Err.Description)
  16.       .Fields("Code") = Err.Number
  17.       .Update
  18.     End With
  19.   End If
  20.   On Error Goto 0

Nel caso che si verifichi un errore, faremo in modo che la pagina restituisca comunque un Recordset valido contenente il messaggio di errore generato.

Alla riga 21 viene istanziato il Recordset se la precedente istanza ha avuto esito negativo. Se il Recordset RS arriva aperto, sarà chiuso per permettere la modifica della struttura.

Saranno aggiunti quattro campi (Type, Source, Description e Code), viene aperto il Recordset, vengono aggiunti dei dati che indicano l'errore che si è verificato (righe 24-36).

Solo allora viene rimpossa la funzione di gestione degli errori. Dalla riga 39 in poi tutti gli errori che si saranno verificati non saranno controllati. L'ideale sarebbe di creare una nuova sezione di codice per la gestione dei nuovi errori.

  1.   Set XMLStream = Server.CreateObject("ADODB.Stream")
  2.   RS.Save XMLStream, adPersistXML
  3.   RS.Close
  4.   CONN.Close
  5.   Set RS = Nothing
  6.   Set CONN = Nothing
  7.   Response.ContentType = "text/xml"
  8.   Response.Write XMLStream.ReadText
  9.   XMLStream.Close
  10.   Set XMLStream = Nothing
  11. %>

Alla riga 40 viene istanziato lo Stream. Alla riga successiva viene salvato il Recordset RS all'interno dello stream XMLStream; la costante adPersistXML identifica il tipo di salvataggio (in XML quindi). Alle righe 42-45 vengono chiusi e deallocati Recordset e connessione.

Completiamo il nostro programmino ASP con la restituzione dei dati al chiamante. Viene innanzitutto definito il tipo di dati restituiti (riga 46) e poi viene restituito il contenuto di XMLStream, prima di chiuderlo e deallocarlo.

Se richiamassimo questa pagina ASP mediante un browser riceveremmo un Recordset XML da esplorare. Nel nostro caso abbiamo invece un semplice programma scritto in Visual Basic; vediamolo:

Figura 1
Figura 1

Il progetto farà uso di ADO 2.6 e pertanto sarà necessario aggiungere tale libreria alla lista dei riferimenti del progetto. Il form contiene solo 4 controlli. Il primo di questi è una Microsoft FlexGriddi nome Griglia, che occupa quasi la totalità della superficie del form. Gli altri controlli sono una Labeldi nome URLLabel, una TextBoxdi nome URLText ed un CommandButtondi nome ApriDBRemoto.
Il codice è molto semplice:

  1. Option Explicit
  2. Private Sub ApriDBRemoto_Click()
  3.   Dim RS As ADODB.Recordset
  4.   Dim Y As Integer
  5.   Dim X As Integer
  6.   On Error GoTo ERRORE
  7.   Set RS = New ADODB.Recordset
  8.   RS.Open URLXML.Text

Nel momento in cui l'utente clicca sul pulsante ApriDBRemoto viene avviata la connessione al sito Internet remoto. Il suo funzionamento è molto semplice.

Alla riga 4 dichiariamo un Recordset di nome RS e lo allochiamo alla riga 9. Tutti gli errori saranno gestiti (riga 8) dalla sezione di codice identificata con l'etichetta ERRORE.

Alla riga 10 viene effettuata l'apertura del Recordset, fornendo come origine della tabella l'indirizzo Internet presente nella TextBox URLXML.
La pagina chiamata dovrà restituire un Recordset XML altrimenti verrà generato un errore.

  1.   If (RS.Fields(0).Name = "Type") And (RS.Fields(1).Name = "Source") Then Err.Raise RS.Fields("CODE").Value, RS.Fields("SOURCE").Value, RS.Fields("DESCRIPTION").Value
  2.   Griglia.Clear
  3.   Griglia.Cols = RS.Fields.Count
  4.   Griglia.Rows = RS.RecordCount + 1
  5.   For X = 1 To RS.RecordCount
  6.     For Y = 0 To RS.Fields.Count - 1
  7.       If X = 1 Then Griglia.TextMatrix(0, Y) = RS.Fields(Y).Name
  8.       Griglia.TextMatrix(X, Y) = RS.Fields(Y).Value & ""
  9.     Next Y
  10.     RS.MoveNext
  11.   Next
  12.   RS.Close
  13.   Set RS = Nothing
  14.   Exit Sub

Ricordiamoci cosa faceva la nostra pagina ASP nel momento in cui si verificava un errore! Essa creava un Recordset contenente quattro campi e li riempiva con i dati dell'errore generato.

Pertanto alla riga 11 viene verificato se i primi due campi del Recordset ricevuto si chiamano Type e Source. In tal caso viene generato volontariamente un errore con i dati presenti nel Recordset. L'errore sarà gestito dalla funzione apposita.

Solo allora sarà possibile azzerare la Griglia e riempirla con i dati ricevuti. Dopo aver preparato righe e colonne, verranno utilizzati due cicli per estrarre i dati dal Recordset (righe 12-21).
Per la prima riga soltanto, sarà eseguita un'istruzione aggiuntiva, che riempie oltre le celle della griglia, anche le intestazioni della colonna (riga 17).

La procedura si conclude con la chiusura e deallocazione del Recordset RS.

  1. ERRORE:
  2.   MsgBox "Si è verificato un errore." & vbNewLine & Err.Description, vbCritical Or vbOKOnly, "DB Remoto"
  3.   If RS.State = adStateOpen Then RS.Close
  4.   Set RS = Nothing
  5. End Sub

Se si dovesse verificare un errore sarà mostrata una finestra di dialogo con la descrizione dell'errore (riga 26) e se il Recordset è ancora aperto sarà chiuso prima di essere deallocato.

  1. Private Sub Form_Unload(Cancel As Integer)
  2.   MsgBox "Il presente codice è stato sviluppato sulla base di un codice di Moreno Sirri" & vbNewLine & "Moreno Sirri VB Site - http://www.msvbsite.net", vbInformation + vbOKOnly, Me.Caption
  3. End Sub
  4. Private Sub Griglia_DblClick()
  5.   Griglia.Clear
  6. End Sub
  7. Private Sub URLXML_KeyPress(KeyAscii As Integer)
  8.   If KeyAscii = 13 Then KeyAscii = 0
  9. End Sub

Seguono tre semplicissime funzioni non fondamentali, ma utili. La prima mostra un avviso sull'autore del codice originale, per rispettare le regole di copyright presenti nella pagina da cui viene fatto spunto per questo esempio (riga 31-33).

Nel momento in cui l'utente clicca due volte sulla griglia essa sarà azzerata. La sua funzione si rivela utile prima di richiedere una nuova pagina, per verificare se i dati sono stati effettivamente aggiornati (righe 35-37).

L'ultima funzione blocca la pressione del tasto Invio nella casella URLXML, in modo da non generare un indirizzo Internet con un carattere di Invio inserito in mezzo (righe 39-41).

Figura 2
Figura 2

Possiamo passare alla prova del programma, molto semplice.
Abbiamo richiamato la nostra pagina ASP richiedendo l'indirizzo della pagina seguito dal parametro Tablename=libri. Essa richiederà l'apertura della tabella LIBRI che sarà mostrata nella griglia.

Figura 3Se si dovesse generare un errore, sarà mostrato un avviso di errore che, purtroppo, conterrà tantissimi caratteri incomprensibili a causa della diversa codifica tra Visual Basic e Internet.

Figura 4È molto interessante notare che è possibile anche salvare i Recordset XML in files con estensione XML e poi richiamarli fornendo semplicemente l'indirizzo Internet della pagina XML salvata.

Questa soluzione si rivela molto utile per alleggerire il lavoro del server e per poter utilizzare anche connessioni a database remoti quando il server ASP è inutilizzabile o non disponibile. Sarà possibile infatti inserire pagine XML statiche anche in server che non supportano ASP.

Il progetto è soltanto la punta di un grosso iceberg e mediante soluzioni di questo genere è possibile creare anche applicazioni di una certa grandezza ed importanza. In questo esempio è stata effettuata la sola lettura del Recordset originale ma con questa stessa tecnica è possible anche effettuare modifiche di dati sul server remoto.

La gestione degli errori è molto rozza e presenta numerose pecche.
Inoltre, la diversa codifica tra Internet e Visual Basic fa sì che non sia possible restituire Recordset contenenti caratteri accentati o altri simboli senza effettuare la codifica Internet. Tale codifica renderà però i dati illeggibili al client a meno di sviluppare una funzione di decodifica (non molto complessa comunque).

Moreno Sirri e Fibia FBI
Basato su: Gestione di un Database Remoto
18 Giugno 2001

Scarica il progetto
Scarica il progetto
Scarica il testo dell'articolo
Scarica il testo dell'articolo
Stampa l'articolo
Stampa l'articolo
Torna all'introduzione delle Richieste dei lettori