為實現「安裝即就緒」的交付體驗,將數據庫初始化腳本內嵌於安裝包,通過自定義 Installer 組件在安裝/卸載/回滾階段自動執行。本文展示基於 System.Configuration.Install 的完整實現方案。
DBInstall.cs 繼承 Installer,標記 [RunInstaller(true)]。Build Action = Embedded Resource)編譯入 DLL,避免外部文件依賴。[RunInstaller(true)]
public partial class DBInstall : Installer {
public override void Install(IDictionary stateSaver) { /* ... */ }
public override void Uninstall(IDictionary savedState) { /* ... */ }
public override void Rollback(IDictionary savedState) { /* ... */ }
}
public override void Install(IDictionary stateSaver) {
base.Install(stateSaver);
if (MessageBox.Show("安裝數據庫?", "確認", MessageBoxButtons.YesNo) == DialogResult.Yes) {
var cfg = new DBConfig(); // 自定義輸入框:Server/User/Pwd
cfg.ShowDialog();
SaveParams(cfg.IP, cfg.DBUser, cfg.DBPwd); // 存入 Context.Parameters
string dbName = "MyAppDB";
ExecuteSql("master", $"CREATE DATABASE [{dbName}]");
string sql = LoadSqlFromAssembly("MyApp.DB.Init.sql");
ExecuteSql(dbName, sql);
}
}
private string LoadSqlFromAssembly(string name) {
var asm = Assembly.GetExecutingAssembly();
using (var stream = asm.GetManifestResourceStream(asm.GetName().Name + "." + name))
using (var reader = new StreamReader(stream))
return reader.ReadToEnd();
}
private void ExecuteSql(string dbName, string sql) {
var conn = new SqlConnection(
$"user id={Context.Parameters["user"]};" +
$"data source={Context.Parameters["dbsource"]};" +
$"initial catalog=master;password={Context.Parameters["pwd"]};");
var cmd = new SqlCommand(sql, conn);
cmd.Connection.Open();
cmd.Connection.ChangeDatabase(dbName);
try { cmd.ExecuteNonQuery(); }
finally { cmd.Connection.Close(); }
}
public override void Uninstall(IDictionary savedState) {
base.Uninstall(savedState);
if (MessageBox.Show("移除數據庫?", "確認", MessageBoxButtons.YesNo) == DialogResult.Yes) {
var cfg = new DBConfig(); cfg.ShowDialog();
SaveParams(cfg.IP, cfg.DBUser, cfg.DBPwd);
ExecuteSql("master", "DROP DATABASE [MyAppDB]");
}
}
public override void Rollback(IDictionary savedState) {
base.Rollback(savedState);
// 安裝失敗時清理殘留庫
if (MessageBox.Show("回滾時刪除數據庫?", "確認", MessageBoxButtons.YesNo) == DialogResult.Yes)
ExecuteSql("master", "DROP DATABASE [MyAppDB]");
}
.msi,雙擊安裝即觸發完整流程。ExecuteNonQuery 不支持 GO 批次分隔符,腳本需拆分為單條語句或手動分批執行。Context.Parameters 在 Install/Uninstall/Rollback 間自動流轉,無需外部存儲。ShowDialog() 會阻塞安裝進程,確保用戶輸入同步獲取。try-catch,友好提示而非拋出原始異常導致安裝崩潰。