Esistono molti metodi per ottenere programmaticamente informazioni utili circa le istanze di SQL Server disponibili sia localmente che in rete anche se, in quest’ultimo caso, non tutti garantiscono il corretto funzionamento dal momento che possono entrare in gioco fattori difficilmente prevedibili e arginabili legati solitamente all’infratruttura di security della rete piuttosto che alla configurazione delle varie istanze di SQL Server.
Ad ogni modo, in nostro soccorso corrono le ormai famigerate API conosciute con l’acronimo di Smo (SQL Server Management Objects), che permettono di interagire con versioni di SQL Server dalla 7 in poi.
Il primo passo da effettuare è dunque l’importazione nel nostro progetto del namespace Microsoft.SqlServer.Management.Smo tramite la ‘reference’ alle librerie Microsoft.SqlServer.Smo.dll e Microsoft.SqlServer.ConnectionInfo.dll. A questo punto, un primo metodo percorribile (e facilmente opinabile) permette di enumerare la lista delle istanze (locali e non) registrate in SQL Server Management Studio tramite il metodo EnumRegisteredServers di SmoApplication:
using Microsoft.SqlServer.Management.Smo.RegisteredServers;
…
RegisteredServer[] servers = SmoApplication.SqlServerRegistrations.EnumRegisteredServers();
foreach (RegisteredServer server in servers) Console.WriteLine(server.ServerInstance);
Un’ altra soluzione teoricamente più flessibile e completa è data dall’utilizzo del metodo EnumAvailableSqlServers (anch’esso contenuto nell’oggetto SmoApplication), il quale restituisce un DataTable contenente una riga per ciascuna istanza raggiungibile sia in locale che in rete, a seconda dell’ overload specificato. Ad esempio, il seguente codice stampa a video le istanze di SQL Server (dalla 7 in poi) disponibili in rete:
…
DataTable availableServersDT = SmoApplication.EnumAvailableSqlServers(true);
foreach (DataRow drow in availableServersDT.Rows)
{
Console.WriteLine("Name:" + drow[0].ToString());
Console.WriteLine("Server:" + drow[1].ToString());
Console.WriteLine("Instance:" + drow[2].ToString());
Console.WriteLine("IsClustered:" + drow[3].ToString());
Console.WriteLine("Version:" + drow[4].ToString());
Console.WriteLine("IsLocal:" + drow[5].ToString());
}
Poiché l’implementazione di questo metodo è basato su un broadcast UDP (con tanto di timeout), è possibile che alcuni server non rispondano in tempo alla richiesta di discovery o addirittura non rispondano affatto (qualora, ad esempio, SQL Browser fosse arrestato, oppure se la porta UDP 1434 (default) fosse bloccata da un firewall… o, nel peggiore dei casi, se un’istanza di SQL Server fosse impostata come "hidden").
Un’ altra alternativa percorribile inoltre è data dalla scansione del registry alla ricerca della chiave InstalledInstances situata in HKLM\SOFTWARE\Microsoft\Microsoft SQL Server:
string[] SQLServerInstances = (string[])registry_key.GetValue("InstalledInstances");
if (SQLServerInstances.Length > 0)
{
foreach (string instance in SQLServerInstances)
{
if (instance == "MSSQLSERVER") Console.WriteLine(System.Environment.MachineName);
else Console.WriteLine(System.Environment.MachineName + @"\" + instance);
}
}
L’eventuale grosso limite di questa scelta si trova chiaramente nel fatto che reperisce soltanto le istanze di SQL Server installate sulla macchina locale.
E’ dunque evidente come una buona metodologia per ottenere maggiori informazioni possibile sulle istanze di SQL Server disponibili e raggiungibili sia in locale che in rete si trova nell’ opportuna combinazione di questi o altri metodi…. Ma ovviamente queste sono delle considerazioni che vanno valutate poi caso per caso 😉