原文:WEB项目(B/S系统)打包安装(总结篇)

打包安装程序的制作选择性还很多的,有installshield,wise installer,inno
setup这几个做打包安装项目都是很强大的,要搞出界面大气个性化的安装,还是得用这几个才行,我这篇说的是.NET自带的安装项目打包WEB系统的,.NET打包安装项目虽然傻傻的,也比较丑,但是搭建安装项目快速也能满足总体的要求,如果没有足够的时间研究重量级的安装工具,短时间内用.NET自带的安装项目也是一个良好的选择。网上有很多关于用.NET打包WEB项目的文章,大体是那样的,但不是很全面,有个别细节并没有涉及,先说下这个安装打包项目的主要功能:

一、安装前系统检测

主要检测SQL
SERVER是否安装,站点名称和端口号是否重复等,framework自动检测没有的话先安装,本身自带就有此功能,IIS是必须要求的,不然没法创建站点。

  二、项目文件安装到指定文件夹并根据安装时的数据库配置修改webconfig连接

三、附加数据库

打包时可以把mdf文件放到WEB项目文件夹下,生成安装文件时就会自动打包进去,安装时执行附加即可。

四、注册COM组件(如果项目中涉及到COM的话)

五、创建WEB站点

六 、创建虚拟目录

这里的虚拟目前是根据打包的项目需要进行的,因为有的WEB项目结构比较复杂,比如一个系统除了本身项目的发布文件,还有另外的独立特殊功能的项目作为虚拟目录的形式一起运行,类似于插拔式的插件一样,需要的话直接拷贝到站点下,设置虚拟目录,系统菜单做好链接指向其页面就可以了。

七、创建桌面快捷方式

比如可以把系统的登录页面或其它起始页作为安装时指定的快捷方式

八、项目卸载

项目的卸载主要包括删除项目文件,卸载附加的数据库,删除站点及桌面快捷方式等

安装WEB项目的前提条件是需要在用户电脑上先安装SQL SERVER数据库(或其它数据库)和IIS信息管理器。

1)安装项目主要涉及的是安装类里面的操作,包括安装和卸载的方法重写等,安装时需要记录用户通过安装界面输入的信息,这里我们可以用XML文件作为记录配置文件,主要是在卸载的时候需要用到用户输入的相关信息,数据库连接串的记录操作如下:

 /// <summary>

/// 获取数据库登录连接字符串

/// </summary>

/// <param name="databasename">数据库名称</param>

/// <returns></returns>

        private string GetConnectionString(string databasename)

{

string ConnStr = "server=" + Context.Parameters["server"].ToString() + ";database=" + (string.IsNullOrEmpty(databasename) ? "master" : databasename) + ";uid=" + Context.Parameters["user"].ToString() + ";pwd=" + Context.Parameters["pwd"].ToString();

if (string.IsNullOrEmpty(databasename)) //将连接串写入XML文件,供卸载操作时读取

            {

dbpath = Path.Combine(this.Context.Parameters["installdir"].ToString(), "dbconfig.xml");

OperateXML.UpdateXMLNode(dbpath, "ConnString", ConnStr);

}

else

{

dbpath = Path.Combine(this.Context.Parameters["installdir"].ToString(), "dbconfig.xml");

OperateXML.UpdateXMLNode(dbpath, "DbName", databasename);

}

return ConnStr;

}

2)安装检测

 /// <summary>

/// 判断是否安装了SQL SERVER

/// </summary>

/// <returns></returns>

        private bool ExistSqlServerService()

{

bool Exist = false;

ServiceController[] service = ServiceController.GetServices();

for (int i = 0; i < service.Length; i++)

{

if (service[i].ServiceName.Length > 5 && service[i].ServiceName.Substring(0, 5) == "MSSQL") //if (service[i].ServiceName == "MSSQLSERVER")

                {

Exist = true;

break;

}

}

return Exist;

}

这里是根据服务名称判断的,如果是SQLSERVER
EXPRESS版的话,服务名是MSSQL$EXPRESS,其它的数据库实例也是MSSQL$+实例名

 /// <summary>

/// 检测IIS及版本号

/// </summary>

/// <returns></returns>

        public string GetIISVerstion()

{

RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\INetStp");

if (key == null)

return string.Empty;

else

return Convert.ToString(key.GetValue("MajorVersion")) + "." + Convert.ToString(key.GetValue("MinorVersion"));

}

 
 
 
 
 
 string entPath = String.Format("IIS://{0}/w3svc", "localhost");



        /// <summary>

/// 端口号是否重复

/// </summary>

/// <returns></returns>

        private bool IsExistSitePort()

{

bool exist = false;

DirectoryEntry ent = GetDirectoryEntry(entPath);

foreach (DirectoryEntry child in ent.Children)

{

if (child.SchemaClassName == "IIsWebServer")

{

if (child.Properties["ServerBindings"].Value != null && child.Properties["ServerBindings"].Value.ToString().Split(':').Length > 1)

{

if (child.Properties["ServerBindings"].Value.ToString().Split(':')[1] == Context.Parameters["siteport"].ToString())

{

exist = true;

break;

}

}

}

}

return exist;

}

child.Properties["ServerBindings"].Value 是绑定属性,其实就是下面这个图里的属性

但是有的站点可能会分配两个端口,child.Properties["ServerBindings"].Value 就是 System.Object[] 字符

        /// <summary>

/// 站点名称是否存在

/// </summary>

/// <returns></returns>

        private bool IsExistSiteName(string sitename)

{

bool exist = false;

using (DirectoryEntry root = new DirectoryEntry(entPath))

{

foreach (DirectoryEntry Child in root.Children)

{

if (Child.SchemaClassName == "IIsWebServer")

{

string WName = Child.Properties["ServerComment"].Value.ToString();

if (sitename == WName)

{

exist = true;

break;

}

}

}

root.Close();

}

return exist;

}

3)安装并复制文件

复制文件的操作在OnBeforeInstall方法中就已经完成,在该方法中可以替换数据库连接字符串操作等。

 protected override void OnBeforeInstall(IDictionary savedState)

{

if (ExistSqlServerService())

{

if (IsExistSitePort())

{

MessageBox.Show("站点端口号重复", "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);

return;

}

if (IsExistSiteName(Context.Parameters["sitename"].ToString()))

{

MessageBox.Show("站点名称重复", "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);

return;

}

base.OnBeforeInstall(savedState);

unRAR("Message.rar"); //解压文件

unRAR("MoreUpload.rar");

string webconfigpath = Path.Combine(this.Context.Parameters["installdir"].ToString(), "Web.config");

string webcofnigstring = File.ReadAllText(webconfigpath).Replace("#constring#", GetConnectionString(Context.Parameters["dbname"].ToString()));

webcofnigstring = webcofnigstring.Replace("#siteport#", Context.Parameters["siteport"].ToString());

webcofnigstring = webcofnigstring.Replace("#comConn#", "Provider=SQLOLEDB.1;Persist Security Info=False;User ID=" + Context.Parameters["user"].ToString() + ";Password=" + Context.Parameters["pwd"].ToString() + ";Initial Catalog=" + Context.Parameters["dbname"].ToString() + ";Data Source=" + Context.Parameters["server"].ToString());

File.WriteAllText(webconfigpath, webcofnigstring);

////安装IIS

                //if (string.Empty == GetIISVerstion())

//{

//    IISInstall(this.Context.Parameters["installdir"].ToString() + "IIS6.0_XPSP3", this.Context.Parameters["installdir"].ToString() + "iis.txt");

//}



            }

else

{

MessageBox.Show("检测到您的电脑没有安装SQL SERVER,无法继续安装此产品", "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);

this.Rollback(savedState);

}

}

上面代码中解压了两个文件,主要是在安装完创建站点时还需要创建虚拟目录。之所以要先压缩放到WEB项目里,是因为生成安装程序时会检测项目的生成是否成功(是否可以不让它检测成功呢?
还不清楚),一般只要我们把发布好的项目COPY到新建项目下就可以,但是独立的项目文件夹有自己独立的bin目录和webconfig文件,是不能混合在一起生成成功的,但是又需要一次完全安装,那么可以先压缩做为WEB项目下的文件,待复制完后再解压。

4)安装

 /// <summary>

/// 安装

/// </summary>

/// <param name="stateSaver"></param>

        public override void Install(IDictionary stateSaver)

{

if (ExistSqlServerService())

{

if (IsExistSitePort())

{

MessageBox.Show("站点端口号重复", "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);

return;

}

if (IsExistSiteName(Context.Parameters["sitename"].ToString()))

{

MessageBox.Show("站点名称重复", "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);

return;

}

base.Install(stateSaver);

WriteBat();

RegisterCom();

string connectionString = GetConnectionString(null);

try

{

using (SqlConnection connection = new SqlConnection(connectionString))

{

connection.Open();

string sql = "sp_attach_db '" + Context.Parameters["dbname"].ToString() + "','" + Context.Parameters["installdir"].ToString() + "App_Data/Db_Data.MDF','"

+ Context.Parameters["installdir"].ToString() + "App_Data/Db_Data_Log.LDF'";

ExecuteSQL(connection, sql);

connection.Close();

}

}

catch (Exception ex)

{

MessageBox.Show("数据库安装失败!\n数据库配置有误,请正确配置信息!\n" + ex.Message, "出错!");

this.Rollback(stateSaver);

return;

}

try

{

CreateDeskTopShortcut();

NewWebSiteInfo siteInfo = new NewWebSiteInfo(string.Empty, Context.Parameters["siteport"].ToString(), "", Context.Parameters["sitename"].ToString(), Context.Parameters["installdir"].ToString());

CreateNewWebSite(siteInfo);

StartWebSite(siteInfo.BindString);

}

catch//(Exception ex)

                {

//MessageBox.Show("创建站点失败!\n" + ex.Message, "出错!");

//this.Rollback(stateSaver);

                     CreateVirWebSite("Message", Context.Parameters["installdir"].ToString() + "Message");

CreateVirWebSite("MoreUpload", Context.Parameters["installdir"].ToString() + "MoreUpload");

}

}

else

{

MessageBox.Show("检测到您的电脑没有安装SQL SERVER,无法继续安装此产品", "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);

this.Rollback(stateSaver);

}

}

上面创建网站时会抛出一个文件路径的异常,但是网站是创建成功的,也算一个遗留问题,创建好网站后调用CreateVirWebSite方法创建虚拟目录。

5)安装时用户参数接收

参数的名称在添加安装项目的视图-》用户界面里填写,如下图:

               

参数的传递在视图——》自定义操作里面设置,如下图:

在CustomActionData里输入所有需要传递到安装类的参数  
/dbname=[DBNAME] /server=[SERVER] /user=[UID] /pwd=[PWD]
/sitename=[SITENAME] /siteport=[SITEPORT] /startpage=[STARTPAGE]
/shortcutname=[SHORTCUTNAME]
/installdir="[TARGETDIR]\"  注意这个格式是固定的,尤其安装路径的参数格式installdir="[TARGETDIR]\"这么写

同时要说明的是在卸载的CustomActionData属性只需要给出installdir参数,即使给了其它的参数,卸载时也是读取不到的,只能读取到初始的默认值,如果安装过程中用户重新修改了就不行了,安装文件时选择的路径始终能正确读取到,正因为如此在安装时需要把录入的相关信息以XML配置文件的形式记录下来,这样才能保证正确无误的卸载。

6)卸载

/// <summary
        /// 卸载

/// </summary>

/// <param name="savedState"></param>

        public override void Uninstall(IDictionary savedState)

{

DeleteWebSite(); //删除安装文件前先删除站点,因删除站点时需读取安装文件的配置信息

            dbpath = Path.Combine(this.Context.Parameters["installdir"].ToString(), "dbconfig.xml");

string connectionString = OperateXML.GetXmlNodeValue(dbpath, "ConnString");

string dbName = OperateXML.GetXmlNodeValue(dbpath, "DbName");

base.Uninstall(savedState);

try

{

using (SqlConnection connection = new SqlConnection(connectionString))

{

connection.Open();

string sql = "if exists(select 1 from master..sysdatabases where name= '" + dbName + "') drop database " + dbName;

ExecuteSQL(connection, sql);

connection.Close();

}

if (Directory.Exists(Context.Parameters["installdir"].ToString() + "Message"))

{

Directory.Delete(Context.Parameters["installdir"].ToString() + "Message", true);//删除解压产生的文件

                }

if (Directory.Exists(Context.Parameters["installdir"].ToString() + "MoreUpload"))

{

Directory.Delete(Context.Parameters["installdir"].ToString() + "MoreUpload", true);

}

}

catch (Exception ex)

{

MessageBox.Show("卸载失败!\n" + ex.Message, "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);

this.Rollback(savedState);

return;

}

}

因为解压产生的文件卸载时不会自动删除,需要单独编写代码删除,这些文件是安装过程中产生的次生文件,它只会自动删除原本WEB项目打包进去的原来文件,至于另外产生的文件

是不会自动删除的。对于解压后的文件进行操作,这里也有个一个必须要注意的地方,就是路径问题,解压产生的次生文件,安装时会读取不到解压后的文件夹路径,事实上文件已经复制解压也完成了,但就是读取不到,对应这种情况办法是建立一个和压缩包一样的空文件夹放到WEB项目里,如果解压后的文件里需要替换webconfig连接串,可以在文件夹里放入Web.xml文件,并设置好要替换的地方,前面说了多个webconfig生成会不成功,这里可以先取名xml,解压后替换连接串再修改文件名OK了。

7)安装项目工程结构

新建一个网站或项目,然后添加安装项目和安装程序类库,如下图

  

虽然是WEB项目打包安装,这里选择安装项目就可以了,并不需要选择Web 
安装项目。安装项目属性里的系统必备选择相应的.NET类库,安装时如果没有装framework也会自动引导安装,如下图:

生成安装项目时会产生两个执行文件,一个.msi 一个setup.exe,msi是打包生成是安装程序,exe是一个引导安装程序,如果电脑上没有安装framework,那么点击exe运行引导安装,如果原本已经安装了相应的framework,那么随便点击那个安装效果是一样的。

8)运行效果图

上面原本默认的路径是C:\Program Files\peace\项目信息管理系统\ 
,如果一级目录原本存在的话会有一个问题,解压时会找不到压缩文件,文件确实是存在的,但是磁盘根目录下却又可以,可能是调用WinRAR解压读写的权限问题。

下面两张是桌面的快捷方式和附加的数据库图

      

卸载时也完全卸载了所有相关的文件和内容。

9)代码下载

有些代码没贴出来,直接放到源码里下载去看好了,主要是DBInstaller.cs文件里的代码。

源码下载:点击下载

WEB项目(B/S系统)打包安装(总结篇)的更多相关文章

  1. Hadoop Web项目--Friend Find系统

    项目使用软件:Myeclipse10.0,JDK1.7,Hadoop2.6,MySQL5.6.EasyUI1.3.6.jQuery2.0,Spring4.1.3. Hibernate4.3.1,str ...

  2. Web项目也能一键打包Android、IOS

    随着移动互联网的不断发展,智能手机配置的不断提高,越来越多的年轻人基本都在使用手机,如微信.支付宝等等.已基本成为一种习惯,坐电梯也好.吃饭也好.开车也好,基本都捧着一个手机在那按来按去,开车就不建议 ...

  3. Java Web项目在Mac系统上启动时提示nodename nor servname provided

    今天一不小心更新了Mac系统,然后在启动Java Web项目的时候,提示了java.net.UnknownHostException: MAC-mini-local nodename nor serv ...

  4. 【IDEA】IDEA创建Maven的Web项目并运行以及打包

     0.IDEA集成Maven并设置Maven的配置 idea15之后的版本,都自带了maven插件,idea14貌似需要自己安装,方法也很简单:File->Settings->Plugin ...

  5. Java Web项目在Mac系统上启动时提示nodename nor servname provided的解决办法

    今天在Mac系统上启动Java Web项目的时候,提示了Java.net.UnknownHostException: yangxiaomindeMacBook-Pro.local nodename n ...

  6. Web 项目没有发布到我们安装的tomcat目录下

    新手做Web项目的时候,在Ecplise把app发布到tomcat,但最后项目并没有发布到我们自己安装的 tomcat目录下,而是在.metadata\.plugins\org.eclipse.wst ...

  7. [转]Idea2016 使用Maven配置简单Web项目(受益比较多的一篇)

    最近被同事一直吵着用Idea写Java,于是偷偷的去试用了一下Idea.确实不错,无论界面还是智能提醒都是蛮符合我的使用习惯,但是刚从Eclipse出来,使用Idea还是不太习惯的.所以这里写出来,供 ...

  8. SSM框架开发web项目系列(一) 环境搭建篇

    前言 开发环境:Eclipse Mars + Maven + JDK 1.7 + Tomcat 7 + MySQL 主要框架:Spring + Spring MVC + Mybatis 目的:快速上手 ...

  9. eclipse 开发web 项目,使用gradle 需要安装的插件

    1.Buildship Gradle 扩展 eclipse IDE 以支持使用 Gradle 构建软件.此解决方案由 Eclipse 基金会提供 2.EGradle Editor (主要用来编写gra ...

随机推荐

  1. MYSQL C API 记录

    一.环境与条件 MySQL AB 提供了C API,能够提供低等级界面,负责完毕涉及SQLserver交互的大多数常规任务:数据库连接 .查询.结果集处理和错误处置.C API通过两个组件实现: 头文 ...

  2. Java8 Lambda表达应用 -- 单线程游戏server+异步数据库操作

    前段时间我们游戏server升级到开发环境Java8,这些天,我再次server的线程模型再次设计了一下,耗费Lambda表情. LambdaJava代码.特别是丑陋不堪的匿名内部类,这篇文章主要就是 ...

  3. asp.net学习之 数据绑定控件--表格绑定控件

    原文:asp.net学习之 数据绑定控件--表格绑定控件     数据绑定 Web 服务器控件是指可绑定到数据源控件,以实现在 Web 应用程序中轻松显示和修改数据的控件.数据绑定 Web 服务器控件 ...

  4. Android开源项目总结

    Android开源项目--分类汇总 Android开源项目第一篇--个性化控件(View)篇 包含ListView.ActionBar.Menu.ViewPager.Gallery.GridView. ...

  5. Android数据库高手秘籍(六)——LitePal的改动和删除操作

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/40083685 在上一篇文章中,我们学会了使用LitePal进行存储数据的功能.确实 ...

  6. 跳水Hibernate(一)实例解说

    此语一与高二接触SSH三框架,但是,当能力有限.我们没有继续下行.今天,我们正在采取的优势Java金痴迷,随即再次上调,另一项研究SSH.让我们先从SSH中间Hibernate说起. 或许你会问.为什 ...

  7. React.js再探(三)

    很多时候,组件实例的外观和行为我们通过props进行定制就可以了.因为任何时候,组件实例的表现只跟 传过来的props属性 相关. 我们称这种为 无状态/ stateless 组件 即它自身是 无记忆 ...

  8. lua学习笔记10:lua简单的命令行

    前面反复使用的命令行,好学喜欢命令行: 一 格公式 lua [options][script][args] 两 详细命令 -e 直接命令传递一个lua -l 加载文件 -i 进入交互模式 比例如.端子 ...

  9. Matlab基于学习------------------函数微分学

    <span style="font-size:18px;">% 函数微分学 % 函数微分学难比功能区,中的积分函数的性质整体叙述性说明.在某些时候差描述叙事的斜率功能 ...

  10. 百度地图API显示多个标注点,解决提示信息问题以及给标注增加地图旁的文字连接提示的另一种解决办法

    原文:百度地图API显示多个标注点,解决提示信息问题以及给标注增加地图旁的文字连接提示的另一种解决办法 公司的网站改版要求在一个页面显示百度地图.上面要同时显示很多标注点,标注点当然要有提示信息嘛,提 ...