C# Web項目制作安裝包,
web項目制作成安裝包是為了方便發布到服務器上,本文主要講了安裝包制作,IIS部署,數據庫安裝,卸載時刪除IIS網站和數據庫
博文參考鏈接:http://www.cnblogs.com/huxj/archive/2010/09/10/1823637.html
下面是本人通過網上資料和自己的思考總結進行補充,希望能對大家又所幫助。
首先我們需要一個已經發布的網站
一、安裝包制作
打開網站

然後右鍵解決方案》添加》新建項目》其他項目類型》安裝和部署》Visual Studio Installer 》安裝項目
在web項目裡新建一個安裝項目,如圖:

在新建的安裝項目,右鍵安裝項目》添加》項目輸出,如圖:

選擇項目輸出,選擇要操作的項目,如圖:

示例項目是一個web網站,所以只有一個內容文件輸出選項,選中內容文件點擊確定
如果示例項目是一個Web項目,則選擇主輸出,如下圖:

現在我們來制作安裝包的安裝界面,如圖選擇用戶界面:


右鍵啟動,添加對話框,如圖:

這裡可以根據安裝項目的需要來選擇設置。
這裡我們選擇文本框(A)、文本框(B)、許可協議

拖動對話框進行排序——對話框的排序代表著安裝時界面順序。
然後我們在文件系統》應用程序文件夾,右邊空白處右鍵》添加》文件,添加license.rtf文件 ,如圖:


現在我們回到用戶界面,選擇用戶協議對話框-屬性
可以看到LicenseFile沒有值,將剛添加進的license.rtf文件添加進去

選擇應用程序文件夾

由於在安裝過程也需要設置數據庫,所以我們還需要讓安裝用戶在安裝過程中輸入數據庫服務器信息,選擇對話框(A)-屬性,設置如圖:

這裡我們只需要服務器、賬號、密碼,所以Edit4Visible設為false.
由於在安裝過程中也需要設置IIS,所以還需要讓安裝用戶在安裝過程中輸入網站配置,選擇對話框(B)-屬性,設置如圖:

Value中的值都是為默認值
由於我們需要配置數據庫和iis,所以我們需要在新建兩個類庫(upLibrary1和unLibrary1),各自添加一個安裝程序類(添加的安裝程序類是一個繼承installer的類),如圖:


其中upLibrary1類庫是安裝,unLibrary1類庫是卸載。
現在我們在安裝項目Setup添加這兩個類庫,右鍵》添加》項目輸出》選擇upLibrary1類庫和unLibrary1類庫》選擇主輸出

添加後

然後右鍵安裝項目》自定義操作》右鍵安裝》添加自定義操作》應用程序文件夾

選擇主輸出來自upLibrary1(活動)

卸載中選擇主輸出來自unLibrary1(活動)
接下來我們需要在安裝過程傳遞輸入的數據傳遞這個項目中,選擇主輸出來自upLibrary1(活動),右鍵屬性,如圖:

屬性框中的CustomActionData就是指定要傳遞到安裝程序的自定義數據。
/server="'[EDITA1]'" /user="'[EDITA2]'" /pwd="'[EDITA3]'" /iis="[IISSERVER]" /ip="[IP]" /port="[PORT]" /ISNAME="[ISNAME]" /targetdir="[TARGETDIR]\"
/targetdir="[TARGETDIR]\"中的“\”記得不要丟了
現在我們回到upLibrary1安裝程序類:
我們先講upLibrary1類庫,先不管unLibrary1類庫
打開upInstaller1類是一個設計視圖,點擊 單擊此處切換到代碼視圖

在安裝程序類裡我們可以寫安裝過程中的處理事件,比如附加數據庫,將網站發布到iis上。
首先我們先從寫Install方法:
public override void Install(IDictionary stateSaver){ //這裡面就是我們的主要代碼區 }
在Install方法中我們可以接收安裝過程中輸出的數據信息,如下:

代碼塊:
安裝:
裡面包含數據庫的附加、連接iis服務器、判斷網站是否存在、添加網站

![]()
1 using System;
2 using System.Collections;
3 using System.Collections.Generic;
4 using System.ComponentModel;
5 using System.Configuration.Install;
6 using System.Linq;
7 using System.Data.SqlClient;
8 using System.Management;
9 using System.IO;
10 using System.Security.AccessControl;
11 using System.DirectoryServices;
12
13
14 namespace upLibrary1
15 {
16 [RunInstaller(true)]
17 public partial class upInstaller1 : System.Configuration.Install.Installer
18 {
19 public upInstaller1()
20 {
21 InitializeComponent();
22 }
23
24 string iis = "";
25 string port = "";
26 private string _target;
27 private string ISNAME;
28 private string targetdir; //安裝地址
29 private DirectoryEntry _iisServer;
30 private ManagementScope _scope;
31 private ConnectionOptions _connection;
32
33 public override void Install(IDictionary stateSaver)
34 {
35
36 base.Install(stateSaver);
37 string databaseServer = Context.Parameters["server"].ToString(); //數據庫服務器
38 //string databasename = Context.Parameters["dbname"].ToString();
39 string userName = Context.Parameters["user"].ToString(); //賬號
40 string userPass = Context.Parameters["pwd"].ToString(); //密碼
41 string targetdir = Context.Parameters["targetdir"].ToString(); //安裝地址
42 iis = this.Context.Parameters["iis"].ToString(); //服務器
43 string ip = this.Context.Parameters["ip"].ToString(); //ip
44 port = this.Context.Parameters["port"].ToString(); //端口
45 ISNAME = this.Context.Parameters["ISNAME"].ToString(); //網站名
46
47 string serverID = "66"; //和iis上的網站ID不可重復
48 try
49 {
50 //System.Diagnostics.Debugger.Launch(); //調試代碼
51 Connect();
52 string serverComment = ISNAME;
53 string defaultVrootPath = this.Context.Parameters["targetdir"];
54 if (defaultVrootPath.EndsWith(@"\"))
55 {
56 defaultVrootPath = defaultVrootPath.Substring(0, defaultVrootPath.Length - 1);
57 }
58 string HostName = "";
59 string IP = ip;
60 string Port = port;
61 string sReturn = CreateWebSite(serverID, serverComment, defaultVrootPath, HostName, IP, Port);
62
63 //給文件添加"Authenticated Users,Everyone,Users"用戶組的完全控制權限
64 if (File.Exists(Context.Parameters["targetdir"].ToString() + "App_Data\\jiaowuDB.mdf"))
65 {
66 FileInfo fi = new FileInfo(Context.Parameters["targetdir"].ToString() + "App_Data\\jiaowuDB.mdf");
67 System.Security.AccessControl.FileSecurity fileSecurity = fi.GetAccessControl();
68 fileSecurity.AddAccessRule(new FileSystemAccessRule("Everyone", FileSystemRights.FullControl, AccessControlType.Allow));
69 fileSecurity.AddAccessRule(new FileSystemAccessRule("Authenticated Users", FileSystemRights.FullControl, AccessControlType.Allow));
70 fileSecurity.AddAccessRule(new FileSystemAccessRule("Users", FileSystemRights.FullControl, AccessControlType.Allow));
71 fi.SetAccessControl(fileSecurity);
72 FileInfo fi1 = new FileInfo(Context.Parameters["targetdir"].ToString() + "App_Data\\jiaowuDB.ldf");
73 System.Security.AccessControl.FileSecurity fileSecurity1 = fi1.GetAccessControl();
74 fileSecurity1.AddAccessRule(new FileSystemAccessRule("Everyone", FileSystemRights.FullControl, AccessControlType.Allow));
75 fileSecurity1.AddAccessRule(new FileSystemAccessRule("Authenticated Users", FileSystemRights.FullControl, AccessControlType.Allow));
76 fileSecurity1.AddAccessRule(new FileSystemAccessRule("Users", FileSystemRights.FullControl, AccessControlType.Allow));
77 fi1.SetAccessControl(fileSecurity1);
78 }
79
80 string connectionString = GetConnectionString(null);
81 //保存數據連接詞,為卸載做准備
82 File.WriteAllText(Path.Combine(targetdir + "App_Data\\", "log.txt"), connectionString);
83 try
84 {
85 using (SqlConnection connection = new SqlConnection(connectionString))
86 {
87 connection.Open();
88 //使用數據庫文件創建數據庫,所以添加的網站項目中需要有App_Data文件夾和數據庫文件(jiaowuDB.mdf)和日志文件(jiaowuDB.ldf)
89 string sql = "sp_attach_db 'jiaowuDB','" + Context.Parameters["targetdir"].ToString() + "App_Data\\jiaowuDB.mdf','"
90 + Context.Parameters["targetdir"].ToString() + "App_Data\\jiaowuDB.ldf'";
91 ExecuteSQL(connection, sql);
92 connection.Close();
93 //修改config文件連接詞
94 string webconfigpath = Path.Combine(this.Context.Parameters["targetdir"].ToString(), "web.config");
95 string webcofnigstring = File.ReadAllText(webconfigpath).Replace("#constring#", GetConnectionString("jiaowuDB"));
96 File.WriteAllText(webconfigpath, webcofnigstring);
97
98 }
99 }
100 catch (Exception e)
101 {
102 throw new Exception(e.Message);
103 }
104 }
105 catch (Exception ex)
106 {
107 base.Rollback(stateSaver);
108
109 throw new Exception(ex.Message);
110 }
111 }
112
113 #region Connect 連接IIS服務器
114 public bool Connect()
115 {
116
117 if (iis == null)
118 return false;
119 try
120 {
121 _iisServer = new DirectoryEntry("IIS://" + iis + "/W3SVC/1");
122 _target = iis;
123 _connection = new ConnectionOptions();
124 _scope = new ManagementScope(@"//" + iis + @"/root/MicrosoftIISV2", _connection);
125 _scope.Connect();
126 }
127 catch
128 {
129
130 return false;
131 }
132 return IsConnected();
133 }
134
135 public bool IsConnected()
136 {
137 if (_target == null || _connection == null || _scope == null) return false;
138 return _scope.IsConnected;
139 }
140 #endregion
141
142 #region CreateWebsite 添加網站
143 public string CreateWebSite(string serverID, string serverComment, string defaultVrootPath, string HostName, string IP, string Port)
144 {
145 try
146 {
147 ManagementObject oW3SVC = new ManagementObject(_scope, new ManagementPath(@"IIsWebService='W3SVC'"), null);
148
149 if (IsWebSiteExists(serverID))
150 {
151 throw new Exception("服務器上已存在" + ISNAME);
152 }
153
154 ManagementBaseObject inputParameters = oW3SVC.GetMethodParameters("CreateNewSite");
155 ManagementBaseObject[] serverBinding = new ManagementBaseObject[1];
156 serverBinding[0] = CreateServerBinding(HostName, IP, Port);
157 inputParameters["ServerComment"] = serverComment;
158 inputParameters["ServerBindings"] = serverBinding;
159 inputParameters["PathOfRootVirtualDir"] = defaultVrootPath;
160 inputParameters["ServerId"] = serverID;
161
162 ManagementBaseObject outParameter = null;
163 outParameter = oW3SVC.InvokeMethod("CreateNewSite", inputParameters, null);
164
165 // 啟動網站
166 //string serverName = "W3SVC/" + serverID;
167 //ManagementObject webSite = new ManagementObject(_scope, new ManagementPath(@"IIsWebServer='" + serverName + "'"), null);
168 //webSite.InvokeMethod("Start", new object[] {});
169
170 return (string)outParameter.Properties["ReturnValue"].Value;
171 }
172 catch (Exception ex)
173 {
174 throw new Exception(ex.Message);
175 }
176 }
177
178 public ManagementObject CreateServerBinding(string HostName, string IP, string Port)
179 {
180 try
181 {
182 ManagementClass classBinding = new ManagementClass(_scope, new ManagementPath("ServerBinding"), null);
183 ManagementObject serverBinding = classBinding.CreateInstance();
184 serverBinding.Properties["Hostname"].Value = HostName;
185 serverBinding.Properties["IP"].Value = IP;
186 serverBinding.Properties["Port"].Value = Port;
187 serverBinding.Put();
188 return serverBinding;
189 }
190 catch
191 {
192 return null;
193 }
194 }
195 #endregion
196
197 #region IsWebSiteExists 判斷網站是否已經存在
198 public bool IsWebSiteExists(string serverID)
199 {
200 try
201 {
202 string siteName = "W3SVC/" + serverID;
203 ManagementObjectSearcher searcher = new ManagementObjectSearcher(_scope, new ObjectQuery("SELECT * FROM IIsWebServer"), null);
204
205 ManagementObjectCollection webSites = searcher.Get();
206 foreach (ManagementObject webSite in webSites)
207 {
208 if ((string)webSite.Properties["Name"].Value == siteName)
209 return true;
210 }
211
212 return false;
213 }
214 catch
215 {
216 return false;
217 }
218 }
219 #endregion
220
221 /// <summary>
222 /// 執行sql語句
223 /// </summary>
224 /// <param name="connection"></param>
225 /// <param name="sql"></param>
226 void ExecuteSQL(SqlConnection connection, string sql)
227 {
228 SqlCommand cmd = new SqlCommand(sql, connection);
229 cmd.ExecuteNonQuery();
230 }
231
232
233 /// <summary>
234 /// 獲取數據庫登錄連接字符串
235 /// </summary>
236 /// <param name="databasename">數據庫名稱</param>
237 /// <returns></returns>
238 private string GetConnectionString(string databasename)
239 {
240 return "server=" + Context.Parameters["server"].ToString() + ";database=" + (string.IsNullOrEmpty(databasename) ? "master" : databasename) + ";User ID=" + Context.Parameters["user"].ToString() + ";Password=" + Context.Parameters["pwd"].ToString();
241 }
242
243 }
244 }
View Code
Web項目的數據庫連接都是在Web.config中的,所以安裝過程還要修改Web.config的數據庫連接,這裡使用簡單的替換。
如下:
1 //修改config文件連接詞
2 string webconfigpath = Path.Combine(this.Context.Parameters["targetdir"].ToString(), "web.config");
3 string webcofnigstring = File.ReadAllText(webconfigpath).Replace("#constring#", GetConnectionString("jiaowuDB"));
4 File.WriteAllText(webconfigpath, webcofnigstring);
5
6 //Web 項目中WebConfig中配置
7 <add name="ConnectionString" connectionString="#constring#" providerName="System.Data.SqlClient" />
8 //就是替換#constring#為安裝過程中生成的新的鏈接字符串。
當然建站不止只有這些,還有新建應用程序池,大家可以去找找資料進行補充
安裝就到這兒了,現在來看看卸載。
卸載:
首先右鍵安裝項目》自定義操作》右鍵卸載》添加自定義操作》應用程序文件夾

選擇主輸出來自unLibrary1(活動)

不過我們這裡並不需要設置CustomActionData值,直接寫代碼
因為一般卸載的時候都不會去設置什麼數據
在示例中的做法在安裝的時候是沒有問題的,在卸載或者修復的時候,就會有問題了,卸載的時候我們需要刪除數據庫文件,那麼我就需要連接數據庫了
1 /// <summary>
2 /// 獲取數據庫登錄連接字符串
3 /// </summary>
4 /// <param name="databasename">數據庫名稱</param>
5 /// <returns></returns>
6 private string GetConnectionString(string databasename)
7 {
8 return "server=" + Context.Parameters["server"].ToString() + ";database=" + (string.IsNullOrEmpty(databasename) ? "master" : databasename) + ";User ID=" + Context.Parameters["user"].ToString() + ";Password=" + Context.Parameters["pwd"].ToString();
9 }
這裡是無法獲取正確的鏈接字符串,Context.Parameters["server"] 這些都已經不存在了,所以要想在卸載和修復的時候都可以用,則需要在安裝的時候保存連接字符串。
保存的位置和方式可根據自己的喜好存儲,畢竟連接字符串不是機密,示例中我們是保存在App_Date中的
1 string connectionString = GetConnectionString(null);
2 //保存數據連接詞,為卸載做准備
3 File.WriteAllText(Path.Combine(targetdir + "App_Data\\", "log.txt"), connectionString);
當然我們也可以在安裝保存的時候對連接字符串進行加密,在卸載中進行解密。
1 //判斷文件是不是存在
2 string webconfigpath = "";
3 if (File.Exists(s + "App_Data\\log.txt"))
4 {
//讀取文件中的連接字符串
5 webconfigpath = Path.Combine(s + "App_Data\\", "log.txt");
6
7 string connectionString = File.ReadAllText(webconfigpath);
8 try
9 {
10 using (SqlConnection connection = new SqlConnection(connectionString))
11 {
12 connection.Open();
13 string sql = " if exists(select * from sysdatabases where name='jiaowuDB' )begin alter database jiaowuDB set single_user with rollback immediate drop database jiaowuDB end ";
14 ExecuteSQL(connection, sql);
15 connection.Close();
16 }
17 File.Delete(s + "App_Data\\log.txt");
18 }
19 catch (Exception es)
20 {
21 MessageBox.Show("刪除數據失敗,請手動刪除!\n" + es.Message, "出錯啦!");
22 }
23 }
unLibrary1類代碼:

![]()
1 using System;
2 using System.Collections;
3 using System.Collections.Generic;
4 using System.ComponentModel;
5 using System.Configuration.Install;
6 using System.Linq;
7 using System.Management;
8 using System.Data.SqlClient;
9 using System.IO;
10 using System.DirectoryServices;
11 using System.Windows.Forms;
12
13
14 namespace unLibrary1
15 {
16 [RunInstaller(true)]
17 public partial class unInstaller1 : System.Configuration.Install.Installer
18 {
19 public unInstaller1()
20 {
21 InitializeComponent();
22 }
23
24 private string _target;
25 private DirectoryEntry _iisServer;
26 private ManagementScope _scope;
27 private ConnectionOptions _connection;
28 /// <summary>
29 /// 卸載
30 /// </summary>
31 /// <param name="savedState"></param>
32 public override void Uninstall(IDictionary savedState)
33 {
34 base.Uninstall(savedState);
35 //System.Diagnostics.Debugger.Launch(); //調試代碼
36 string serID = "66";
37 try
38 {
39 Connect();
40 string SiteID = IsWebSiteExists(serID);
41 if (SiteID == "") { return; }
42 else
43 {
44 //這裡要獲取保存的鏈接字符串
45 DirectoryEntry root = new DirectoryEntry("IIS://localhost/W3SVC");//參數只能這樣寫
46 DirectoryEntry site = (DirectoryEntry)root.Invoke("GetObject", "IIsWebServer", serID);//serID:為站點ID
47 DirectoryEntry siteVDir = site.Children.Find("Root", "IISWebVirtualDir");//參數只能這樣寫
48 string s = siteVDir.Properties["Path"].Value.ToString(); //安裝地址
49 //判斷文件是不是存在
50 string webconfigpath = "";
51 if (File.Exists(s + "App_Data\\log.txt"))
52 {
53 webconfigpath = Path.Combine(s + "App_Data\\", "log.txt");
54
55 string connectionString = File.ReadAllText(webconfigpath);
56 try
57 {
58 using (SqlConnection connection = new SqlConnection(connectionString))
59 {
60 connection.Open();
61 string sql = " if exists(select * from sysdatabases where name='jiaowuDB' )begin alter database jiaowuDB set single_user with rollback immediate drop database jiaowuDB end ";
62 ExecuteSQL(connection, sql);
63 connection.Close();
64 }
65 File.Delete(s + "App_Data\\log.txt");
66 }
67 catch (Exception es)
68 {
69 MessageBox.Show("刪除數據失敗,請手動刪除!\n" + es.Message, "出錯啦!");
70 }
71 }
72 DelSite(serID);
73 }
74 }
75 catch (Exception ex)
76 {
77 MessageBox.Show("卸載出錯!\n" + ex.Message, "出錯啦!");
78 }
79
80 }
81
82 #region Connect 連接IIS服務器
83 public bool Connect()
84 {
85 try
86 {
87 _iisServer = new DirectoryEntry("IIS://localhost/W3SVC/1");
88 _target = "localhost";
89 _connection = new ConnectionOptions();
90 _scope = new ManagementScope(@"//localhost/root/MicrosoftIISV2", _connection);
91 _scope.Connect();
92 }
93 catch
94 {
95
96 return false;
97 }
98 return IsConnected();
99 }
100 public bool IsConnected()
101 {
102 if (_target == null || _connection == null || _scope == null) return false;
103 return _scope.IsConnected;
104 }
105 #endregion
106
107
108 /// <summary>
109 /// 刪除站點
110 /// </summary>
111 /// <param name="WebSiteName">站點ID</param>
112 public void DelSite(string WebSiteID)
113 {
114 try
115 {
116 string SiteID = IsWebSiteExists(WebSiteID);
117 if (SiteID == "") return;
118
119 DirectoryEntry deRoot = new DirectoryEntry("IIS://localhost/W3SVC");
120 try
121 {
122 DirectoryEntry deVDir = new DirectoryEntry();
123 deRoot.RefreshCache();
124 deVDir = deRoot.Children.Find(SiteID, "IIsWebServer");
125 deRoot.Children.Remove(deVDir);
126 deRoot.CommitChanges();
127 deRoot.Close();
128 return;
129 }
130 catch (System.Exception)
131 {
132 return;
133 }
134 }
135 catch (Exception e)
136 {
137 MessageBox.Show("error:刪除站點失敗." + e.Message);
138 }
139 }
140
141 #region IsWebSiteExists 判斷網站是否已經存在
142 public string IsWebSiteExists(string serverID)
143 {
144 try
145 {
146 string siteName = "W3SVC/" + serverID;
147 ManagementObjectSearcher searcher = new ManagementObjectSearcher(_scope, new ObjectQuery("SELECT * FROM IIsWebServer"), null);
148
149 ManagementObjectCollection webSites = searcher.Get();
150 foreach (ManagementObject webSite in webSites)
151 {
152 if ((string)webSite.Properties["Name"].Value == siteName)
153 return serverID;
154 }
155
156 return "";
157 }
158 catch
159 {
160 return "";
161 }
162 }
163 #endregion
164
165
166 /// <summary>
167 /// 執行sql語句
168 /// </summary>
169 /// <param name="connection"></param>
170 /// <param name="sql"></param>
171 void ExecuteSQL(SqlConnection connection, string sql)
172 {
173 SqlCommand cmd = new SqlCommand(sql, connection);
174 cmd.ExecuteNonQuery();
175 }
176
177 }
178 }
unLibrary1
最後右鍵安裝項目》生成
生成安裝包

安裝流程預覽:






注:
我們有時間可以會有一些特殊要求,比如密文
這裡我們就需要用到 數據庫表編輯器(orca)了
orca下載地址:http://pan.baidu.com/s/1bpDoia7
使用orca打開剛生成的Setup.msi文件
選擇control,找到你要編輯的文本框,將Attributes改成2097159 ,保存
這裡我們是CustomTextA中Edit3

第一次發文,諸多不足,請多指教。