System.Data.Sql.SqlDataSourceEnumerator.Instance.GetDataSources() 返回包含可見 SQL Server 實例資訊的 DataTable。
| 欄位名稱 | 型別 | 說明 |
|---|---|---|
| ServerName | string | 伺服器名稱 (機器名或 IP) |
| InstanceName | string | 實例名稱 (預設實例為空/NULL) |
| IsClustered | bool | 是否叢集 |
| Version | string | 版本號 (如 15.0.2000.5 → SQL 2019) |
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="SqlInstanceEnumerator.aspx.cs" Inherits="Demo.SqlInstanceEnumerator" %>
<html>
<head runat="server"><title>SQL Server 實例列舉</title></head>
<body>
<form id="form1" runat="server">
<h2>可用 SQL Server 實例</h2>
<asp:DropDownList ID="ddlInstances" runat="server" Width="400px"
AutoPostBack="true" OnSelectedIndexChanged="ddlInstances_SelectedIndexChanged">
<asp:ListItem Text="-- 請選擇實例 --" Value="" />
</asp:DropDownList>
<br /><br />
<asp:Label ID="lblDetail" runat="server" ForeColor="Blue" />
</form>
</body>
</html>
using System;
using System.Data;
using System.Data.Sql;
public partial class SqlInstanceEnumerator : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
LoadSqlInstances();
}
}
private void LoadSqlInstances()
{
try
{
DataTable instances = SqlDataSourceEnumerator.Instance.GetDataSources();
foreach (DataRow row in instances.Rows)
{
string serverName = row["ServerName"]?.ToString() ?? "";
string instanceName = row["InstanceName"]?.ToString() ?? "";
string version = row["Version"]?.ToString() ?? "";
bool isClustered = Convert.ToBoolean(row["IsClustered"]);
string displayName = string.IsNullOrEmpty(instanceName)
? serverName
: $"{serverName}\\{instanceName}";
if (!string.IsNullOrEmpty(version))
displayName += $" (v{version})";
if (isClustered)
displayName += " [Clustered]";
ddlInstances.Items.Add(new ListItem(displayName, $"{serverName}|{instanceName}"));
}
if (ddlInstances.Items.Count == 1) // 只有預設項
{
ddlInstances.Items.Add(new ListItem("未偵測到實例 (可能被防火牆/瀏覽服務封鎖)", ""));
}
}
catch (Exception ex)
{
lblDetail.Text = $"列舉失敗: {ex.Message}";
// 記錄日誌
}
}
protected void ddlInstances_SelectedIndexChanged(object sender, EventArgs e)
{
if (ddlInstances.SelectedIndex > 0)
{
string[] parts = ddlInstances.SelectedValue.Split('|');
string server = parts[0];
string instance = parts.Length > 1 ? parts[1] : "";
lblDetail.Text = $"已選擇: {server} { (string.IsNullOrEmpty(instance) ? "(預設實例)" : $"\\{instance}") }";
// 可進一步測試連線、建立連接字串等
string connStr = string.IsNullOrEmpty(instance)
? $"Server={server};Database=master;Integrated Security=true;"
: $"Server={server}\\{instance};Database=master;Integrated Security=true;";
Session["SelectedConnStr"] = connStr;
}
else
{
lblDetail.Text = "";
}
}
}
// 列舉可能耗時數秒,建議非同步 + 快取
private static readonly MemoryCache _cache = MemoryCache.Default;
private const string CacheKey = "SqlInstancesCache";
public async Task GetSqlInstancesAsync(bool forceRefresh = false)
{
if (!forceRefresh && _cache.Contains(CacheKey))
return (DataTable)_cache.Get(CacheKey);
return await Task.Run(() =>
{
var dt = SqlDataSourceEnumerator.Instance.GetDataSources();
_cache.Set(CacheKey, dt, DateTimeOffset.Now.AddMinutes(10)); // 快取 10 分鐘
return dt;
});
}
| 問題 | 原因 | 解決/替代 |
|---|---|---|
| 列舉結果為空 | SQL Browser 服務未啟動、防火牆封鎖 UDP 1434、網路隔離 | 啟動 SQL Browser、開放 UDP 1434、或手動輸入連接字串 |
| 僅顯示本機實例 | 跨網段廣播不通、域策略限制 | 手動配置、Central Management Servers、註冊表掃描 |
| 權限不足異常 | 應用程式池身分無列舉權限 | 授予適當權限、或改用註冊表讀取 (HKLM\Software\Microsoft\Microsoft SQL Server) |
| .NET Core / .NET 5+ 不支援 | SqlDataSourceEnumerator 僅限 .NET Framework | 改用 `Microsoft.Data.SqlClient` 的 `SqlDataSourceEnumerator` (支援 .NET Core 3.1+) |
// NuGet: Microsoft.Data.SqlClient
using Microsoft.Data.SqlClient;
var instances = SqlDataSourceEnumerator.Instance.GetDataSources();
// 相同 API,支援跨平台 (Windows/Linux/macOS)
using Microsoft.Win32;
public static List GetLocalInstalledInstances()
{
var instances = new List();
using (var hklm = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64))
using (var sqlKey = hklm.OpenSubKey(@"SOFTWARE\Microsoft\Microsoft SQL Server"))
{
if (sqlKey != null)
{
var installedInstances = sqlKey.GetValue("InstalledInstances") as string[];
if (installedInstances != null)
{
foreach (var instance in installedInstances)
{
instances.Add(instance.Equals("MSSQLSERVER", StringComparison.OrdinalIgnoreCase)
? Environment.MachineName
: $"{Environment.MachineName}\\{instance}");
}
}
}
}
return instances;
}
`SqlDataSourceEnumerator` 適合「選擇連線目標」的安裝精靈/配置頁面。生產環境連線字串應預先配置於 Web.config/Key Vault/環境變數,**避免運行時動態發現**。理解其依賴 SQL Browser 服務與 UDP 1434 廣播機制,有助於排查「列舉為空」的網路/防火牆問題。