一个解决方案中可能会包含多个类库项目和一个网站,打包过程如下:

1、在【解决方案资源管理器】中【右键-添加-新建项目】,左侧选择【其他类型项目】,右侧选择【安装项目】,如下图:

2、点击【确定】后,左侧【文件系统】选项卡中选择【应用程序文件夹】-【添加】-【项目输出】,类库项目选择添加【主输出】,网站选择添加【内容文件】

3、在网站的制作过程中可能用到一些其他的BLL组件,也需要添加进来,还是选择【应用程序文件夹】-【添加】-【程序集】,选择你网站BIN文件夹下的一些BLL

4、因为要带数据库带包,此处采用打包程序利用系统存储过程附加MDF和LDF文件的方法,所以【应用程序文件夹】中还需要【添加-文件】,将数据库的MDF和LDF文件添加进来(先停止SQL服务器,直到安装程序制作完成),如果安装程序需要在控制面板的添加删除程序列表中有图标的话,也需要将ICO图标文件添加进来。

5、设置安装项目的常用属性:

Author:作者

Manufactuer:公司

Title:安装程序的标题

AddRemoveProgramsIco:设置为添加进来的ICO文件

如果不带数据库安装的话,可以将安装项目直接生成就可以了,如果Debug设置为True,则生成的MSI文件在Debug文件夹中,如果为False,生成的MSI文件在Release文件夹中。

6、在【解决方案资源管理器】中,右键,添加【新建项目】-【Visual C#】-【类库】,建立数据库安装程序,类库建好后,将默认的Class1.cs文件删除,右键,添加【新建项】-【安装程序类】,下面主要是此类的代码。

7、安装程序类的代码:

 1 using System.ComponentModel;
 2 using System.Configuration.Install;
 3 using System.Collections; //以下引入
 4 using System.Collections.Specialized;
 5 using System.Data;
 6 using System.Data.SqlClient;
 7 using System.Reflection;
 8 using System.Xml;
 9 
10 namespace DbClass
11 {
12     [RunInstaller(true)]
13     public partial class InstallDB : Installer
14     {
15         /// <summary>
16         /// 必需的设计器变量,均来自于安装程序的“自定义操作”视图中的设置
17         /// </summary>
18         private string hostname;
19         private string username;
20         private string userpassword;
21         private string dbname;
22 
23         public InstallDB()
24         {
25             InitializeComponent();
26         }
27 
28         private string CreateSqlStr()
29         {
30             string sqlstr = "";
31             string datafile = Context.Parameters["installdir"+ @"FlowerShop.mdf";
32             string logfile = Context.Parameters["installdir"+ @"FlowerShop_log.ldf";
33             sqlstr = "EXEC  sp_attach_db @dbname ='" + Context.Parameters["dbname"+ "',@filename1='" + datafile + "',@filename2='" + logfile + "'";
34             return sqlstr;
35         }
36 
37         private void ExecuteSql(string DatabaseName, string SqlStr)
38         {
39             string SqlConnectionStr = @"server=" + hostname + ";uid=" + username + ";pwd=" + userpassword;
40             SqlConnection myConnection = new SqlConnection(SqlConnectionStr);
41             SqlCommand myCommand = new SqlCommand(SqlStr, myConnection);
42             myCommand.Connection.Open();
43             myCommand.Connection.ChangeDatabase(DatabaseName);
44             myCommand.ExecuteNonQuery();
45             myCommand.Connection.Close();
46         }
47 
48         private void AddFlowerShopDataBase()
49         {
50             ExecuteSql("pubs", CreateSqlStr()); 
51         }
52 
53         private void ModifyXML()
54         {
55             string XMLdir = Context.Parameters["installdir"+ @"Web.config";
56             XmlNodeReader reader = null;
57             XmlTextWriter writer = null;
58             XmlDocument doc = new XmlDocument();
59             doc.Load(XMLdir);
60             reader = new XmlNodeReader(doc);
61             writer = new XmlTextWriter(XMLdir, System.Text.Encoding.UTF8);
62 
63             try
64             {
65                 while (reader.Read())
66                 {
67                     if (reader.NodeType == XmlNodeType.Element && reader.Name == "connectionStrings")
68                     {
69                         string strContent = reader.ReadInnerXml();
70                         strContent = "<add name=\"strShop\" connectionString=\"server=" + hostname + ";database=" + dbname + ";uid=" + username + ";pwd=" + userpassword + "\" providerName=\"System.Data.SqlClient\"/>";
71                         XmlNode root = doc.DocumentElement;
72                         XmlElement elem = doc.CreateElement("connectionStrings");
73                         elem.InnerXml = strContent;
74                         root.ReplaceChild(elem, root.ChildNodes[1]);
75                         doc.Save(writer);
76                         break;
77                     }
78                 }
79             }
80             finally
81             {
82                 if (reader != null)
83                     reader.Close();
84             }
85         }
86 
87         public override void Install(IDictionary stateSaver)
88         {
89             base.Install(stateSaver);
90             hostname = Context.Parameters["hostname"];
91             username = Context.Parameters["username"];
92             userpassword = Context.Parameters["userpassword"];
93             dbname = Context.Parameters["dbname"];
94             this.AddFlowerShopDataBase();
95             this.ModifyXML();
96         }
97     }  
98 }

【注意】 最后一个方法Install方法中Parameters中的键名都是与接下来要添加的自定义操作中的变量名要保持一致的,包括上面用到的installdir。

【注意】 类库项目编写完成后,在解决方案中选中类库项目,右键,生成

8、在安装项目的【应用程序文件夹】中【添加】-【项目输出】,将刚建好的DbClass项目的“主输出”添加进来。

9、在安装项目上右键-【视图】-【用户界面】,在【安装】中,选择【启动】,右键选择【添加对话框】-【文本框(A)】,调整文本框A的位置到【安装文件夹】之上,如果要添加许可协议,还可以再添加对话框,选择【许可协议】,调整位置到【欢迎使用】之下。

10、选中【文本框(A)】,设置其属性如下:


注意设置的Edit*Property

11、在安装项目上右键-【视图】-【自定义操作】,在【安装】处右键【添加自定义操作】,选择应用程序文件夹中的DbClass主输出,并设置主输出的CustomActionData属性为:/dbname=[DBNAME]  /hostname=[SERVER]  /username=[UID]  /userpassword=[PWD]  /installdir="[TARGETDIR]\",总共包括5项,都是DbClass项目的类中要用到的,每一项都以/开头,每项之间都用空格隔开,每一项的名字都是与DbClass项目的类中Context.Paramerters的键名一直,其中前4项的[]中的内容都与上面用户界面的文本框A的属性中设置的Edit*Property一致,最后一项是固定的TARGETDIR,写法有所不同,[]两边有双引号。下面的提交、回滚、卸载都同样设置。

 

12、如果要添加许可协议,先创建一个rtf文件,来包含许可协议的内容,注意此rtf文件不能新建一个word DOC文件,然后将其扩展名再改成rtf,这样许可协议在显示的时候会是乱码,必须打开WORD软件,去新建一个空白文档,然后写入许可协议内容,最后直接保存成rtf格式,随后在【文件系统】的【应用程序文件夹】中添加【文件】,选择此rtf文件,然后在【用户界面】的【安装】-【启动】中选择【许可协议】,设置LicenseFile属性为应用程序文件中的rtf文件。

13、可以为安装包添加卸载程序

A、在系统文件的system32文件夹下找到msiexec.exe。(c:\windows\system32\msiexec.exe)在打包项目中应用程序文件夹中添加文件msiexec.exe。

注意:最后生成时若提示msiexec.exe受windows文件保护,可以将msiexec.exe文件复制到另一个位置,然后添加到安装程序中来,并重新设置B步骤中的创建方式的target
B、创建msiexec的快捷方式,改此快捷方式的Argmuments属性为“/x {产品ID}”,说明:产品ID的值为打包项目(比如FlowerShopSetup) 的ProductCode属性值,如: /x{BB8D4C5A-B041-489B-84FF-ACF0C8342264}。
C、将快捷方式拖到用户程序菜单中即可,可以为快捷方法重命名,如:卸载FlowerShop,也可以设置快捷方式的Icon属性,为快捷方式指定图标。

 

最后选择安装项目,右键生成即可。