versione italiana versione italiana
english version english version

ADO.NET & SQL Server 2000 (Parte 1/3)

System.Data.SqlClient è il namespace che contiene la definizione delle classi di ADO.NET che consentono l’accesso al database engine SQL Server 2000.

Infatti, pur ritenendo valide le idee che erano alla base della filosofia “Universal Data Access”, in Microsoft ci si è resi conto che la stragrande maggioranza delle applicazioni in architettura Windows DNA prevedevano come back-end il motore di SQL Server, e che per avere performance superiori era necessario creare una modalità “nativa” di accesso ai dati. Quindi, semplificando al massimo, è stata riprodotta nel Microsoft .NET Framework la stessa situazione architetturale che esisteva con la DBLibrary, cioè un accesso diretto che by-passa ogni strato superfluo di codice di sistema. Questo articolo si propone di mostrare lo strettissimo legame che esiste tra ADO.NET e SQL Server 2000, tralasciando momentaneamente la parte di supporto XML presente nel dabase engine, che verrà adeguatamente trattata in un successivo articolo.

 

Il Sql Server .NET Data Provider

 

Questo .NET Data Provider è stato realizzato completamente ex-novo, e non contiene nemmeno una riga di codice un-managed. Al suo interno, la presenza di un parser TDS (Tabular Data Stream, il formato di scambio dati che SQL Server utilizza da sempre), garantisce un accesso ottimizzato alle informazioni presenti nel database engine. A differenza dell’OleDb .NET Data Provider, che invece si basa sui servizi OLE DB già conosciuti ed utilizzati da ADO 2.x, e che con i suoi strati di interfacce (seppure ottimizzate) introduce un certo overhead. Queste considerazioni sono ancora più importanti se parliamo di codice che deve essere eseguito lato server, con tutte i requisiti di scalabilità richiesti, ad esempio, da una applicazione Web.

 

Fig.1 Architettura del SQL Server .NET Data Provider

 

Tutte le comunicazioni tra il processo client, che utilizza il SQL Server .NET Data Provider, e il database server avvengono sempre utilizzando le Network Libraries, le librerie che consentono a SQL Server di rimanere in ascoluto, su uno o più protocolli di trasporto dei pacchetti di rete, di frames TDS. Quante e quali Network Libraries vengono “attivate” lato server (in realtà vengono sempre installate tutte all’installazione del prodotto) lo si decide in fase di setup di SQL Server o successivamente attraverso l’utility chiamata “Server Network Utility”, che consente, tra le altre cose, anche di configurare la cifratura sui dati trasmessi. Esiste una net-lib di default che è la TCP/IP Socket per la l’edizione Standard e Advanced, mentre è Named Pipes per l’edizione Desktop Engine. Questa scelta è stata fatta in considerazione del fatto che la prima, definita anche “Super-Socket Library” è di gran lunga la più efficente. Esiste un problema però: questa net-lib richiede che venga caricato correttamente sulla macchina lo stack TCP/IP, altrimenti il client (anche processi client sulla stessa macchina) non può comunicare con il server, ecco il motivo per cui viene sempre abilitata di default anche la Named Pipes net-lib.

 

Lato client, invece, sulle macchine dove è stato installato il supporto a SQL Server, è presente una utility chiamata “Client Network Utility” che consente di abilitare e configurare le net-lib presenti. Altra possibilità è quella di specificare, attraverso l’attributo “Network Library=xxxxxxx” della stringa di connessione, direttamente dal client la net-lib da utilizzare. Ultima possibilità è quella di stabilire, configurando le relative chiavi del registry, qual’è la net-lib di default e quali sono i parametri di funzionamento.

Il consiglio spassionato di Microsoft, è comunque quello di utilizzare la TCP/IP Socket net-lib, date le funzionalità che espone (es. l’encryption basata su SSL) e soprattutto le performance.

 

SqlClient o SQL Server?

 

Vi siete chiesti il perchè dello strano nome dato al namespace all’interno del quale sono definite queste classi (System.Data.SqlClient)? Se il server si chiama SQL Server, perchè chiamare il namespace SqlClient? La spiegazione a questa decisione esiste, ed è molto interessante. Attualmente (.NET Framework v1.0) il namespace in questione contiene classi che non offrono nessun supporto “automatizzato” per la gestione di cursori lato server, cioè di strumenti interni al database engine capaci di operare in modalità row-oriented (crea il cursore, muoviti in avanti di un record, leggi il valore dei campi, ecc.), se non attraverso l’utilizzo di specifiche Stored Procedure (sp_cursor, sp_cursorclose, sp_cursorexecute, sp_cursorfetch, sp_cursoropen,ecc.) di sistema inviate attraverso l’oggetto SqlCommand. Ricordate cosa avveniva invece con ADO 2.x quando si otteneva dalla base dati un Recordset di tipo “Dynamic” o “Keyset” e non si selezionava specificatamente il valore adUseClient per la proprietà CursorLocation dell’oggetto Connection o dello stesso Recordset? Beh, ve lo rammento io: veniva creato un cursore lato server, pilotato dal client utilizzando i metodi trasparenti quali MoveNext, MovePrevious, ecc. Questa tecnica di accesso ai dati, seppur comoda per gestire tutte le funzionalità di locking e la concorrenza nelle operazioni sui dati, ha dato nel tempo rilevanti problemi di overhead nell’utilizzo delle risorse sul server.

 

Per questo MS ha sempre incoraggiato lo sviluppo di applicazioni “disconnesse” verso la fonte dati, che quindi potessero essere più “leggere” nell’utilizzo delle risorse del server. ADO.NET, nella sua prima versione, favorisce ulteriormente lo sviluppo di applicazioni di questo tipo ma, alcune voci interne a Microsoft, parlano già di un nuovo .NET Data Provider dedicato a SQL Server, che verrà individuato dal namespace System.Data.SqlServer e che conterrà di nuovo il supporto a codice che viene eseguito, in modalità managed,  all’interno del processo SQL Server nella prossima versione denominata in codice Yukon, per consentire operazioni avanzate quali le SP nei linguaggi .NET, il caricamento di set di dati in modalità non-logged, e così via.

 

La connessione a SQL Server

 

La classe SqlConnection è il punto di partenza dal quale inizieremo ad analizzare il SQL Server .NET Data Provider. Attraverso la definizione di questa classe è possibile interagire con SQL Server, andando a configurare, per esempio, il modo con il quale viene gestito il connection pooling o la modalità di autenticazione scelta dal client.

 

// Instanzio un nuovo oggetto SqlConnection
string scnn = “Server=localhost;Database=Northwind;Trusted_Connection=Yes”;
using(SqlConnection cnn = new SqlConnection(scnn))
{
try
{
                  // Apertura della connessione
cnn.Open();
                   // Eseguo le operazioni sul database...
}
catch(Exception e)
{
                  // gestisco l’eccezione
}
}

 

Da un punto di vista logico, questa classe rappresenta una sessione aperta tra il client e il database server o, a livello ancora più basso, una connessione di rete.

La caratteristica fondamentale di una SqlConnection è sicuramente la ConnectionString che può essere impostata utilizzando la relativa proprietà oppure passata come parametro al costruttore. Viene eseguito il parsing subito dopo l’assegnazione di un valore, quindi se qualcosa è errato viene generata una eccezione, tipicamente una ArgumentException. Questa operazione può essere eseguita solo a connessione non ancora aperta, oppure già chiusa, e provoca il reset di tutte le proprietà che vengono impostate dal contenuto della ConnectionString.

 

L’attributo Persist Security Info (default FALSE) provoca la persistenza della password, specificata in fase di apertura della connessione, all’interno della proprietà ConnectionString. Questo ovviamente può provocare un potenziale problema di sicurezza, ma in certe circostanze evita di dover ripassare ogni volta quella informazione. Attenzione anche a potenziali problemi di sicurezza derivanti dal costruire il valore della proprietà ConnectionString sulla base dell’input di un utente attraverso una DialogBox o simili. Infatti se l’utente immettesse una stringa del tipo “passwordvalida;Database=AltroDatabase” in una TextBox nella quale si richiede solo la password, e questo valore venisse concatenato ad una stringa che definiva già il database al quale collegarsi, la connessione verrebbe aperta verso il nuovo database, posto che l’utente utilizzato abbia i permessi per poterlo fare.

 

Ancora riguardo alla security, occorre dire che dal punto di vista delle performance l’utilizzo della sicurezza integrata con Windows (“Trusted_Connection=Yes” oppure “Integrated Security=SSPI”) provoca una leggera perdita delle performance in fase di autenticazione inizale rispetto all’utilizzo della security standard di SQL Server (“User ID=username;Pwd=1234”), anche se i benefici generali (non ultima la possibilità di non utilizzare una password da mettere da qualche parte) sono di gran lunga superiori. Gli altri attributi della ConnectionString sono:

 

Nome

Default

Descrizione

Application Name

'.Net SqlClient Data Provider'

Il nome della connessione aperta verso SQL Server.

AttachDBFilename

o

Initial File Name

 

Il nome del primary file (full path) di un database “attachable” al momento della apertura della connessione.

Connect Timeout

o

Connection Timeout

15 sec.

Il tempo timeout per l’esecuzione di una operazione verso SQL Server prima di terminare e generare una eccezione.

Connection Lifetime

0 sec. (timeout massimo)

Quando la connessione ritorna in un pool, viene verificato se la differenza tra quando è stata creata e l’istante corrente è maggiore del valore specificato, e nel caso viene distrutta. Utile in un ambiente cluster per velocizzare il passaggio da un server ad un’altro in caso di failover.

Connection Reset

'true'

Determina se la connessione viene resettata dopo che è stata eliminata da un pool. Settando questo valore a 'false' evita successivi round-trip verso il server in caso di riutilizzo, ma occorre essere consapevoli che lo stato della connessione non è stato resettato (es. security o altre info di connessione).

Current Language

 

Il tipo di linguaggio utilizzato per i messaggi di errore di SQL Server.

Data Source

o

Server

o

Address

o

Addr

o

Network Address

 

Il nome dell’istanza di SQL Server (Es. “SERVER\Istanza”) alla quale connettersi, o il suo indirizzo IP.

Enlist

'true'

Il pooler arruola automaticamente questa connessione nel contesto della transazione alla quale il thread corrente appartiene.

Initial Catalog

o

Database

 

Nome del database al quale connettersi.

Integrated Security

o

Trusted_Connection

'false'

Sicurezza integrata con Windows.

I valori possibili sono 'true', 'false', e 'sspi', che è equivalente a 'true'.

Max Pool Size

100

Numero massimo di connessioni permesse in un pool.

Min Pool Size

0

Numero minimo di connessioni permesse in un pool.

Network Library

o

Net

'dbmssocn'

La network library utilizzata per aprire la connessione con l’istanza di SQL Server. I valori possibili sono:

dbnmpntw(Named Pipes)

dbmsrpcn(Multiprotocol)

dbmsadsn(Apple Talk)

dbmsgnet(VIA)

dbmsipcn(Shared Memory)

dbmsspxn(IPX/SPX) dbmssocn(TCP/IP)

La net-lib deve essere installata sul sistema al quale si vuole connettersi. Se si specifica "(local)" o “localhost” di default viene utilizzata shared memory.

Packet Size

8192

Dimensione in bytes dei pacchetti TDS utilizzati per comunicare con SQL Server. Dimensioni possibili tra 512 Byte e 32Kb, da impostare a seconda del tipo di info che vengono scambiate. Di solito si lascia il default, ma in caso di scambio di blocchi di informazioni di grandi dimensioni (immagini, testi, ecc.) può essere utile aumentare il parametro per ridurre i round-trip.

Password

o

Pwd

 

La password utilizzata per la login standard di SQL Server specificata per la connessione.

Persist Security Info

'false'

Di default le informazioni riguardanti la security non vengono rese disponibili attraverso l’oggetto SqlConnection dopo che la connessione è stata aperta o resettata. Occorre fornirle di nuovo in caso di riapertura.

Pooling

'true'

Abilita il pooling per questa connessione.

User ID

 

La login standard di SQL Server utilizzata per la connessione.

Workstation ID

Nome della macchina locale

Il nome della workstation dalla quale si apre la connessione.