博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
    本文是在参考李洪根先生的".NET平台下WEB应用程序的部署(安装数据库和自动配置)" 的基础上完成,已测试通过。

(一)创建部署项目
    1. 在“文件”菜单上指向“添加项目”,然后选择“新建项目”。
    2. 在“添加新项目”对话框中,选择“项目类型”窗格中的“安装和部署项目”,然后选择“模板”窗格中的“Web 安装项目”。在“名称”框中键入 Test Installer。
    3. 单击“确定”关闭对话框。
    4. 项目被添加到解决方案资源管理器中,并且文件系统编辑器打开。
    5. 在“属性”窗口中,选择 ProductName 属性,并键入项目名称。

(二)将 webTest 项目的输出添加到部署项目中(如果使用的是VS2005请打上sp1补丁)
    1. 在“文件系统编辑器”中,选择“Web 应用程序”文件夹。在“操作”菜单上,指向“添加”,然后选择“项目输出”。
    2. 在“添加项目输出组”对话框中,选择“项目”下拉列表中的“webTest”。
    3. 单击“确定”关闭对话框。
    4. 从列表中选择“主输出”和“内容文件”组,然后单击“确定”。

(三)创建安装程序类
    1. 在“文件”菜单上指向“新建”,然后选择“项目”。
    2. 在“新建项目”对话框中,选择“项目类型”窗格中的“C# 项目”,然后选择“模板”窗格中的“类库”。在“名称”框中键入 DBCustomAction。
    3. 单击“打开”关闭对话框。
    4. 从“项目”菜单中选择“添加新项”。
    5. 在“添加新项”对话框中选择“安装程序类”。在“名称”框中键入 InstallDB 。
    6. 单击“确定”关闭对话框。
    7. 详细代码附后面

(四)创建自定义安装对话框
    1. 在解决方案资源管理器中选择“Test Installer”项目。在“视图”菜单上指向“编辑器”,然后选择“用户界面”。
    2. 在用户界面编辑器中,选择“安装”下的“启动”节点。在“操作”菜单上,选择“添加对话框”。
    3. 在“添加对话框”对话框中,选择“许可协议”对话框,然后单击“确定”关闭对话框。
    4. 在“添加对话框”对话框中,选择“文本框 (A)”对话框,然后单击“确定”关闭对话框。
    5. 在“操作”菜单上,选择“上移”。重复此步骤,直到“文本框 (A)”对话框位于“安装文件夹”节点之上。
    6. 在“属性”窗口中,选择 BannerText 属性并键入:安装数据库.。
    7. 选择 BodyText 属性并键入:安装程序将在目标机器上安装数据库。
    8. 选择 Edit1Label 属性并键入:数据库名称:。
    9. 选择 Edit1Property 属性并键入 DBName。
    10. 选择 Edit1Value 属性并键入:DBName。
    11. 选择 Edit2Label 属性并键入:服务器名:。
    12. 选择 Edit2Property 属性并键入 Servers。
    13. 选择 Edit2Value 属性并键入:(local)。
    14. 选择 Edit3Label 属性并键入:用户名:。
    15. 选择 Edit3Value 属性并键入:sa。
    16. 选择 Edit3Property 属性并键入 UserID。
    17. 选择 Edit4Label 属性并键入:密码:。
    18. 选择 Edit4Property 属性并键入 PWD。
    19. 选择 Edit1Visible、Edit2Visible、Edit3Visible 和 Edit4Visible 属性,并将它们设置为 true。

(五)创建自定义操作
    1. 在解决方案资源管理器中选择“Test Installer”项目。在“视图”菜单上指向“编辑器”,然后选择“自定义操作”。
    2. 在自定义操作编辑器中选择“安装”节点。在“操作”菜单上,选择“添加自定义操作”。
    3. 在“选择项目中的项”对话框中,双击“应用程序文件夹”。
    4. 选择“主输出来自 InstallDB(活动)”项,然后单击“确定”关闭对话框。
    5. 在“属性”窗口中,选择 CustomActionData 属性并键入 /dbname=[DBNAME] /server=[SERVERS] /user=[USERID] /pwd=[PWD] /targetdir="[TARGETDIR]\"。

     附/targetdir="[TARGETDIR]\"是安装后的目标路径,为了在DBCustomAction类中获得安装后的路径,我们设置此参数。

(六)添加文件
    1. 将SQL Server生成的脚本文件DB.sql添加到“Test Installer”项目
    2. 将安装文件LisenceFile.rtf(自己写的使用许可文本文件)添加到“Test Installer”项目
    3. 在用户界面编辑器中,选择许可协议,设置LisenceFile属性为LisenceFile.rtf文件
    4.一般会自动将依赖项添加到“检测到的依赖项”,如果没有,那么我们要手动将其加入步骤5)
        Crystal_Managed2003.msm (如果有水晶报表)
        dotnetfxredist_x86.msm (.net一定是必须的)
        ... (如果有引用其他的dll)
    5.如果使用了水晶报表,手动加入要包含的文件:项目-->添加-->合并模块(添加你的程序文件) (包括dotNetFramework和MDAC27),位于:C:\Program Files\Common Files\Merge Modules\ 下(*为必要的 )
    具体功能如下:
 
     a )托管组件 MSM 处理所有托管组件的分发,其中包括 Windows 窗体查看器、Web 窗体查看器和所有 Crystal Decisions 命名空间
       * Crystal_Managed2003.msm
         Crystal_Managed2003_chs.msm

     b )对于使报表运行所需的所有其他文件,由数据库访问 MSM 处理其分发。其中包括数据库、导出和图表驱动程序。
       * Crystal_Database_access2003.msm
         Crystal_Database_access2003_chs.msm

     c )KeyCode MSM 处理 Crystal Decisions 密钥号码的安装,注意是添加合并模块,否则没有“MergeMouduleProperties”属性
       * Crystal_regwiz2003.msm

     d )如果报表文件使用了 ADO.NET 的 dataset 数据集对象,那么 VC_User_CRT71_RTL_X86_---.msm 和 VC_User_STL71_RTL_X86_---.msm 模块也必须包含在安装工程中。而且这两个模块的文件安装属性的"Module Retargetable Folder"项必须修改成为系统目录
        VC_User_CRT71_RTL_X86_---.msm
        VC_User_STL71_RTL_X86_---.msm
   
     e )打开解决方案-->右键点击Crystal_regwiz2003.msm的属性,在“MergeMouduleProperties”里的“License Key”填入:AAP5GKS0000GDE100DS(这个是你生成Crystal Report是用到的注册号的密码!)
 
(七)附InstallerDB代码
  1 using System;
  2 using System.Collections.Generic;
  3 using System.ComponentModel;
  4 using System.Configuration.Install;
  5 using System.Diagnostics;
  6 
  7 namespace InstallDB
  8 {
  9     [RunInstaller(true)]
 10     public partial class InstallerDB : Installer
 11     {
 12         public InstallerDB()
 13         {
 14             InitializeComponent();
 15         }
 16 
 17         public override void Install(System.Collections.IDictionary stateSaver)
 18         {
 19             base.Install(stateSaver);
 20             
 21             this.UpdateConfig();
 22             
 23             //使用脚本创建,还原的方式实现
 24             this.InstallDB();
 25 
 26             //使用附加的方式实现
 27             //this.InstallDB2();
 28 
 29             //删除脚本文件
 30             DeleteFile(String.Format("{0}DB.bak"base.Context.Parameters["targetdir"]));
 31         }
 32 
 33         public override void Uninstall(System.Collections.IDictionary savedState)
 34         {
 35             base.Uninstall(savedState);
 36             DeleteFile(String.Format("{0}DB.dak",this.Context.Parameters["targetdir"]));
 37         }
 38 
 39         private void DeleteFile(string paths)
 40         {
 41             try
 42             { 
 43                 System.IO.FileInfo delFile = new System.IO.FileInfo(paths);
 44 
 45                 if(delFile.Exists)
 46                 {
 47                     delFile.Delete();
 48                 }
 49             }
 50             catch(Exception ex)
 51             {
 52                 throw (ex);
 53             }
 54         }
 55 
 56         private void CreateSql(String paths,String paths2)
 57         {
 58             System.IO.StreamWriter File = null;
 59             System.IO.StreamWriter FileRestort = null;
 60             String db = String.Format("{0}",this.Context.Parameters["dbname"]);
 61             String path = String.Format("{0}",this.Context.Parameters["targetdir"]);
 62             String oldDbname = "chat";
 63             try
 64             {
 65                 System.Text.StringBuilder s = new System.Text.StringBuilder();
 66                 s.Append("use master" + "\r\n" );
 67                 s.Append("\r\n");
 68                 s.Append("if not exists (select * from sysdatabases where name='" + db + "')\r\n");
 69                 s.Append("begin" + "\r\n");
 70                 s.Append("create database " + db + "\r\n");
 71                 s.Append("ON" +"\r\n");
 72                 s.Append("( name=" + db + ",FILENAME='" + path + db + ".mdf')" + "\r\n");
 73                 s.Append("LOG ON" + "\r\n");
 74                 s.Append("(name=" + db + "_log , FILENAME='" + path + db + "_log.ldf')" + "\r\n");
 75                 s.Append("end" + "\r\n");
 76                 s.Append("\r\n");
 77                 s.Append("");
 78                 File = new System.IO.StreamWriter(paths);
 79                 File.Write(s.ToString());
 80 
 81                 System.Text.StringBuilder s2 = new System.Text.StringBuilder();
 82                 s2.Append("use master" + "\r\n");
 83                 s2.Append("\r\n");
 84                 s2.Append("if exists (select * from sysdevices where name='DBdisk')" +"\r\n");
 85                 s2.Append(" BEGIN" +"\r\n");
 86                 s2.Append("  EXEC sp_dropdevice 'DBdisk'" + "\r\n");
 87                 s2.Append(" END" +"\r\n");
 88                 s2.Append("Else" +"\r\n");
 89                 s2.Append(" BEGIN" +"\r\n");
 90                 s2.Append("  EXEC sp_addumpdevice 'disk','DBdisk', '" + path + "DB.bak'" +"\r\n");
 91                 s2.Append(" END" + "\r\n");
 92                 s2.Append("" + "\r\n");
 93                 s2.Append("restore database " + db + "\r\n");
 94                 s2.Append("from disk='" +path+ "DB.bak'" +"\r\n");
 95                 s2.Append(" WITH FILE = 1," + "\r\n");
 96                 s2.Append("MOVE N'" + oldDbname + "' TO N'" + path + db + ".mdf',  MOVE N'" + oldDbname + "_log' TO N'" + path + db + "_log.LDF',  NOUNLOAD,  REPLACE,  STATS = 10" + "\r\n");
 97                 
 98 
 99                 FileRestort = new System.IO.StreamWriter(paths2);
100                 FileRestort.Write(s2.ToString());
101                 //RESTORE DATABASE [dbname1] FROM  DISK = N'D:\db.bat' WITH   FILE = 1,  MOVE N'Chat' TO N'C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Data\dbname1.mdf',  MOVE N'Chat_log' TO N'C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Data\DBName1_log.LDF',  NOUNLOAD,  REPLACE,  STATS = 10
102                 //GO
103                 //   方法如下:
104                 //1、在SQL2005中生成欲导出数据库脚本。
105                 //2、使用备份功能将源数据库备份。
106                 //3、在SQL2000中建立空目标数据库,对此数据库执行第1步生成的脚本。
107                 //4、使用还原功能将第2步备份还原即可。
108 
109             }
110             catch(Exception ex)
111             {
112                 throw ex;
113             }
114             finally
115             {
116                 File.Close();
117                 FileRestort.Close();
118             }
119         }
120 
121         //方法1:使用备份文件.()
122         private void InstallDB()
123         {
124             //安装数据库,调用自动批处理。
125             try
126             {
127                 //创建临时脚本
128                 CreateSql(String.Format("{0}Mydb2000tp.sql"this.Context.Parameters["targetdir"]), String.Format("{0}Mydb2000Re.sql"this.Context.Parameters["targetdir"]));
129                 //调用osql执行脚本(sql2005使用sqlcmd方可)
130                 System.Diagnostics.Process sqlProcess=new Process();
131                 sqlProcess.StartInfo.UseShellExecute = false;
132                 sqlProcess.StartInfo.RedirectStandardError = true;
133                 sqlProcess.StartInfo.FileName = "sqlcmd.exe";
134                 sqlProcess.StartInfo.Arguments = string.Format("-U {0} -P{1} -S {2} -i {3}Mydb2000tp.sql",this.Context.Parameters["user"],this.Context.Parameters["pwd"],this.Context.Parameters["server"],this.Context.Parameters["targetdir"]);
135                 sqlProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
136                 sqlProcess.Start();
137                 string error = sqlProcess.StandardError.ReadToEnd();
138                 sqlProcess.WaitForExit(); //等待执行
139 
140                 sqlProcess.StartInfo.Arguments = string.Format("-U {0} -P{1} -d {2} -S {3} -i {4}Mydb2000Cr.sql"this.Context.Parameters["user"], this.Context.Parameters["pwd"], this.Context.Parameters["dbname"], this.Context.Parameters["server"], this.Context.Parameters["targetdir"]);
141                 sqlProcess.Start();
142                 error += sqlProcess.StandardError.ReadToEnd();
143                 sqlProcess.WaitForExit(); //等待执行
144 
145                 sqlProcess.StartInfo.Arguments = string.Format("-U {0} -P{1} -S {2} -i {3}Mydb2000Re.sql"this.Context.Parameters["user"], this.Context.Parameters["pwd"], this.Context.Parameters["server"], this.Context.Parameters["targetdir"]);
146                 sqlProcess.Start();
147                 error += sqlProcess.StandardError.ReadToEnd();
148                 sqlProcess.WaitForExit(); //等待执行
149 
150                 sqlProcess.Close();
151 
152                 //删除文件
153                 DeleteFile(String.Format("{0}Mydb2000tp.sql"this.Context.Parameters["targetdir"]));
154                 DeleteFile(String.Format("{0}Mydb2000Re.sql"this.Context.Parameters["targetdir"]));
155                 DeleteFile(String.Format("{0}Mydb2000Cr.sql"this.Context.Parameters["targetdir"]));
156 
157                 if (!(error.Equals(""|| error == null))
158                 {
159                     throw new Exception(error);
160                 }
161 
162             }
163             catch(Exception ex)
164             {
165                 throw ex;
166                 
167             }
168         }
169 
170         //方法2:附加数据库.
171 
172         private void CreateSql(string paths)
173         {
174             System.IO.StreamWriter File = null;
175             String db = String.Format("{0}"this.Context.Parameters["dbname"]);
176             String path = String.Format("{0}"this.Context.Parameters["targetdir"]);
177             
178             try
179             {
180                 System.Text.StringBuilder s = new System.Text.StringBuilder();
181                 s.Append("use master" + "\r\n");
182                 s.Append("\r\n");
183                 s.Append("if not exists (select * from sysdatabases where name='" + db + "')\r\n");
184                 s.Append("begin" + "\r\n");
185                 s.Append("create database " + db + "\r\n");
186                 s.Append("ON" + "\r\n");
187                 s.Append("( FILENAME='" + path +  "hotop100_Data.mdf')," + "\r\n");
188                 s.Append("( FILENAME='" + path + "hotop100_log.ldf')" + "\r\n");
189                 s.Append("FOR ATTACH" + "\r\n");
190                 s.Append("end" + "\r\n");
191                 s.Append("\r\n");
192                 s.Append("");
193                 File = new System.IO.StreamWriter(paths);
194                 File.Write(s.ToString());
195 
196             }
197             catch (Exception ex)
198             {
199                 throw ex;
200             }
201             finally
202             {
203                 File.Close();
204 
205             }
206         }
207         private void InstallDB2()
208         {
209             //安装数据库,调用自动批处理。
210             try
211             {
212                 //创建临时脚本
213                 CreateSql(String.Format("{0}Mydb2000tp.sql"this.Context.Parameters["targetdir"]));
214                 //调用osql执行脚本(sql2005使用sqlcmd方可)
215                 System.Diagnostics.Process sqlProcess = new Process();
216                 sqlProcess.StartInfo.UseShellExecute = false;
217                 sqlProcess.StartInfo.RedirectStandardError = true;
218                 sqlProcess.StartInfo.FileName = "sqlcmd.exe";
219                 sqlProcess.StartInfo.Arguments = string.Format("-U {0} -P{1} -S {2} -i {3}Mydb2000tp.sql"this.Context.Parameters["user"], this.Context.Parameters["pwd"], this.Context.Parameters["server"], this.Context.Parameters["targetdir"]);
220                 sqlProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
221                 sqlProcess.Start();
222                 string error = sqlProcess.StandardError.ReadToEnd();
223                 sqlProcess.WaitForExit(); //等待执行
224                 sqlProcess.Close();
225 
226                 //删除文件
227               //  DeleteFile(String.Format("{0}Mydb2000tp.sql", this.Context.Parameters["targetdir"]));
228 
229                 if (!(error.Equals(""|| error == null))
230                 {
231                     throw new Exception(error);
232                 }
233 
234             }
235             catch (Exception ex)
236             {
237                 throw ex;
238 
239             }
240         }
241         private void UpdateConfig()
242         {
243             try
244             {
245                 System.IO.FileInfo FileInfo = new System.IO.FileInfo(this.Context.Parameters["targetdir"+ "\\web.config");
246                 if (FileInfo.Exists == false)
247                 {
248                     throw new InstallException("没有找到配置文件");
249                 }
250 
251                 //实例化XML文档
252 
253                 System.Xml.XmlDocument XmlDocument=new System.Xml.XmlDocument();
254                 XmlDocument.Load(FileInfo.FullName);
255 
256                 //查找到appSettings中的节点
257               
258                 Boolean FoundIt = false;
259 
260                 foreach (System.Xml.XmlNode Node in XmlDocument["configuration"]["appSettings"])
261                 {
262                     if (Node.Name.Equals("add"))
263                     {
264                         if (Node.Attributes.GetNamedItem("key").Value.Equals("connString"))
265                         {
266                             Node.Attributes.GetNamedItem("value").Value = string.Format("Persist Security Info=False;Data Source={0};Initial Catalog={1};User ID={2};Password={3};Packet Size=4096;Pooling=true;Max Pool Size=100;Min Pool Size=1"this.Context.Parameters["server"], this.Context.Parameters["dbname"], this.Context.Parameters["user"], this.Context.Parameters["pwd"]);
267                             FoundIt = true;
268                         }
269                     }
270 
271                 }
272 
273                 if (FoundIt == false)
274                 {
275                     throw new InstallException("web.config文件没有包含connString连接字符串设置");
276                 }
277 
278                 XmlDocument.Save(FileInfo.FullName);
279             }
280             catch (Exception ex)
281             {
282                 throw ex;
283             }
284         }
285     }
286 }