.NET SQL 連線對話框(Dialog)

  • 160
  • 0

System.Windows.Form 底下的 Dialog(對話框)很實用。程式能透過 Dialog 輔助使用者正確輸入 Y/N、檔案路徑甚至是字型、顏色。

如果有現成的輸入資料庫連線的 Dialog 就好了。我發現 Windows 對 .udl 檔有很親切的 UI 介面,會面面俱到地輔助連線設定,串一下就有現成的 Dialog 了

當手邊的 Windows 沒有裝 SSMS 等要額外安裝的工具又要測試連線時,有個超好用的小撇步。

只要右鍵新增文字檔再把 .txt 副檔名改成 .udl,再把檔案雙擊開啟就有現成的連線對話框。

功能完整,按 OK 之後就會存入 OLE DB 連線字串,可以用記筆本打開,如果是連 MSSQL 把頭尾去掉就能直接放到 SqlConnection 了。

最近想到這特性其實能直接變成 .NET 程式的對話框,關鍵要能抓到編輯結束使用者按下 OK 的事件。以下是實現這個想法的範例碼

void Main()
{
    var connStr = AskConnectionByUdl();
    if (connStr is null)
    {
        Console.WriteLine("null 可能是使用者沒按確定或輸入內容無法解析.");
    }
    else
    {
        Console.WriteLine($"成功透到 .udl GUI 取得連線字串:{connStr}");
    }
}

// Define other methods and classes here
/// <summary>
/// 利用 Windows 預設的 .udl 開啟方式來輸入連線資訊
/// </summary>
string AskConnectionByUdl()
{
    var udl = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.udl");
    udl.Dump("產生 .udl 在 temp 資料夾");
    var connStr = (string)null;

    try
    {
        var file = File.Open(udl, FileMode.OpenOrCreate);
        file.Dispose();

        // Windows 預設以 Ole DB Core Services 開啟 .udl
        var pro = Process.Start(udl);

        pro.WaitForExit();

        var udlText = File.ReadAllText(udl);
        Console.WriteLine($"使用者連線編輯結束.取得連線資訊(OLE):{udlText}");

        connStr = ConvertOle2Sql(udlText);
        return connStr;
    }
    finally
    {
        File.Delete(udl);
    }
}

/// <summary>
/// 只用簡單的字串處理來轉成 ADO SQL 連線字串
/// </summary>
string ConvertOle2Sql(string oleTxt)
{
    var oleStr = oleTxt.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries).LastOrDefault();
    if (string.IsNullOrEmpty(oleStr))
    {
        return null;
    }

    // modify config 
    var oleConn = oleStr;
    // to sql connection
    var connStr = oleConn.Split(new[] { ';' }, 2)[1];
    var last = connStr.IndexOf(";Initial File");
    if (last != -1) connStr = connStr.Substring(0, last);
    connStr = connStr.Replace(@"User ID="""";", "");
    var conb = new SqlConnectionStringBuilder(connStr);

    return conb.ToString();
}

只要用 Process 開啟 .udl 檔,再用 WaitForExit() 等待使用者結束編輯即可,剩下的就是讀取檔案做字串處理。

這段程式碼已經能應付大部分情境了。還有一些細節,加入之後會變很長。

例如上面這段程式只能跑在 .NET Framework 在 .NET Core 會跳錯,因為 Process 在 Core 的預設值不一樣 UseShellExecute 是 false,要在 Core 執行可以改用

var pro = Process.Start(new ProcessStartInfo() {UseShellExecute=true, FileName=udl});

UseShellExecute 開啟,會讓系統執行該副檔名預設的開啟方式,但如果不幸使用者改了 .udl 的預設變成記事本,那我們原本以為會開啟對話框,就會變成開啟記事本。

對這種狀況,要指定用 OLE DB Core Services 開啟,對應地副檔名就不用限定 .udl 了。

var args = @$"""C:\Program Files\Common Files\System\Ole DB\oledb32.dll"",OpenDSLFile {udl}";
var pro = pro = Process.Start("rundll32.exe", args);

上面這段 Code 只能用在 Windows,話雖如此我也並不知道 Linux 或 Mac 是否預裝有支援編輯 .udl 的應用。

範例只假設了 MSSQL 的情境,而且對其它類型的連線沒有防呆,如果要防呆要檢查 OLE DB 字串的 Provider 屬性,目前已知的 MSSQL 的 Provider 分別是 MSOLEDBSQLSQLOLEDBSQLNCLI 作開頭(如果發現有缺歡迎留言告知)

其實我還想過為對話框附加 Always on top 的功能,因為 .udl 的視窗有點特殊,它不會顯示在工作列。一般拿到 Process.MainWindowHandle 輸入到控制視窗的 Win32 API 就可以了,但 rundll32.exe 本身並沒有 MainWindowHandle,到現在到還不能很好地實現,不過這功能最多就是錦上添花而已。

以上就是偷個懶不用刻連線資訊輸入畫面的小撇步。