目录
l 摘要
l 一般安装程序的制作
l 在安装程序中部署SQL Server数据库
1. 通过调用osql来执行数据库脚本文件
2. 通过把脚本文件作为资源文件载入
3. 通过sp_attach_db来创建数据库
l 总结
一个项目完成之后,安装程序的制作是一个必要的过程。如果需要部署数据库,则使安装程度的制作变得比较麻烦。使用visual studio.net可以非常方便的制作应用程序以及部署程序中需要的数据库。本文介绍了如何使用visual studio.net制作安装程序,以及如何在安装程序中部署数据库.本文假设您对ADO.net比较熟悉。
一般安装程序的制作
Visual studio.net 提供了很强大并且非常便捷的安装程序制作功能。一般的安装程序制作可以参考如下步骤:
(1) 在Visual studio.net里面新建一个安装项目(针对一般windows应用程序)或者web安装项目(针对基于web的应用程序),比如叫SetupFace.
(2) 在解决方案里面的项目中的SetupFace上单击右键,可以看到如下的视图:(略)
视图中出现的项目就是在制作安装程序中需要涉及到的项目。
a. 文件系统部分提供了如何把需要安装到目标机可执行程序以及运行时需要的dll等打包到安装程序中,同时也提供了如何在目标机的桌面上和程序菜单中创建快捷方式以及文件夹等。
b. 注册表部分提供了如何在目标机的注册表中添加相关的键值。
c. 文件类型提供了在目标机上创建一个文件类型与应用程序的关联,并可以为注册的文件类型增加相关的右键菜单功能。比如注册一个.pdf的文件,使用你自己的程序打开。
d. 用户界面提供了在安装过程中的界面,也可以根据自己的需要创建如自述文件,注册码校验等等功能。创建项目时已经提供了一些基本的画面。
e. 自定义操作部分主要提供了如何在安装的不同阶段中完成不同的工作。比如在安装过程中创建数据库,在卸载过程中删除数据库等。
f. 启动条件部分提供了在安装您的应用程序前需要完成什么条件。Visual studio.net提供了可以在用户计算机上搜索启动条件的功能。比如要求某个程序已经安装,可以通过搜索文件系统或则搜索注册表来完成。
(3) 在视图中选择文件系统,将看到如下画面:(略)
如果您需要完成一个简单的安装程序,在添加中选择文件,选择您以及编译完成的应用程序,Visual studio.net会自动引入该应用程序所需要的dll(只针对Visual studio.net开发的应用程序,其他的程序没有试过),然后根据您的需要在用户的”程序”菜单和用户桌面创建快捷方式,然后把快捷方式的指向选择为在应用程序文件夹中导入的应用程序即可。
(4) 最后,可以直接编译该项目,安装程序的制作即可完成。
如果需要更多的控制和修改安装程序过程中的内容,可以根据第(2)步中提到的不同视图进行编辑即可。如果需要制作web项目的安装程序,在创建项目时选择创建Web项目即可, 其他部分大同小异。也可以直接参考MSDN的如下链接:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vsintro7/html/vxconATourOfVisualStudio.asp
2.在安装程序中部署SQL Server数据库
通过上面的介绍,一般应用程序的制作非常容易,基本上就是把您的应用程序拖入该安装程序的过程。如果您的应用程序的运行需要数据库的支持(如SQL Server),问题就变得比较复杂一点。
主要有如下几个方面的问题:
(1) 如何在获得安装画面的值,比如获得用户输入的用户名密码。
(2) 如何设计一个程序来与数据库服务器进行交互,创建新的数据库。
如何在获得安装程序中的值,可以参看如下链接,这里我们不做太多的介绍。
<http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vsintro7/html/vxconATourOfVisualStudio.asp>
这个例子演示了如何在用户界面自定义对话框要求用户输入信息,然后在自定义操作中把获得的值通过CustomActionData来传递给自定义操作中的主输出,最后在主输出相面里面的程序里面来创建一个数据库。
通过对上面的例子的理解,基本上可以按照这个方式来创建一个数据库,它通过ADO.net执行SQL语句来完成创建数据库的。但是,如果有大量的数据表以及存储过程需要建立,通过这个的方式非常麻烦。可不可以通过直接在SQL Server中创建相应的数据库生成脚本文件来直接完成呢?
我们有3个解决方案:
(1) 通过调用osql来执行数据库脚本文件
(2) 通过把相应的脚本文件作为资源文件嵌入到项目中,然后通过ADO.net来执行
(3) 通过调用SQL Server的sp_attach_db的存储过程来直接附加数据库。
2.1 通过调用osql来执行数据库脚本文件
从上面的例子我们已经知道了如何传递值,那么我们只要在项目文件中程序段中执行osql即可。
这里有一个问题就是从什么地方找到数据库的脚本文件。我们可以把脚本文件放到文件系统中,直接安装到用户机器上,并可以通过如下方法获得到该文件的位置。
Assembly asm=Assembly.GetExecutingAssembly();
String setuppath=asm.Location;
这样我们就可以知道脚本文件的位置了,下面的文件就是如何启动osql程序了。我们可以通过如下的代码段来完成:
Process sqlprocess=new Process(); sqlprocess.StartInfo.FileName="osql.exe";
sqlprocess.StartInfo.Arguments=String.Format("-U {0} -P {1} -S {2} -i {3}",this.uid,this.pwd,this.serverip,this.spath); //uid 为用户名,pwd为密码,serverip为目标服务器的ip,spath为数据库脚本所在的路径
sqlprocess.StartInfo.WindowStyle=ProcessWindowStyle.Hidden;
sqlprocess.Start();
sqlprocess.WaitForExit(); //等待程序执行
sqlprocess.Close();
从上面可以知道,该方法必须要求安装程序的客户机以及安装好了SQL Server才能使用(osql为安装了SQL Server后提供的命令行下的程序).同时在实际的测试过程中,我们发现如果对于用户在安装程序是选择带有空格的路径,如;C:/program files/yourappliaction/时,安装失败。这个是一个比较严重的问题。
2.2 通过把脚本文件作为资源文件载入
从前面的讨论中我们可以看到,直接使用ADO.net执行时比较麻烦,需要一句句执行,如果使用脚本,数据库中生成的脚本中有”GO”命令,在ADO.net中执行时会出问题。因此,根据对数据库安装脚本的分析,我们可以采用如下替代方案。
在数据库的安装过程中,无外乎如下几个部分:
(1) 创建数据库
(2) 创建表
(3) 创建试图或者存储过程
并且这三个部分是有先后顺序的,顺序不能颠倒,但是每个过程中没有顺序关系。在测试过程中我们发现可以在一条语句中创建多个表或者多个存储过程。也就是说,我们可以把执行过程按照上面的顺序执行就行了。并且我们把数据库脚本作为资源文件嵌入,只要调入执行就可以了,这样就达到了简化创建一条条命令的过程。
获得资源文件代码如下:
Assembly Asm=Assembly.GetExecutingAssembly();
StreamReader str;
str=new StreamReader(Asm.GetManifestResourceStream(Asm.GetName().Name+"."+filename))// filename为你需要摘入的资源文件。作为资源文件时,只要把文件导入到您的项目中,并且把生成操作改为嵌入的资源即可。
这里我们是直接获得了该文件的文件流,因此直接把该流中的内容读入即可。
我们可以通过如下操作完成:
(1) 建立一个数据库的链接,创建数据库. 比如: connectionstring=”server=127.0.0.1,uid=sa,pwd=pwd”;
(2) 重新创建一个数据库链接,该链接指向创建的数据库。connectionstring=”server=127.0.0.1,uid=sa,pwd=pwd,database=yourdatabase”;
(3) 在新的链接中执行创建数据表和数据存储过程的代码即可。
需要注意的是:不要在你的脚本中有GO命名,其他命令都可以直接执行。
该方法的好处在于: 可以不要求安装的目标机上有SQL Server,也不存在因为文件路径中有空格的问题而倒是安装程序失败。当然,如果您的数据库为Oracle或者DB2等,您也可以采用类似的方法来实现。
2.3 通过sp_attach_db来创建数据库
通过上面的讨论我们已经很清楚如何安装数据库了。在安装数据库的过程中,我们除了可以通过数据库脚本来创建数据库之外,我们也可以通过SQL Server的系统存储过程sp_attach_db来附加数据库。
这里我们解决两个问题即可:
(1) 确定数据库文件(.mdf和.ldf)的位置。
(2) 执行存储过程。
对于问题1我们可以借鉴安装数据的第一种方法,即把.mdf和.ldf通过文件系统安装到目标机上,然后通过
Assembly asm=Assembly.GetExecutingAssembly();
String setuppath=asm.Location;
获得文件的路径。
最后通过调用sp_attach_db 加上相应的参数即可完成。
需要注意的是: 该方法也只能针对数据库安装在本机的情况下进行安装。
总结
本文通过介绍了三种不同的方法来在安装程序是如何安装数据库,同时也分析了不同的方法的优劣之处,用户可以根据自己的实际需要来选择安装方法。同时,通过该方法的提出,用户也可以完成在安装程序是对数据库的配置工作。
Imports System.ComponentModel imports System.Configuration.Install imports System.IO imports System.Reflection <runinstaller(true)> Public Class DBCustomActionClass DBCustomAction inherits System.Configuration.Install.Installer #region "组件设计器生成的代码 " public Sub New()Sub New() mybase.new() ’该调用是组件设计器所必需的 initializecomponent() ’在 InitializeComponent() 调用之后添加所有初始化 end Sub ’Installer 重写 dispose 以清理组件列表。 protected Overloads Overrides Sub Dispose()Sub Dispose(ByVal disposing As Boolean) if disposing Then if Not (components Is Nothing) Then components.dispose() end If end If mybase.dispose(disposing) end Sub private components As System.ComponentModel.IContainer <system.diagnostics.debuggerstepthrough()> Private Sub InitializeComponent()Sub InitializeComponent() end Sub #end Region ’执行sql 语句 private Sub ExecuteSql() Sub ExecuteSql(ByVal conn As String, ByVal DatabaseName As String, ByVal Sql As String) dim mySqlConnection As New SqlClient.SqlConnection(conn) dim Command As New SqlClient.SqlCommand(Sql, mySqlConnection) command.connection.open() command.connection.changedatabase(databasename) try command.executenonquery() finally close Connection command.connection.close() end Try end Sub public Overrides Sub Install()Sub Install(ByVal stateSaver As System.Collections.IDictionary) MyBase.Install(stateSaver) ’ ------------------------建立数据库----------------------- try dim connStr As String = String.Format("data source={0};user id={1};password={2};persist security info=false;packet size=4096", Me.Context.Parameters.Item("server"), Me.Context.Parameters.Item("user"), Me.Context.Parameters.Item("pwd")) ’根据输入的数据库名称建立数据库 executesql(connstr, "master", "CREATE DATABASE " + Me.Context.Parameters.Item("dbname")) ’调用osql执行脚本 dim sqlProcess As New System.Diagnostics.Process sqlprocess.startinfo.filename = "osql.exe " sqlprocess.startinfo.arguments = String.Format(" -U {0} -P {1} -d {2} -i {3}db.sql",Me.Context.Parameters.Item("user"), Me.Context.Parameters.Item("pwd"),Me.Context.Parameters.Item("dbname"), Me.Context.Parameters.Item("targetdir")) sqlprocess.startinfo.windowstyle = ProcessWindowStyle.Hidden sqlprocess.start() sqlprocess.waitforexit() ’等待执行 sqlprocess.close() ’删除脚本文件 dim sqlFileInfo As New System.IO.FileInfo(String.Format("{0}db.sql",Me.Context.Parameters.Item("targetdir"))) if sqlFileInfo.Exists Then sqlfileinfo.delete() end If catch ex As Exception throw ex end Try