SqlDataSourceEnumerator.Instance.GetDataSources()无法定位本地的SQL Server 2008实例。

7
我使用以下代码列出所有远程和本地的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 Express实例(版本9.0.5000),但无法列出其他SQL Server实例(版本10.0.1600)。

我在互联网上进行了大量研究,并确保(1)Sql Browser正在运行,(2)UDP端口1434是开放的。

有人知道原因吗?谢谢。

4个回答

18

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

public class SqlServerInstance
{
    public string ServerInstance { get; set; }
    public string Version { get; set; } 
}

public static List<SqlServerInstance> LocateSqlInstances()
{
    List<SqlServerInstance> results = new List<SqlServerInstance>();

    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["ServerName"].ToString() + '\\' + instancename;
            }
            else
            {
                servername = source["ServerName"].ToString();
            }

            results.Add(new SqlServerInstance (){ ServerInstance = servername, Version = source["Version"].ToString() });
        }
    }

    return results;
}
请注意:SqlDataSourceEnumerator.Instance.GetDataSources() 有以下缺点:
  • 受防火墙规则限制(阻止 TCP/IP 1433 和 UDP 1434)
  • 如果 SQL 浏览器关闭,则无法找到 SQL 服务器
  • 如果隐藏了 SQL 服务器,则无法找到
  • 列表内容不保证可重复(由于超时)。实际上,后续调用很可能根据网络 I/O、服务器性能、网络上的服务器数量和其他时间相关限制而给出不同的列表。

几个来源都说您需要调用 SqlDataSourceEnumerator.Instance.GetDataSources() 2 次...

参考文献:


9
非常感谢Mitch提供的精彩答案。然而,最终我做的是以下内容:
我有两种单独的方法来获取本地和远程服务器实例。本地实例是从注册表中检索出来的。您需要同时搜索WOW64和WOW3264 hives以获取SQL Server 2008(64位)和SQL Server Express(32位)。
这是我使用的代码:
/// <summary>
  ///  get local sql server instance names from registry, search both WOW64 and WOW3264 hives
  /// </summary>
  /// <returns>a list of local sql server instance names</returns>
  public static IList<string> 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<string> localInstanceNames = new List<string>(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<String> values = new List<string>();

        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. 

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

3
Visual Studio无法识别函数:FormatLocalSqlInstanceNames(ref instances64Bit); FormatLocalSqlInstanceNames(ref instances32Bit); - Zag Gol
1
"FormatLocalSqlInstanceNames" 是什么作用?你能发一下代码吗? - yaronkl

3

GetDataSources和SqlDataSourceEnumerator的方法需要注意的事项。如果实例名称是默认的,实例名称将为空![为什么..我不知道,为什么不能指定详细信息,也不知道,但编写它的那个人...啊]

ServerName:服务器的名称。

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

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

Version:服务器的版本(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


1
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();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接