SqlDataSourceEnumerator.Instance.GetDataSources () не находит локальный экземпляр SQL Server 2008 - PullRequest
4 голосов
/ 26 июля 2011

Я использую следующий код для перечисления всех удаленных и локальных экземпляров 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 (версия 10.0.1600).

Я провел много исследований в Интернете и убедился, что 1 - Sql Broswer работает и 2 - UDP-порт 1434 открыт.

Кто-нибудь знает почему? Спасибо.

Ответы [ 4 ]

16 голосов
/ 26 июля 2011

Вы пропускаете серверы, которые не являются именованными экземплярами.Измените свой код:

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 выключен
  • Не находит SQL-серверы, если они скрыты
  • Содержание списка не гарантируется для повторения (из-затайм-аутам).Фактически, последующий вызов может дать другой список в зависимости от сетевого ввода-вывода, производительности сервера, количества серверов в сети и других ограничений, зависящих от времени

Некоторые источники говорят, что вынеобходимо сделать 2 вызова SqlDataSourceEnumerator.Instance.GetDataSources() ...

Refs:

8 голосов
/ 28 июля 2011

Большое спасибо Митчу за его великолепный ответ. Однако то, что я сделал в конечном итоге, выглядит следующим образом:

У меня есть два отдельных метода для получения локального и удаленного экземпляра сервера соответственно. Локальные экземпляры извлекаются из реестра. Вам необходимо выполнить поиск по кустам WOW64 и WOW3264, чтобы получить 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 голосов
/ 09 июня 2016

Что-то, что люди должны знать о методах GetDataSources и SqlDataSourceEnumerator. Если имя экземпляра используется по умолчанию, имя экземпляра будет пустым! [Почему .. Я не знаю, почему я не могу указать многословно, тоже не знаю, но парень из MS, который написал это ...

ServerName: имя сервера.

InstanceName: имя экземпляра сервера. Пусто, если сервер работает как экземпляр по умолчанию.

IsClustered Указывает, является ли сервер частью кластера.

Версия Версия сервера (8.00.x для SQL Server 2000 и 9.00.x для SQL Server 2005).

ОТ ЗДЕСЬ: https://msdn.microsoft.com/en-us/library/system.data.sql.sqldatasourceenumerator.getdatasources(v=vs.110).aspx

1 голос
/ 10 ноября 2017
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();
...