1. 主页 > vs安装问题 > VS2005安装问题 >

VS2005制作Web安装程序

网站完成后,需要部署到目标机器上,方法有很多,直接把文件Copy到目标机器上,执行SQL脚本,配置IIS,这样可以做到;也可以使用InstallShield这样到专业制作软件来打包。本篇文章是使用VS2005自带到安装部署工具来制作exe安装文件。   涉及到到内容包括:使用安装部署工具,建立数据库,配置IIS,文件操作,注册表等。参考了网上关于使用VS制作安装程序的文章。环境:Windows2003 + VS2005 + SQL2005。 注:本文只是为了实现,没有强调方法,变量等的写法标准。   使用VS2005制作安装程序的时候,有多种选择,如下图: 我想一般常用的可能就最上面的两种。当使用Web安装项目时,执行制作好的msi安装文件时,会发现实际上是添加虚拟目录而不是添加网站,而且无法选择安装目录,当然,可以自己写脚本来对IIS进行修改。不过在这篇文章里,将不采用此模式。本篇文章用的是使用“安装项目”,就和打包WinForm程序一样,把Web文件部署到目标机器上,然后重写install方法,配置IIS,执行SQL脚本,修改web.config文件等。   在开始整个过程之前,需要先了解一下“预编译”的概念,MSDN上的说明是:默认情况下,在用户首次请求资源(如网站的一个页)时,将动态编译 ASP.NET 网页和代码文件。第一次编译页和代码文件之后,会缓存编译后的资源,这样将大大提高随后对同一页提出的请求的效率。请查阅MSDN“预编译”相关文档。   准备一个文件DBSQL.txt,在里面包含连接数据库后需要执行的SQL脚本,在本例中使用了简单的一个Create Tabel的SQL。   好了,现在开干,吼吼~~~~~~~~~~   打开VS2005,打开一个网站项目,这里是打开的本地localhost,如图: 新加一个页面,随便取个名字(本文中为ClientCallback.aspx),然后写一个简单的按钮事件即可,这不是本文的重点,由你随意处理^_^ 再添加web配置文件即web.config,在下添加               此文件到时候是需要发布到目标机器上的。(关于连接数据库字符串,VS2005里面有专门的connectionStrings,本文未使用,可查阅帮助) 点击生成网站,访问页面,ok! 选择菜单生成=》发布网站: 点击确定后,网站已经生成,这些就是需要部署到目标机器上的所有文件。   点击菜单文件=》添加=》新建项目,添加安装部署项目,如图:     添加安装项目类库: 删除默认的Class1.cs,新加一个安装程序类文件,名为MyInstaller.cs   在此项目中,添加对System.EnterpriseServices和System.DirectoryServices的引用,在操作IIS的时候,需要用到。在文件中添加: using System; using System.IO; using System.DirectoryServices; using System.Reflection; using System.Data; using System.Data.SqlClient; using System.Configuration.Install; using System.Management; using System.Collections; using Microsoft.Win32; using System.Collections.Specialized;如果编译的时候出错,请添加相关引用。   修改文件如下图:   注意要手动添加Installer!   将DBSQL.txt文件放到此项目中,在属性中设置为“嵌入的资源”   回到MyWebSetup项目,点击查看属性,可以设置安装文件到显示相关信息,如图     选择文件系统,如图: 然后:   (在文件系统中,在属性里面可以设置安装程序默认到安装路径)   添加一个叫bin文件夹并添加在生成网站时bin目录下的dll文件,如图:   在应用程序文件夹下在生成网站时目录下的文件,添加后如图:     选择“用户界面编辑器”,添加两个文本框A和B,A将作为安装新站点后的IIS设置,B将作为数据库操作时的参数设置,调整位置后如下: 调整A的属性,这里只选择了显示两个输入框,属性分别为IISSERVER和PORT,值为localhost和9998,其他的你可以自己调整。如图:   文本框B的设置如下: OK,文本框设置完毕。当然,你还可以选择其他的多种文本框,如协议什么的。   打开自定义操作面板:     然后: 在CustomActionData中输入: /dbname=[DBNAME] /server=[DBSERVERNAME] /user=[USERNAME] /pwd=[PASSWORD] /iis=[IISSERVER] /port=[PORT] /targetdir="[TARGETDIR]/" 这些参数就是文本框A和B上的输入框的值,在安装过程中可以获得,然后进行处理。   至此,基本的安装文件已经制作完毕。进行生成,然后点击安装,可以看到文件已经复制到了相应到目录。接下来就要接收参数对IIS和数据库进行处理。   打开SetupClassLibrary项目下的MyInstaller.Designer.cs,修改此文件。 申明几个变量:         private System.Data.SqlClient.SqlConnection sqlConn;         private System.Data.SqlClient.SqlCommand Command;         private string DBName;         private string ServerName;         private string AdminName;         private string AdminPwd;      private string iis;         private string port;         private string dir;         public static string VirDirSchemaName = "IIsWebVirtualDir";           private string _target;         private DirectoryEntry _iisServer;         private ManagementScope _scope;         private ConnectionOptions _connection;   连接数据库服务器到方法: #region ConnectDatabase 连接数据库         private bool ConnectDatabase()         {             if (Command.Connection.State != ConnectionState.Open)             {                 try                 {                     Command.Connection.Open();                 }                 catch(Exception e)                 {                     return false;                 }             }             return true;         }         #endregion 如果不能正确连接数据库服务器,请检查你的连接字符串,或者将连接字符串写入文件查看。不好意思,我不知道如何对这种安装部署程序进行debug,sorry咯!   读取SQL文件的方法: #region GetSql 从文件中读取SQL,在读取包含SQL脚本的文件时需要用到,参考自MSDN         private string GetSql(string Name)         {             try             {                 Assembly Asm = Assembly.GetExecutingAssembly();                 Stream strm = Asm.GetManifestResourceStream(Asm.GetName().Name + "." + Name);                 StreamReader reader = new StreamReader(strm);                 return reader.ReadToEnd();             }             catch (Exception getException)             {                 throw new ApplicationException(getException.Message);             }         }         #endregion 可以将此需要执行的SQL脚本放在此文本中   执行SQL语句的方法: #region ExecuteSql 执行SQL语句,参考自MSDN         private void ExecuteSql(string DataBaseName, string sqlstring)         {             Command = new System.Data.SqlClient.SqlCommand(sqlstring, sqlConn);             if (ConnectDatabase())             {                 try                 {                     Command.Connection.ChangeDatabase(DataBaseName);                     Command.ExecuteNonQuery();                 }                 finally                 {                     Command.Connection.Close();                 }             }         }         #endregion   创建数据库及数据库表: #region CreateDBAndTable 创建数据库及数据库表,参考自MSDN         protected bool CreateDBAndTable(string DBName)         {                         bool Restult = false;             try             {                 ExecuteSql("master", "USE MASTER IF EXISTS (SELECT NAME FROM SYSDATABASES WHERE NAME='" + DBName + "') DROP DATABASE " + DBName);                 ExecuteSql("master", "CREATE DATABASE " + DBName);                 ExecuteSql(DBName, GetSql("DBSQL.txt"));                                 Restult = true;               }             Catch             {             }             return Restult;         }         #endregion   从备份文件恢复数据库及数据库表 #region RestoreDB 从备份文件恢复数据库及数据库表         ///         /// 从备份文件恢复数据库及数据库表         ///         /// 数据库名         /// 配件中数据库脚本资源的名称         ///         protected bool RestoreDB(string DBName)         {               dir = this.Context.Parameters["targetdir"];             bool Restult = false;               string MSQL = "RESTORE DATABASE " + DBName +                 " FROM DISK = '" + dir + @"data.bak' " +                 " WITH MOVE 'Test' TO '" + @"c:/" + DBName + ".mdf', " +                 " MOVE 'Test_log' TO '" + @"c:/" + DBName + ".ldf' ";               try             {                 ExecuteSql("master", "USE MASTER IF EXISTS (SELECT NAME FROM SYSDATABASES WHERE NAME='" + DBName + "') DROP DATABASE " + DBName);                 ExecuteSql("master", MSQL);                   Restult = true;             }             finally             {                 // 删除备份文件                 try                 {                     File.Delete(dir + @"data.bak");                 }                 catch                 {                 }             }               return Restult;         }         #endregion 这里可以到注册表读取SQL Server的安装路径,把恢复后的数据库文件放到data目录地下。在本例中,只是实现了恢复,并未进行标准的操作。其中Test和Test_log时备份时数据库的文件信息。如果想要从备份文件中恢复,请把文件包含到项目里并且设置和DBSQL.txt一样,嵌入到程序里。最后执行删除。不过我想应该有办法不把文件先安装到目标机器上,而是有方法想读取DBSQL.txt文件一样,直接恢复数据库,不过确实没想到办法,失败!   网站安装好后,需要设置web.config文件,这里只涉及到连接字符串到设置,其他的可以同理修改。         #region WriteWebConfig 修改web.config的连接数据库的字符串         private bool WriteWebConfig()         {             System.IO.FileInfo FileInfo = new System.IO.FileInfo(this.Context.Parameters["targetdir"] + "/web.config");             if (!FileInfo.Exists)             {                 throw new InstallException("Missing config file :" + this.Context.Parameters["targetdir"] + "/web.config");             }               System.Xml.XmlDocument xmlDocument = new System.Xml.XmlDocument();             xmlDocument.Load(FileInfo.FullName);               bool FoundIt = false;             foreach (System.Xml.XmlNode Node in xmlDocument["configuration"]["appSettings"])             {                 if (Node.Name == "add")                 {                     if (Node.Attributes.GetNamedItem("key").Value == "ConnectionString")                     {                         Node.Attributes.GetNamedItem("value").Value = String.Format("Persist Security Info=False;Data Source={0};database={1};User ID={2};Password={3};Packet Size=4096;Pooling=true;Max Pool Size=100;Min Pool Size=1", ServerName, DBName, AdminName, AdminPwd);                         FoundIt = true;                     }                 }             }               if (!FoundIt)             {                 throw new InstallException("Error when writing the config file: web.config");             }               xmlDocument.Save(FileInfo.FullName);             return FoundIt;         }         #endregion     #region WriteRegistryKey 写注册表。安装部署中,直接有一个注册表编辑器,可以在那里面设置。         private void WriteRegistryKey()         {             // 写注册表             RegistryKey hklm = Registry.LocalMachine;             RegistryKey cqfeng = hklm.OpenSubKey("SOFTWARE", true);               RegistryKey F = cqfeng.CreateSubKey("cqfeng");               F.SetValue("FilePath", "kkkk");         }         #endregion   操作IIS,建立网站等。可参考: VS2005制作网页对IIS进行操作   #region Connect 连接IIS服务器         public bool Connect()         {               if (iis == null)                 return false;             try             {                 _iisServer = new DirectoryEntry("IIS://" + iis + "/W3SVC/1");                 _target = iis;                 _connection = new ConnectionOptions();                 _scope = new ManagementScope(@"//" + iis + @"/root/MicrosoftIISV2", _connection);                 _scope.Connect();             }             catch             {                   return false;             }             return IsConnected();         }           public bool IsConnected()         {             if (_target == null || _connection == null || _scope == null) return false;             return _scope.IsConnected;         }         #endregion   #region IsWebSiteExists 判断网站是否已经存在         public bool IsWebSiteExists(string serverID)         {             try             {                 string siteName = "W3SVC/" + serverID;                 ManagementObjectSearcher searcher = new ManagementObjectSearcher(_scope, new ObjectQuery("SELECT * FROM IIsWebServer"), null);                   ManagementObjectCollection webSites = searcher.Get();                 foreach (ManagementObject webSite in webSites)                 {                     if ((string)webSite.Properties["Name"].Value == siteName)                         return true;                 }                   return false;             }             catch             {                 return false;             }         }         #endregion           #region GetNextOpenID 获得一个新的ServerID         private int GetNextOpenID()         {            DirectoryEntry iisComputer = new DirectoryEntry("IIS://localhost/w3svc");             int nextID = 0;             foreach (DirectoryEntry iisWebServer in iisComputer.Children)             {                 string sname = iisWebServer.Name;                 try                 {                     int name = int.Parse(sname);                     if (name > nextID)                     {                         nextID = name;                     }                 }                 catch                 {                 }             }             return ++nextID;         }         #endregion   #region CreateWebsite 添加网站         public string CreateWebSite(string serverID, string serverComment, string defaultVrootPath, string HostName, string IP, string Port)         {             try             {                 ManagementObject oW3SVC = new ManagementObject(_scope, new ManagementPath(@"IIsWebService='W3SVC'"), null);                   if (IsWebSiteExists(serverID))                 {                     return "Site Already Exists...";                 }                   ManagementBaseObject inputParameters = oW3SVC.GetMethodParameters("CreateNewSite");                 ManagementBaseObject[] serverBinding = new ManagementBaseObject[1];                 serverBinding[0] = CreateServerBinding(HostName, IP, Port);                 inputParameters["ServerComment"] = serverComment;                 inputParameters["ServerBindings"] = serverBinding;                 inputParameters["PathOfRootVirtualDir"] = defaultVrootPath;                 inputParameters["ServerId"] = serverID;                                 ManagementBaseObject outParameter = null;                 outParameter = oW3SVC.InvokeMethod("CreateNewSite", inputParameters, null);                                 // 启动网站                 string serverName = "W3SVC/" + serverID;                 ManagementObject webSite = new ManagementObject(_scope, new ManagementPath(@"IIsWebServer='" + serverName + "'"), null);                 webSite.InvokeMethod("Start", null);                   return (string)outParameter.Properties["ReturnValue"].Value;             }             catch (Exception ex)             {                 return ex.Message;             }         }           public ManagementObject CreateServerBinding(string HostName, string IP, string Port)         {             try             {                 ManagementClass classBinding = new ManagementClass(_scope, new ManagementPath("ServerBinding"), null);                 ManagementObject serverBinding = classBinding.CreateInstance();                 serverBinding.Properties["Hostname"].Value = HostName;                 serverBinding.Properties["IP"].Value = IP;                 serverBinding.Properties["Port"].Value = Port;                 serverBinding.Put();                 return serverBinding;             }             catch             {                 return null;             }         }         #endregion     好了,准备工作已经做完,现在开始写最重要的Install方法了 整个方法写完后如下: #region Install 安装         ///         /// 安装数据库         ///         ///         public override void Install(IDictionary stateSaver)         {              base.Install(stateSaver);               dir = this.Context.Parameters["dir"];               DBName = this.Context.Parameters["DBNAME"].ToString();             ServerName = this.Context.Parameters["server"].ToString();             AdminName = this.Context.Parameters["user"].ToString();             AdminPwd = this.Context.Parameters["pwd"].ToString();             iis = this.Context.Parameters["iis"].ToString(); ;             port = this.Context.Parameters["port"].ToString();                         //写入获取的安装程序中的变量,此段代码为调试用可以不添加             this.sqlConn.ConnectionString = "Packet size=4096;User ID=" + AdminName + ";Data Source=" + ServerName + ";Password=" + AdminPwd + ";Persist Security Info=False;Integrated Security=false";               // 执行SQL 安装数据库 可选择时恢复或者时直接创建             if(!CreateDBAndTable(DBName))             {                 throw new ApplicationException("创建数据库时出现严重错误!");             }                           // 从备份数据库文件恢复数据库             /*             if (!RestoreDB(DBName))             {                 throw new ApplicationException("恢复数据库时出现严重错误!");             }             */               // 添加网站             Connect();             //string serverID = GetNextOpenID().ToString();             //string serverComment = websitenName;                        // 下面的信息为测试,可以自己编写文本框来接收用户输入信息             string serverID = "5555";             string serverComment = "cqfeng";             string defaultVrootPath = this.Context.Parameters["targetdir"];             if (defaultVrootPath.EndsWith(@"/"))             {                 defaultVrootPath = defaultVrootPath.Substring(0, defaultVrootPath.Length-1);             }             string HostName = "";             string IP = "";             string Port = port;             string sReturn = CreateWebSite(serverID, serverComment, defaultVrootPath, HostName, IP, Port);                         // 修改web.config             if (!WriteWebConfig())             {                 throw new ApplicationException("设置数据库连接字符串时出现错误");             }               // 写注册表             WriteRegistryKey();         }         #endregion   删除时的方法。在本文中未详细操作,比如删除站点,删除数据库等。如果需要,请你自己补足 #region Uninstall 删除         public override void Uninstall(IDictionary savedState)         {             if (savedState == null)             {                 throw new ApplicationException("未能卸载!");             }             else             {                 base.Uninstall(savedState);             } }         #endregion     编译,然后选择安装,如图: 第一图: 第二图:   第三图: 抱歉,我不知道在这里怎么使登录密码框输入时显示为*号   第四图: 第五图:   安装: 安装完成:   安装后的IIS   安装目录: 安装后的数据库:   至此,一个简单的部署web程序的exe文件已经完成,当然,省略了很多东西,比如,对安装机器的判断(IIS版本,Framework版本,SQL Server版本等),IIS站点属性等设置(默认页面,访问权限,执行权限等),卸载程序时应该删除的东西等等。这些东西,在MSDN里面可以查找到相关说明,如果你需要,只有辛苦一下了,嘿嘿。 相信有了这些,自己用WinForm来写安装程序也时可以了哈。   问题:安装的时候输入密码时无法显示为*号;安装文件夹中出现编译后的安装类编译后的dll文件。哪位大哥对这些比较熟悉的,指点指点……………..   写得不是很仔细,如果有问题或者错误,请你自己多调试一下!         我跟着上面的步骤做: 1:把数据库和IIS建立摒弃,只做程序的发布,成功! 2:把建立【表,视图,存储过程】的SQL语句放到DBSQL.txt中,安装上面的步骤,把DBSQL.txt作为嵌入资源,加入数据库的建立,结果出现错误是“创建数据库时出现严重错误”。      问题1:
#region ExecuteSql 执行SQL语句,参考自MSDN         private void ExecuteSql(string DataBaseName, string sqlstring)         {                         Command = new System.Data.SqlClient.SqlCommand(sqlstring, sqlConn);             if (ConnectDatabase())             {                 try                 {                     Command.Connection.ChangeDatabase(DataBaseName);                     Command.ExecuteNonQuery();                 }                 finally                 {                     Command.Connection.Close();                 }             }         }         #endregion
 问题出在ExecuteSq这个方法上面,sqlConn并没有创建, 解决办法: 所以只要在 Command = new System.Data.SqlClient.SqlCommand(sqlstring, sqlConn); 这一条语句前面加上   sqlConn = new SqlConnection("user id="+AdminName+";password="+AdminPwd+";database=master;server="+ServerName); // AdminName必须为该数据库具有建立数据库权限的用户,如sa     修改为这一步之后还是存在同样的问题“创建数据库时出现严重错误”,上网搜索,方向很多人遇到数据库可以建立,但是数据库内并没有存在任何表,视图和存储过程。经过分析: 问题2: ExecuteSql(DBName, GetSql("DBSQL.txt"));  对于把建立表,视图和存储过程的SQL语句发到DBSQL.txt中,使用GetSql(string Name)方法,会出现错误,具体错误在哪里,我还没有到达到那种水平,要是谁知道,可以给我留个言!先谢了! 解决办法: 把所有的建立表的SQL语句发到一个Table.txt中,每一个“建立视图”和“建立存储过程”的SQL语句放到单独的txt中(“建立视图”和“建立存储过程”的SQL语句要是想“建立表”那样全部放到一个txt中,也会出现错误,应该是GetSql(string Name)方法的问题),执行“建立表”->建立视图->建立存储过程(顺序掉转不知道能不能成功,具体没有试过) 解决上面两个问题,就可以建立相应的数据库以及对应的表,视图和存储过程。 现在要去踢球,就先写道这里,今晚在把剩下的问题和解决的办法写出来。………………

本文由VS软件圈(vssoft.net)发布,不代表VS软件圈立场,转载联系作者并注明出处:https://vssoft.net/vsazwt/VS2005anzhuangwenti/2020/0721/416.html

联系我们

在线咨询:点击这里给我发消息

微信号:PREEE8

工作日:9:30-18:30,节假日休息