SqlDataSourceEnumerator.Instance.GetDataSources()找不到本地SQL Server 2008实例

我使用以下代码列出所有远程和本地SQL Server实例:

public static void LocateSqlInstances() { using( DataTable sqlSources = SqlDataSourceEnumerator.Instance.GetDataSources()) { foreach(DataRow source in sqlSources.Rows ) { string instanceName = source["InstanceName"].ToString(); if (!string.IsNullOrEmpty(instanceName)) { Console.WriteLine(" Server Name:{0}", source["ServerName"]); Console.WriteLine(" Instance Name:{0}", source["InstanceName"]); Console.WriteLine(" Version:{0}", source["Version"]); Console.WriteLine(); } } Console.ReadKey(); } } 

在我的本地计算机上运行代码。 代码可以查找并列出已安装但未列出其他SQL Server实例(版本10.0.1600)的SQL Server express实例(版本9.0.5000)。

我已经在互联网上做了很多研究,并确保1-Sql Broswer正在运行,2 – UDP端口1434是开放的。

谁知道为什么? 谢谢。

您正在跳过未命名实例的服务器。 修改你的代码:

 public static void LocateSqlInstances() { using (DataTable sqlSources = SqlDataSourceEnumerator.Instance.GetDataSources()) { foreach (DataRow source in sqlSources.Rows ) { string servername; string instanceName = source["InstanceName"].ToString(); if (!string.IsNullOrEmpty(instanceName)) { servername = source["InstanceName"] + '\\' + source["ServerName"]; } else { servername = source["ServerName"]; } Console.WriteLine(" Server Name:{0}", servername ); Console.WriteLine(" Version:{0}", source["Version"]); Console.WriteLine(); } Console.ReadKey(); } } 

请注意: SqlDataSourceEnumerator.Instance.GetDataSources()有缺点:

  • 受防火墙规则限制(阻止的TCP / IP 1433和UDP 1434)
  • 如果SQL浏览器关闭,则找不到SQL Server
  • 如果隐藏了SQL Server,则找不到它们
  • 列表内容不保证可重复(由于超时)。 实际上,根据网络I / O,服务器性能,网络上的服务器数量以及其他与时间相关的约束,后续调用很可能会给出不同的列表。

有几个消息来源说你必须对SqlDataSourceEnumerator.Instance.GetDataSources()进行2次调用…

参考文献:

  • SqlDataSourceEnumerator.Instance; 没有返回所有实例
  • EnumAvailableSqlServers或SqlDataSourceEnumerator – 可用数据库的错误列表
  • 枚举SQL Server
  • 以编程方式列出SQL Server

非常感谢Mitch,他给出了很好的答案。 但是,我最终完成的工作如下:

我有两个单独的方法分别获取本地和远程服务器实例。 从注册表中检索本地实例。 您需要搜索WOW64和WOW3264配置单元以获取SQL Server 2008(64位)和SQL Server Express(32位)

这是我使用的代码:

 ///  /// get local sql server instance names from registry, search both WOW64 and WOW3264 hives ///  /// a list of local sql server instance names public static IList GetLocalSqlServerInstanceNames() { RegistryValueDataReader registryValueDataReader = new RegistryValueDataReader(); string[] instances64Bit = registryValueDataReader.ReadRegistryValueData(RegistryHive.Wow64, Registry.LocalMachine, @"SOFTWARE\Microsoft\Microsoft SQL Server", "InstalledInstances"); string[] instances32Bit = registryValueDataReader.ReadRegistryValueData(RegistryHive.Wow6432, Registry.LocalMachine, @"SOFTWARE\Microsoft\Microsoft SQL Server", "InstalledInstances"); FormatLocalSqlInstanceNames(ref instances64Bit); FormatLocalSqlInstanceNames(ref instances32Bit); IList localInstanceNames = new List(instances64Bit); localInstanceNames = localInstanceNames.Union(instances32Bit).ToList(); return localInstanceNames; } 

 public enum RegistryHive { Wow64, Wow6432 } public class RegistryValueDataReader { private static readonly int KEY_WOW64_32KEY = 0x200; private static readonly int KEY_WOW64_64KEY = 0x100; private static readonly UIntPtr HKEY_LOCAL_MACHINE = (UIntPtr)0x80000002; private static readonly int KEY_QUERY_VALUE = 0x1; [DllImport("advapi32.dll", CharSet = CharSet.Unicode, EntryPoint = "RegOpenKeyEx")] static extern int RegOpenKeyEx( UIntPtr hKey, string subKey, uint options, int sam, out IntPtr phkResult); [DllImport("advapi32.dll", SetLastError = true)] static extern int RegQueryValueEx( IntPtr hKey, string lpValueName, int lpReserved, out uint lpType, IntPtr lpData, ref uint lpcbData); private static int GetRegistryHiveKey(RegistryHive registryHive) { return registryHive == RegistryHive.Wow64 ? KEY_WOW64_64KEY : KEY_WOW64_32KEY; } private static UIntPtr GetRegistryKeyUIntPtr(RegistryKey registry) { if (registry == Registry.LocalMachine) { return HKEY_LOCAL_MACHINE; } return UIntPtr.Zero; } public string[] ReadRegistryValueData(RegistryHive registryHive, RegistryKey registryKey, string subKey, string valueName) { string[] instanceNames = new string[0]; int key = GetRegistryHiveKey(registryHive); UIntPtr registryKeyUIntPtr = GetRegistryKeyUIntPtr(registryKey); IntPtr hResult; int res = RegOpenKeyEx(registryKeyUIntPtr, subKey, 0, KEY_QUERY_VALUE | key, out hResult); if (res == 0) { uint type; uint dataLen = 0; RegQueryValueEx(hResult, valueName, 0, out type, IntPtr.Zero, ref dataLen); byte[] databuff = new byte[dataLen]; byte[] temp = new byte[dataLen]; List values = new List(); GCHandle handle = GCHandle.Alloc(databuff, GCHandleType.Pinned); try { RegQueryValueEx(hResult, valueName, 0, out type, handle.AddrOfPinnedObject(), ref dataLen); } finally { handle.Free(); } int i = 0; int j = 0; while (i < databuff.Length) { if (databuff[i] == '\0') { j = 0; string str = Encoding.Default.GetString(temp).Trim('\0'); if (!string.IsNullOrEmpty(str)) { values.Add(str); } temp = new byte[dataLen]; } else { temp[j++] = databuff[i]; } ++i; } instanceNames = new string[values.Count]; values.CopyTo(instanceNames); } return instanceNames; } } SqlDataSourceEnumerator.Instance.GetDataSources() is used to get remote sql server instances. 

最后,我只是合并远程实例列表和本地实例列表以生成最终结果。

人们需要了解GetDataSources和SqlDataSourceEnumerator的方法。 如果实例名称是默认值 – InstanceName将为空! [为什么……我不知道,为什么我不能指定详细,不知道那个,但MS写的那个人…… arrrgh]

ServerName:服务器的名称。

InstanceName:服务器实例的名称。 如果服务器作为默认实例运行,则为空。

IsClustered指示服务器是否是群集的一部分。

版本服务器版本(SQL Server 2000为8.00.x,SQL Server 2005为9.00.x)。

从这里: https : //msdn.microsoft.com/en-us/library/system.data.sql.sqldatasourceenumerator.getdatasources(v = vs.110).aspx

 var registryViewArray = new[] { RegistryView.Registry32, RegistryView.Registry64 }; foreach (var registryView in registryViewArray) { using (var hklm = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, registryView)) using (var key = hklm.OpenSubKey(@"SOFTWARE\Microsoft\Microsoft SQL Server")) { var instances = (string[]) key?.GetValue("InstalledInstances"); if (instances != null) { foreach (var element in instances) { if (element == "MSSQLSERVER") Console.WriteLine(System.Environment.MachineName); else Console.WriteLine(System.Environment.MachineName + @"\" + element); } } } } Console.ReadKey();