此项目是通过winform的打包程序来实现web网站的打包,打包程序是自定义的。
下面的webconfig的连接字符串的配置信息
<connectionStrings> <add name="DB_Exam_OnLine_YHKConnectionString" connectionString="Persist Security Info=False;Data Source=192.168.1.23;database=database_myself;User ID=sa;Password=sa;Packet Size=4096;Pooling=true;Max Pool Size=100;Min Pool Size=1" providerName="System.Data.SqlClient" /> </connectionStrings>
1、发布网站:右键点击web项目,“发布网站”将它发布到本地机器。
2、安装项目:从菜单处依次点 文件->新建->文件->项目->其他项目类型->安装和部署->安装项目。
3、添加文本框(A):安装项目->视图->用户界面->添加对话框,选择对话框(A)。(可以添加需要的对话框如下图)
4、对话框(A)的属性设置:
BannerText:数据库设置
BodyText:设置数据库连接字符串
Edit1Label:数据库服务器:
Edit1Property:DBSERVERNAME //这个是自己起的名字
Edit1Value:10.78.25.23 //此为默认值,可不设置
Edit1Visible:True
Edit2Label:数据库名称:
Edit2Property:DBNAME //这个是自己起的名字
Edit2Value:testDataBase //此为默认值,可不设置
Edit2Visible:True
Edit3Label:登录帐号:
Edit3Property:USERNAME //这个是自己起的名字
Edit3Value:sa //此为默认值,可不设置
Edit3Visible:True
Edit4Label:登录密码:
Edit4Property:PASSWORD //这个是自己起的名字
Edit4Value:
Edit4Visible:True
5、安装程序类:新建一c#类库项目“Install”,右键 添加->新建项->安装程序类,建立一安装程序类如下:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Configuration.Install; using System.IO; using System.DirectoryServices; using System.Reflection; using System.Data; using System.Data.SqlClient; using System.Management; using System.Collections; using Microsoft.Win32; using System.Collections.Specialized; using System.Diagnostics; using System.Net;//dns namespace Install { [RunInstaller(true)] public partial class GF_Installer : Installer { public GF_Installer() { InitializeComponent(); } //先设置私有成员,对应安装程序里接收到的用户输入 private string dbname; private string dbserver; private string user; private string pwd; private string iis; private string physicaldir; #region WriteWebConfig 修改web.config的连接数据库的字符串 private bool WriteWebConfig() { bool Restult = false; try { //加载配置文件 System.IO.FileInfo FileInfo = new System.IO.FileInfo(this.Context.Parameters["targetdir"] + "/web.config"); if (!FileInfo.Exists) { throw new InstallException("缺少配置文件 :" + this.Context.Parameters["targetdir"] + "/web.config"); } System.Xml.XmlDocument xmlDocument = new System.Xml.XmlDocument(); xmlDocument.Load(FileInfo.FullName); //修改连接字符串 foreach (System.Xml.XmlNode Node in xmlDocument["configuration"]["connectionStrings"]) { if (Node.Name == "add") { if (Node.Attributes.GetNamedItem("name").Value == "connetion") { Node.Attributes.GetNamedItem("connectionString").Value = String.Format("database={0};server={1};uid={2};pwd={3};", dbname, dbserver, user, pwd); } } } xmlDocument.Save(FileInfo.FullName); Restult = true; } catch { } return Restult; } #endregion #region 修改网站主目录 private bool CreateVirtualDir() { bool Restult = false; try { string constIISWebSiteRoot = "IIS://" + iis + "/W3SVC/1/ROOT";//网站顶层目录结构 DirectoryEntry root = new DirectoryEntry(constIISWebSiteRoot); root.Properties["Path"][0] = physicaldir;//设置物理地址 root.Invoke("AppCreate", true); root.Properties["AccessRead"][0] = true; //勾选读取(一定要先将此项勾选) root.Properties["AccessScript"][0] = true;//勾选脚本资源访问 root.Properties["EnableDirBrowsing"][0] = true;//勾选目录浏览 root.Properties["EnableDefaultDoc"][0] = true;//勾选启用默认内容文档 root.Properties["DefaultDoc"][0] = "Default.aspx";//设置起始页 root.CommitChanges(); Restult = true; } catch { throw; } return Restult; } #endregion #region 设置iis web服务扩展 SetWebServices() private bool SetWebServices() { bool Restult = false; try { string strRst = ExeCommand("iisext /EnExt /"ASP/"", true);//允许Active server Pages if (strRst.Contains("Enabling extension complete")) { Restult = true; } //获取最新版本的asp.net string cmdPath = @"C:/WINDOWS/Microsoft.NET/Framework/"; DirectoryInfo fi = new DirectoryInfo(cmdPath); DirectoryInfo[] fi2 = fi.GetDirectories(); string[] fi3 = new string[fi2.Length]; int k = 0; for (int i = 0; i < fi2.Length; i++) { string dirName = fi2[i].Name.ToString(); if (dirName.Contains("v") && dirName.Contains(".")) { fi3[k] = dirName; k++; } } strRst = ExeCommand("iisext /EnExt /"ASP.NET " + fi3[k - 1] + "/"", true);//允许ASP.NET v2.0.50727 if (strRst.Contains("Enabling extension complete")) { Restult = true; } strRst = ExeCommand("iisext /EnExt /"HTTPODBC/"", true);//允许Internet 数据连接器 if (strRst.Contains("Enabling extension complete")) { Restult = true; } } catch { throw; } return Restult; } #endregion #region 注册最新版本的asp.net RegistIIS() /// <summary> /// 注册IIS按钮事件 /// </summary> private bool RegistIIS() { bool Restult = false; try { string cmdPath = @"C:/WINDOWS/Microsoft.NET/Framework/"; DirectoryInfo fi = new DirectoryInfo(cmdPath); DirectoryInfo[] fi2 = fi.GetDirectories(); string[] fi3 = new string[fi2.Length]; int k = 0; for (int i = 0; i < fi2.Length; i++) { string dirName = fi2[i].Name.ToString(); if (dirName.Contains("v") && dirName.Contains(".")) { fi3[k] = dirName; k++; } } string strRst = cmdPath + fi3[k - 1] + "//" + "aspnet_regiis.exe -r"; strRst = ExeCommand(strRst, true); if (strRst.Contains("开始安装") && strRst.Contains("安装完毕")) { Restult = true; } } catch { throw; } return Restult; } #endregion #region 创建数据库 private bool CreateDBAndTable() { bool Restult = false; try { string sqlQuery = "osql.exe -U " + user + " -P " + pwd + " -S " + dbserver + " -i /"" + physicaldir + "//DBSQL.txt/""; WriteInstallInfo("uid=" + user + ";database=master;pwd=" + pwd + ";server=" + dbserver); string strRst = ExeCommand(sqlQuery, true); if (strRst.Contains("消息") || strRst.Contains("级别") || strRst.Contains("状态") || strRst.Contains("失败") || strRst.Contains("错误")) { Restult = false; } else { Restult = true; } } catch { throw; } return Restult; } #endregion #region 执行cmd命令 /// <summary> /// 执行cmd命令 /// </summary> /// <param name="commandText"></param> /// <returns></returns> public static string ExeCommand(string commandText, bool NewWindow) { string strOutput = ""; try { Process p = new Process(); p.StartInfo.FileName = "cmd.exe"; p.StartInfo.UseShellExecute = false; p.StartInfo.RedirectStandardInput = true; p.StartInfo.RedirectStandardOutput = true; p.StartInfo.RedirectStandardError = true; p.StartInfo.CreateNoWindow = NewWindow; p.Start(); p.StandardInput.WriteLine(commandText); p.StandardInput.WriteLine("exit"); strOutput += p.StandardOutput.ReadToEnd(); p.WaitForExit(); p.Close(); } catch (Exception e) { strOutput += e.Message; } return strOutput; } #endregion #region 写入安装信息 private bool WriteInstallInfo(string WriteInfo) { bool Restult = false; try { FileStream fst = new FileStream("C://Program Files//yhk//GF_Setup//Install.ini", FileMode.Create);//追加模式 StreamWriter m_Sw = new StreamWriter(fst, System.Text.Encoding.GetEncoding("utf-8"));//指定编码.否则将出错! m_Sw.WriteLine(WriteInfo); m_Sw.Close(); Restult = true; } catch { } return Restult; } #endregion #region 创建网站快捷方式 private bool CreateShortCut() { bool Restult = false; try { IPHostEntry ipHost = Dns.Resolve(Dns.GetHostName()); IPAddress ipAddr = ipHost.AddressList[0]; StreamWriter sw = new StreamWriter(File.Open(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "//我的站点.url", FileMode.Create, FileAccess.Write)); sw.WriteLine("[InternetShortcut]"); sw.WriteLine("URL=http://" + ipAddr.ToString() + "/Default.aspx"); sw.WriteLine("IconFile=" + physicaldir + "//main.ico"); sw.WriteLine("IconIndex=0"); sw.Flush(); sw.Close(); //创建用户"程序"菜单快捷方式及图标,借助.url生成网络快捷方式(要和界面添加的用户程序目录一致) /*处理"开始-程序"目录的位置,因为默认SpecialFolder.Programs会到当前用户的程序目录下,而我们要处理到All User的程序目录下, 因为在web部署项目中添加卸载快捷方式时,我们在"文件系统视图-右键-添加特殊文件夹-用户的'程序'菜单"是添加到All User的程序目录下的,所以下面用程序创建的要和界面添加的保持一致, 同时当添加到All User的程序目录下,那么所有用户的程序菜单中都会有的*/ string str = Environment.GetFolderPath(Environment.SpecialFolder.Programs); string[] arr = str.Split(new char[] { '//' }); arr[arr.Length - 3] = "All Users"; string t = ""; foreach (string i in arr) { t += i + "//"; } Directory.CreateDirectory(t + "高芳安装"); sw = new StreamWriter(File.Open(t + "高芳安装//我的站点.url", FileMode.Create, FileAccess.Write)); sw.WriteLine("[InternetShortcut]"); sw.WriteLine("URL=http://" + ipAddr.ToString() + "/Default.aspx"); sw.WriteLine("IconFile=" + physicaldir + "//main.ico");//此处不支持中文路径 sw.WriteLine("IconIndex=0"); sw.Flush(); sw.Close(); Restult = true; } catch { throw; } return Restult; } #endregion #region 修改文件权限 private bool ModifyFank() { bool Restult = false; try { //cacls 文件名 /e /c /g users:c //c为允许修改的权限 string strRst = ExeCommand("cacls /"" + physicaldir + "//bin" + "/" /e /c /g users:c", true); if (strRst.Contains("处理的文件") || strRst.Contains("处理的目录")) { Restult = true; } } catch { throw; } return Restult; } #endregion #region Install 从这里开始启动安装 public override void Install(IDictionary stateSaver) { //启动调试 System.Diagnostics.Debugger.Launch(); //先设置私有成员,对应安装程序里接收到的用户输入 base.Install(stateSaver); this.Context.Parameters["dbserver"] = Dns.GetHostName(); physicaldir = this.Context.Parameters["targetdir"].ToString(); // virtualdir = this.Context.Parameters["virtualdir"].ToString(); dbname = this.Context.Parameters["dbname"].ToString(); dbserver = this.Context.Parameters["dbserver"].ToString(); user = this.Context.Parameters["user"].ToString(); pwd = this.Context.Parameters["pwd"].ToString(); // iis = this.Context.Parameters["iis"].ToString(); iis = this.Context.Parameters["dbserver"].ToString(); // 执行SQL 安装数据库 可选择时恢复或者时直接创建 if (!CreateDBAndTable()) { throw new ApplicationException("创建数据库时出现严重错误!"); } //注册最新版本的asp.net if (!RegistIIS()) { throw new ApplicationException("注册最新版本的asp.net时出现严重错误!"); } // 添加网站 if (!CreateVirtualDir()) { throw new ApplicationException("添加网站时出现严重错误!"); } //添加web服务扩展 if (!SetWebServices()) { throw new ApplicationException("添加web服务扩展时出现严重错误!"); } // 修改web.config if (!WriteWebConfig()) { throw new ApplicationException("修改web.config时出现严重错误!"); } // 创建网站快捷方式 if (!CreateShortCut()) { throw new ApplicationException("创建网站快捷方式时出现严重错误!"); } // 修改文件夹权限 if (!ModifyFank()) { throw new ApplicationException("修改文件夹权限时出现严重错误!"); } } #endregion } }
6、添加项目输出: 编译dll文件
右键单击安装项目 添加->项目输出中选择“Install”,选中“主输出”,单击“确定”。这样你可以在解决方案安装项目树中看见多了“主输出来自Install(活动)”节点。
右键此安装项目 视图->自定义操作 中选择“安装”节点,右键 “添加自定义操作”,进入“应用程序文件夹”,选中“主输出来自Install(活动)”,单击“确定。
选中“安装”下的“主输出来自Install(活动)”节点,在其属性窗口中设置CustomActionData 的值为 /dbname=[DBNAME] /dbserver=[DBSERVERNAME] /user=[USERNAME] /pwd=[PASSWORD] /targetdir="[TARGETDIR]/",这是设置文本框(A)的输入与安装程序类中要访问的变量之间的对应关系,其中targetdir="[TARGETDIR]/"代表应用程序安装目录(注意:各个对应关系之间必须用空格隔开)。
8、添加文件:发布网站时生成的文件夹全部克隆到安装项目中。
右键安装项目,视图->文件系统 在“应用程序文件夹”下按发布网站时生成的文件夹里的结构添加文件夹与文件。
9、编译生成, 到安装项目的debug或者release目录下可看见生成的安装包。
10、添加卸载功能:
添加一个控制台应用程序,uninstall.cs
using System; using System.Collections.Generic; using System.Text; using System.Data.SqlClient; using System.IO; using System.DirectoryServices; using System.Net; namespace UnInstall { class Program { #region ExecuteSql 执行SQL语句,参考自MSDN private static void ExecuteSql(SqlConnection sqlConn, string sqlstring) { SqlCommand Command = new SqlCommand(); try { Command.Connection = sqlConn; Command.CommandText = sqlstring; Command.CommandType = System.Data.CommandType.Text; if (Command.Connection.State == System.Data.ConnectionState.Closed) { Command.Connection.Open(); } Command.ExecuteNonQuery(); } finally { if (Command.Connection.State == System.Data.ConnectionState.Open) { Command.Connection.Close(); } } } #endregion #region GetSql 从文件中读取SQL,在读取包含SQL脚本的文件时需要用到,参考自MSDN /// <summary> /// 读取配置时生成的安装文件信息Install.ini /// </summary> /// <param name="FileName">Install.ini</param> /// <returns>"uid=" + user + ";database=master;pwd=" + pwd + ";server=" + dbserver</returns> private static string GetSqlConn(string FileName) { try { //"C://Program Files//yhk//GF_Setup//Install.ini" FileName = "C://Program Files//yhk//GF_Setup//" + FileName; string contextFile = string.Empty; if (!File.Exists(FileName)) //如果文件不存在,则创建 { StreamWriter sr = File.CreateText(FileName); sr.Close(); } StreamReader readFile = new StreamReader(FileName); contextFile = readFile.ReadToEnd(); readFile.Close(); return contextFile; } catch (Exception getException) { throw new ApplicationException(getException.Message); } } #endregion #region 修改网站主目录 private static bool CreateVirtualDir() { bool Restult = false; try { string constIISWebSiteRoot = "IIS://" + Dns.GetHostName() + "/W3SVC/1/ROOT"; DirectoryEntry root = new DirectoryEntry(constIISWebSiteRoot); root.Properties["Path"][0] = @"C:/Program Files/yhk/YJXT";//@"C:/Inetpub/wwwroot";//设置物理地址 root.Invoke("AppCreate", true); root.Properties["DefaultDoc"][0] = "Default.aspx";//设置起始页 root.CommitChanges(); Restult = true; } catch { } return Restult; } #endregion #region 删除文件夹及文件 /// <summary> /// 删除文件夹及其子文件 /// </summary> /// <param name="dir">文件夹的路径</param> private static void DeleteFolder(string dir) { try { if (Directory.Exists(dir)) //如果存在这个文件夹删除之 { foreach (string d in Directory.GetFileSystemEntries(dir)) { if (!d.Contains("UnInstall.exe")) { if (File.Exists(d)) { File.Delete(d); //直接删除其中的文件 } else { DeleteFolder(d); //递归删除子文件夹 } } } // Directory.Delete(dir); //删除已空文件夹 } } catch { throw; } } #endregion #region 删除快捷方式 private static void DeleteShortCut() { try { string FileName = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "//我的站点.url"; if (File.Exists(FileName)) { File.Delete(FileName); } string str = Environment.GetFolderPath(Environment.SpecialFolder.Programs); string[] arr = str.Split(new char[] { '//' }); arr[arr.Length - 3] = "All Users"; string t = ""; foreach (string i in arr) { t += i + "//"; } FileName = t + "高芳安装//我的站点.url"; if (File.Exists(FileName)) { File.Delete(FileName); } Directory.Delete(t + "高芳安装"); } catch { throw; } } #endregion #region 分离数据库存储过程 private static string AttachDB() { return " create proc P_KillConnections @dbname varchar(200)" + "as" + " declare @sql nvarchar(500)" + " declare @spid nvarchar(20)" + " declare #tb cursor for select spid=cast(spid as varchar(20)) from master..sysprocesses where dbid=db_id(@dbname) open #tb fetch next from #tb into @spid" + " while @@fetch_status=0" + " begin" + " exec('kill '+@spid)" + " fetch next from #tb into @spid end" + " close #tb" + " deallocate #tb"; } #endregion static void Main(string[] args) { SqlConnection sqlConn = new SqlConnection(GetSqlConn("Install.ini")); string sql = "use master if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[P_KillConnections]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)" + " drop procedure [dbo].[P_KillConnections]"; ExecuteSql(sqlConn, sql); sql = AttachDB(); ExecuteSql(sqlConn, sql); sql = "exec P_KillConnections wxd"; ExecuteSql(sqlConn, sql); sql = "USE MASTER IF EXISTS (SELECT NAME FROM SYSDATABASES WHERE NAME='wxd') DROP DATABASE wxd"; ExecuteSql(sqlConn, sql); // 添加网站 if (!CreateVirtualDir()) { throw new ApplicationException("添加网站时出现严重错误!"); } DeleteShortCut(); DeleteFolder(@"C:/Program Files/yhk/GF_Setup"); string sysroot = System.Environment.SystemDirectory; System.Diagnostics.Process.Start(sysroot + "//msiexec.exe", "/x {D022C62C-555D-4103-A2AB-4CEB90C6297D} /qr"); } } }
注意:{D022C62C-555D-4103-A2AB-4CEB90C6297D},是安装项目的ProductCode(项目,f4)必须与安装的程序一至。
把这个程序最后生成的.exe文件添加到项目里安装程序文件中即可,生成了Uninstall.exe的卸载文件。当然可以在“用户的“程序”菜单”中添加文件夹(你的网站的名字)然后,的Uninstall.exe的快捷方式(在应用程序文件夹里点击Uninstall.exe右击创建快捷方式然后把它拖到你要的地方就好了)建立到这里。(可以给卸载程序更换图标,但是该图标必须是标准的图标文件。)
在用户界面的每个窗口可以使用自己的图片,美化程序。SplashBitmap(启动画面)BannerBitmap(其它的页面的图片属性名字)