使用安装程序类轻松部署 SQL Server 数据库






4.91/5 (45投票s)
使用 System.Configuration.Install 和 VS.NET 安装项目部署 MS SQL Server 数据库。
引言
如果您制作了一个使用 SQL Server 数据库的应用程序,该数据库需要位于客户端服务器上,那么 VS.NET 安装项目的帮助不大。您可以选择 InstallShild 或其他产品,这将使事情变得容易,但成本会更高。因此,为了寻找免费的解决方案,我在 MSDN 上找到了一篇关于使用 Installer
类和自定义操作来实现此目的的文章。该代码是用 VB.NET 编写的,因此本文将其移植到 C#,并添加了一些我发现有用的新功能。您需要做的就是创建一个派生自 System.Configuration.Install
的类,并将两个名为 *install.txt* & *uninstall.txt* 的嵌入式资源添加到解决方案中。 *install.txt* 将包含您的数据库的 SQL 脚本,而 *uninstall.txt* 将包含删除脚本。对于数据库脚本,我使用的是 Microsoft 团队为 ASP.NET InSQL 会话状态制作的 ASPstate 脚本
< sessionState
mode ="SQLServer"
stateConnectionString ="tcpip=127.0.0.1:42424"
sqlConnectionString ="data source=aleph;User ID=ASPsession;Password=ASPsession;"
cookieless ="false"
timeout ="60"
/>
为了使我的 Web 应用程序在客户端服务器上工作,我需要使用我的应用程序和 SQL 脚本制作一个 MSI。 为了在安装时运行脚本,我制作了一个名为 ScriptInstall
的 * .dll *,其代码如下所示。
Installer 类代码
首先,我们声明一个 string
,它将具有默认值,并且可以被 Install
方法覆盖
string conStr="packet size=4096;integrated security=SSPI;"+
"data source=\"(local)\";persist security info=False;"+
"initial catalog=master";
我使用两个函数,它们将返回连接字符串和脚本内容
private static string GetScript(string name)
{
Assembly asm = Assembly.GetExecutingAssembly();
Stream str = asm.GetManifestResourceStream(
asm.GetName().Name+ "." + name);
StreamReader reader = new StreamReader(str);
return reader.ReadToEnd();
}
private static string GetLogin(string databaseServer,
string userName,string userPass,string database)
{
return "server=" + databaseServer +
";database="+database+";User ID=" + userName +
";Password=" + userPass;
}
然后我使用两个函数,它们将在 SQL Server 上运行 *install.txt* 和 *uninstall.txt*。 ExecuteSQL
具有一个 regex
,它在 GO 之后拆分脚本,以便我可以使用 SQLCommand
逐个执行,我这样做是因为如果 SQL 脚本包含“GO”,ADO.NET 将抛出异常。
private static void ExecuteSql(SqlConnection sqlCon)
{
string[] SqlLine;
Regex regex = new Regex("^GO",RegexOptions.IgnoreCase | RegexOptions.Multiline);
string txtSQL = GetScript("install.txt");
SqlLine = regex.Split(txtSQL);
SqlCommand cmd = sqlCon.CreateCommand();
cmd.Connection = sqlCon;
foreach(string line in SqlLine)
{
if(line.Length>0)
{
cmd.CommandText = line;
cmd.CommandType = CommandType.Text;
try
{
cmd.ExecuteNonQuery();
}
catch(SqlException)
{
//rollback
ExecuteDrop(sqlCon);
break;
}
}
}
}
private static void ExecuteDrop(SqlConnection sqlCon)
{
if(sqlCon.State!=ConnectionState.Closed)sqlCon.Close();
sqlCon.Open();
SqlCommand cmd = sqlCon.CreateCommand();
cmd.Connection = sqlCon;
cmd.CommandText = GetScript("uninstall.txt");
cmd.CommandType = CommandType.Text;
cmd.ExecuteNonQuery();
sqlCon.Close();
}
有了这些函数,我们现在可以覆盖 Install(IDictionary stateSaver)
和 Uninstall(IDictionary savedState)
。在 Install 方法中,除了在服务器上运行 SQL 脚本之外,我还保存用户提交的连接数据。以明文形式保存连接字符串是危险的,因此我使用 RijndaelManaged
对其进行加密。您也可以在源代码中找到该类。我保存连接字符串是因为卸载时需要它来删除数据库 ASPstate。
public override void Install(IDictionary stateSaver)
{
base.Install (stateSaver);
if(Context.Parameters["databaseServer"].Length>0 &&
Context.Parameters["userName"].Length>0 &&
Context.Parameters["userPass"].Length>0)
{
conStr = GetLogin(
Context.Parameters["databaseServer"],
Context.Parameters["userName"],
Context.Parameters["userPass"],
"master");
RijndaelCryptography rijndael = new RijndaelCryptography();
rijndael.GenKey();
rijndael.Encrypt(conStr);
//save information in the state-saver IDictionary
//to be used in the Uninstall method
stateSaver.Add("key",rijndael.Key);
stateSaver.Add("IV",rijndael.IV);
stateSaver.Add("conStr",rijndael.Encrypted);
}
SqlConnection sqlCon = new SqlConnection(conStr);
sqlCon.Open();
ExecuteSql(sqlCon);
if(sqlCon.State!=ConnectionState.Closed)sqlCon.Close();
}
public override void Uninstall(IDictionary savedState)
{
base.Uninstall (savedState);
if(savedState.Contains("conStr"))
{
RijndaelCryptography rijndael = new RijndaelCryptography();
rijndael.Key = (byte[])savedState["key"];
rijndael.IV = (byte[])savedState["IV"];
conStr = rijndael.Decrypt((byte[])savedState["conStr"]);
}
SqlConnection sqlCon = new SqlConnection(conStr);
ExecuteDrop(sqlCon);
}
设置项目
现在 Installer 类已完成,我可以创建一个安装项目并添加主要输出。在用户界面编辑器中,选择“安装”下的“开始”节点。在“操作”菜单上,选择“添加对话框”。在“添加对话框”对话框中,选择“文本框 (A)”对话框,然后单击“确定”以关闭对话框。在“操作”菜单上,选择“上移”。重复此操作,直到“文本框 (A)”对话框位于“安装文件夹”节点上方。像这样编辑“文本框 (A)”窗体的属性
转到自定义操作编辑器,并将主要输出添加到安装和卸载节点。单击安装节点上的主要输出并编辑属性。在 CustomActionData 中,键入以下内容
/databaseServer=[EDITA1] /userName=[EDITA2] /userPass=[EDITA3]
我使用 Context.Parameters
在 Installer
类中获取文本框的值。
conStr = GetLogin(
Context.Parameters["databaseServer"],
Context.Parameters["userName"],
Context.Parameters["userPass"],
"master");
现在一切都完成了。只需构建这两个项目,您就可以安装数据库了。我希望您会发现此代码有用,可以向代码中添加很多东西,例如更安全地存储 Rijndael
的密钥和 IV,或者在 ExecuteSql
事务中使用。期待您的评论。
历史
- 版本 1.0