杉宫竹苑工作室

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 2551|回复: 0

ASP.NET 完整打包卸载更新攻略

[复制链接]
发表于 2017-1-7 19:15:53 | 显示全部楼层 |阅读模式

正式会员享受无限制浏览网站功能和高速网盘下载,赶快加入本站吧!

您需要 登录 才可以下载或查看,没有账号?立即注册

x
前言
前阵子做了一个有关Installshield的OA 打包安装程序,用的版本Installshield 2010-Premier,具体功能的内容如下:
1、OA采用的是ASP.NET (C#)开发
2、动态发布到IIS虚拟目录(采用自定义对话框)
3、附加,分离,删除数据库
4、动态修改web.config
5、完美卸载
6、更新包制作
【安装】首先准备一个发布好的aspnet网站,然后在web.config插入标签,在app_data文件夹放入数据库文件。安装的时候会自动把文件copy到目标机器,在使用dos命令将app_data里面的文件附加到数据库,根据用户填写的数据库信息替换web.config的标签……
【更新】更新包的思路也很简单,在安装的时候会把用户填写的数据库信息存到注册表(数据库服务器,用户名,密码,虚拟目录,安装路径),用了这些信息,那么更新的时候直接把文件copy到用户安装时选择的路径就可以了,如果有数据库相关的更新,则可以使用dos命令执行数据库文件(.sql),如果有web.config的更新,则再一次动态替换web.config的标签即可。
【卸载】网站的卸载就是删除文件,分离和删除数据库,删除注册表相关键值,删除虚拟目录

一、新建项目
1.jpg
选择All Types下面的InstallScript MSI Project,填写产品名称,保存路径,点击OK
2.jpg

点击OK后出来这个界面Project Assistant 项目助手,点击进去可看到有些简单描述项目的选项
Installation Designer安装设计,点击进去可看到产品的信息,安装脚本,安装界面等
3.jpg
切换到Installation  Designer可看到以上界面。
二、填写产品信息
4.jpg
填写产品的基本信息(包括产品名称,安装语言,产品的安装版本,产品编码……)
三、选择文件源
5.jpg
选择文件源,在DefaultComponents下面的files点击右键,选择Dynamic File Linking选择文件源(将文件源填充到components,多个components组成一个features)
6.jpg
点击 New Link弹出Dynamic File Link Settings对话框,点击Browse选择文件夹,然后点击OK,在点击左边对话框的确定,则完成文件源的设置
7.jpg

定位到Setup Design选项,可看到右边窗口有DefaultFeature和DefaultComponents
1个Feature(功能)可以拆分为多个Components(组件),1:N
1个Components可以绑定一个文件夹或者文件,1:N
8.jpg
在Defaultfeature右键选择Associate Components,弹出Component的列表,选择然后点击OK按钮则可以将该components添加到feature下面。
四、设置文件夹权限
9.jpg
功能Feature关联完Component后则可以在Application Data下面的files and folders看到关联过来的文件夹信息,可以对其进行局部调整。也可以对文件夹进行权限控制,权限设置如下:
11.jpg
选中文件夹,右键点击Properties属性,则弹出以下属性窗口
12.jpg
点击Permissions弹出以下界面
13.jpg
在空白处点击右键选择New,则弹出以下界面
14.jpg
设置文件夹的权限,点击OK完成

五、Installshield Script
15.jpg
默认的脚本没有任何东西,只有一句 #include "ifx.h",必须点击右边的安装函数才出来脚本。
InstallScript脚本的语法类似于C,也类似于VBScript,可以调用VB的代码。也可以调用dos命令,也可以调用exe。
16.jpg
选择 Before Move Data 阶段的函数 OnFirstUIBefore,可出来安装过程中对话框的代码,代码如下:
游客,如果您要查看本帖隐藏内容请回复


Dlg_SdWelcome:    欢迎对话框
Dlg_SdRegisterUser   注册用户对话框
Dlg_SetupType       安装类型对话框
Dlg_SdAskDestPath 选择安装目录对话框
Dlg_SdFeatureTree        功能树对话框
Dlg_SQL   sql相关对话框
Dlg_SdStartCopy 复制文件对话框
这几个是系统默认的对话框,所有对话框的生命周期基于Setup.rul脚本,也就是说需要在Setup.Rul里面设置对话框的相关脚本信息和调用对话框的构造函数。
系统默认的对话框脚本都包含在#include "ifx.h"头文件里面,如果是自定义的对话框则【后面会提到】需要引用相关对话框的脚本。
17.jpg

若要引用其他的对话框,则要从dialog source里面调出对话框函数

六、Dialog对话框
18.jpg
对话框选项位于User Interface(用户体验,简称UI)下面的Dialog(对话框)选项

19.jpg
鼠标悬停在对话框名称,右键,选择Edit,可看到对话框的相关信息(布局,控件,属性……Control Identifier是唯一标识列),可以修改对话框的布局和信息。
20.jpg
21.jpg
Skin则是对话框的皮肤,选中皮肤,点击Select应用该皮肤。
七、一个完整的ASP.Net打包程序
1、前言
在了解了Installshield 2010 的一些基本设置和熟悉操作界面后,给大家演示一个完整的ASP.NET打包程序,ASP.NET的安装与部署比较简单,主要是把网站发布到IIS,附加数据库,配置数据库信息(包括数据库用户,密码,服务器),修改web.config配置文件。主要功能有:
●     手动选择安装目录
●     创建和设置IIS虚拟目录
●     动态附加分离数据库
●     自动修改配置文件
●     完美卸载
2、创建IIS虚拟目录
2.1、自定义创建虚拟目录对话框
由于Installshield自身没有操作IIS的功能,那么就要借助外部程序或者windowsAPI,用程序配置 IIS 所用到的“技术”无非是 ADSI 或者 WMI 提供的组件服务程序。可以通过 Windows Host Script 来执行 JScript 或者 VBScript 脚本,也可以在 VB/Delphi 这类快速开发工具开发程序来调用,甚至可以通过浏览器中运行的JavaScript/JScript/VBScript 以及 IIS 运行的 ASP 来调用。因为支持 IDispatch 接口,所以可以后期绑定地通过CreateObject 或者 GetObject 方式来获取 ADSI/WMI 的特定接口。那么我们这里就简单地利用adsi来操作IIS。
由于Installshield自身没有创建虚拟目录的窗口,那么我们就简单的自己做一个自定义的窗口,窗口很简单,就只有一个文本框,用于输入虚拟目录的名称。制作过程如下:
22.jpg
首先先All Dialogs那里右键,弹出菜单,选择New Dialog
23.jpg
新建对话框向导
24.jpg
对话框有多种类型:
Blank Dialog 空对话框,该对话框什么都没有,连上一步,下一步的按钮都没有
NewScriptBasedDialog 普通基于脚本的对话框,带基本按钮
NewSkinnableDialog 带皮肤功能的对话框,带基本按钮
25.jpg
如果弹出冲突页面,直接点击SkipAll就行了。
26.jpg
添加完皮肤对话框后,界面如上,现在就可以对对话框进行编辑,修改对话框标题,按钮的文字,字体大小,摆置方式等。最重要的是甚至对话框的Resource identifier,这是对话框的唯一标识列。
那么现在对话框已经添加完成了,那么如何在安装的过程中显示该对话框呢?
每个对话框都有一个构造函数,那么只有调用该对话框的构造函数就行了,接下来请看怎么编写对话框的构造函数(详情按F1)。
27.jpg
在DefineDialog ( szDialogName, hInstance, szDLLName,nDialogID, szDialogID, nReserved, hwndOwner, lMsgLevel ); 这个函数里,最主要的参数就是第四个nDialogID(对话框ID),也就是对话框Resource identifier属性的值。那么对话框构造函数就可以这样写:
  1.     szDialogName = "SelectVirDialog";
  2.     hInstance  = 0;
  3.     szDLLName  = "";
  4.     nSdDialog  = "13001"
  5.     szDialog   = "";
  6.     hwndParent = 0;
  7.     nResult  = DefineDialog (szDialogName, hInstance, szDLLName, nSdDialog, szDialog,
  8.                              hwndParent, HWND_INSTALL,
  9.                              DLG_MSG_STANDARD|DLG_CENTERED);   
  10.     if ( nResult = DLG_ERR ) then
  11.        bDone = TRUE;
  12.        return -1;
  13.     endif;  
复制代码


这里设置了一个名字为SelectVirDialog的对话框,对话框ID为13001,其他参数可以为空或为0。那么有了构造函数,那么在Setup.rul里面就可以调用构造函数,使用对话框了。
一般为了方便管理,每个对话框都会配置一个对话框的脚本。脚本里面也就是构造函数和点击按钮的业务处理
  1. //选择虚拟目录   
  2. Dlg_SdSelectVirtual:
  3.         szTitle="";
  4.         szMsg="";
  5.         nResult=SdSelectVirtual(szTitle,szMsg);
  6.         if(nResult=BACK) then
  7.             goto Dlg_SdAskDestPath;   
  8.         endif;
  9.         if(nResult=NEXT && !MAINTENANCE) then
  10.             goto Dlg_SQL;
  11.         endif;
复制代码


SdSelectVirtual也就是一个构造函数,里面封装了DefineDialog 函数和业务处理。返回的是按钮ID,BACK和NEW都是枚举值。
对话框其实处于一种死循环状态,只靠goto语句来跳出循环。具体出来的对话框界面如下:
28.jpg
那么如果获取用户输入的值呢?
跟对话框的原理一样,每一个控件也是有一个唯一标识列的(Control Identifier)
设置控件的值CtrlSetText(szDialogName,1204,"A8");
获取控件的值CtrlGetText(szDialogName,1204,svVituralDir);
1204是控件的Control Identifier
szDialogName是对话框的名称,跟DefineDialog第一个参数相对应。
最后一个参数则是设置和获取填充的值或变量。
游客,如果您要查看本帖隐藏内容请回复

2.2、创建虚拟目录(使用ADSI)
设置好界面,获取到用户输入的虚拟目录名称,接下来就是创建虚拟目录了。
第一步:获取IIS的Default站点
set objW3SVC = CoGetObject("IIS://localhost/W3SVC/1/Root","");
第二步:创建虚拟目录
set objVirDir=objW3SVC.Create("IISWebVirtualDir",virtrualDir);//virtrualDir是变量
第三步:设置虚拟目录的属性
objVirDir.Path = TARGETDIR;   
objVirDir.AccessRead = TRUE;   
objVirDir.AccessScript = TRUE;   
objVirDir.AppCreate(TRUE);   
objVirDir.SetInfo();
详细代码请参考SdSelectVirtual.rul的CreateWebSite函数
3、填写数据库信息
3.1、自定义数据库对话框
数据库的对话框也需要自定义,在上面已经介绍过自定义对话框的制作方法,数据库对话框界面如下:

29.jpg
填写服务器信息,默认是localhost或者.都可以
填写用户名,默认一般是sa
填写密码,默认是******
3.2、验证数据库信息
游客,如果您要查看本帖隐藏内容请回复

DB_CheckConnection 这个函数用于验证当前用户输入的数据库信息是否正确,有关数据库的相关操作位于database.rul文件。
如果数据库的信息填写无误,那么把数据库信息写到注册表,方便以后升级使用。
[url=]4[/url]、附加数据库
30.jpg
在执行复制文件到目标机器后,点击Finish(完成)按钮会触发函数onend
  1. //---------------------------------------------------------------------------
  2. // OnEnd
  3. //
  4. // The OnEnd event is called at the end of the setup. This event is not
  5. // called if the setup is aborted.
  6. //---------------------------------------------------------------------------
  7. function OnEnd()
  8. begin
  9. if(!MAINTENANCE)then
  10. //ConfigurateSql();
  11. CreateDataBase(Server,User,Pwd);//Server,User,Pwd为SdCreateSql.rul的全局变量  
  12. endif;
  13. end;
复制代码

Server,User,Pwd都是全局变量,把变量定义到最顶部跟#include同级
  1. #include "Ifx.h"  
  2. #include "database.rul"

  3. #define REX_DIALOG_ID 13003
  4. #define REX_CTRL_ID_SERVER 1209 //服务器
  5. #define REX_CTRL_ID_USER 1207 //用户名
  6. #define REX_CTRL_ID_PWD 1208 //密码

  7. export prototype SdCreateSql(string, string); //构造函数
  8. //prototype CreateDataBase(STRING,STRING,string);//创建数据库
  9. prototype AlterConfigure(string);//修改web.config
  10. string Server,User,Pwd; //全局变量
复制代码


附加数据库是调用了dos命令的osql.exe,代码如下:
  1. //创建数据库
  2. function CreateDataBase(svSQLsvr,svSQLusr,svSQLpwd)
  3.     STRING szCmdLine,szWaitTxt,szCommandLine;
  4.     begin
  5.     //A8数据库
  6.     szWaitTxt=" 正在创建A8数据库.";
  7.     SdShowMsg (szWaitTxt, TRUE);
  8.     Delay(2);
  9.     szCmdLine = "/U "+svSQLusr+" /P "+svSQLpwd+" /S "+svSQLsvr+" /Q "EXEC  sp_attach_db  @dbname  =  N'A8',@filename1  = N'"+TARGETDIR ^"App_Data\A8.mdf',@filename2  = N'"+TARGETDIR ^"App_Data\A8_log.ldf'"";
  10.     if (LaunchAppAndWait("osql.exe", szCmdLine,LAAW_OPTION_NOWAIT | LAAW_OPTION_HIDDEN) < 0) then
  11.         MessageBox ("数据库创建失败!请确您的系统中已安装 Microsoft SQL Server 2000. 如仍无法解决,请联系系统供应商!",SEVERE);
  12.     endif;  
  13.     SdShowMsg (szWaitTxt,FALSE);  
  14.     szWaitTxt=" 正在优化系统数据库.";
  15.     SdShowMsg (szWaitTxt, TRUE);
  16.     Delay(2);
  17.     szCmdLine = "/U "+svSQLusr+" /P "+svSQLpwd+" /S "+svSQLsvr+" /Q "use A8 ; exec sp_updatestats"";
  18.     if (LaunchAppAndWait("osql.exe", szCmdLine,LAAW_OPTION_NOWAIT | LAAW_OPTION_HIDDEN) < 0) then
  19.     MessageBox ("数据库优化失败!您可以在 sql查询分析器中执行 use dlbj ; exec sp_updatestats 完成!",SEVERE);
  20.     endif;
  21.     SdShowMsg (szWaitTxt,FALSE);  
  22.     //打开浏览器浏览制定的网页   
  23.     szCommandLine = ProgramFilesFolder ^ "Internet Explorer\iexplore.exe";
  24.     LaunchAppAndWait(szCommandLine, "http://localhost/"+svVituralDir+"/login/login.aspx", NOWAIT);   

  25.     //修改配置文件
  26.     ConfigurateSql();
  27.    
  28. end;
复制代码


在这里使用了LaunchAppAndWait调用exe文件,详情请按F1
34.jpg
[url=]5、修改Web.Config文件[/url]
修改Web.Config文件也是在文件拷贝到目标机器的完成阶段实现。
第一步:定标签
在Web.Config文件里为每一个要替换的节点定下一个注释标签

则是一个注释标签
第二步:定位行数
根据标签就可以找到该标签下面那一个节点,代码看GetLineNum函数
  1. //从上往下搜索某文件下面的字符串,并返回该字符串所在的行数
  2. function NUMBER GetLineNum(szFileName,szSearchStr,isContinue)
  3. string svReturnLine;
  4. NUMBER nvLineNumber,nvResult;
  5. begin
  6.     nvResult = FileGrep (szFileName, szSearchStr, svReturnLine, nvLineNumber,isContinue);
  7.     switch(nvResult)
  8.             case FILE_NOT_FOUND:
  9.             // Report error; then abort.
  10.             MessageBox( szFileName + " not found.", WARNING);
  11.             abort;
  12.         case FILE_LINE_LENGTH:
  13.             // Report error; then abort.
  14.             MessageBox (szFileName + "lines too long.", WARNING);
  15.             abort;
  16.         case OTHER_FAILURE:
  17.             // Report error; then abort.
  18.             MessageBox (szFileName + "Unknown failure on call to FileGrep.", WARNING);
  19.             abort;
  20.     endswitch;
  21.     return (nvLineNumber+1);
  22. end ;
复制代码


第三步:替换该行数据
使用FileInsertLine函数可以替换文件中的某一行。
  1. //替换webconfig里面链接字符串,使用GetLineNum注意最后一个参数,从头开始找还是继续上次往下找
  2.             nvLineNum=GetLineNum(ConFullDir,sConTag1,CONTINUE);
  3.             if(FileInsertLine(ConFullDir,ConString1,nvLineNum,REPLACE)<0) then
  4.             MessageBox ("FileInsertLine failed.", SEVERE);
  5.             endif;
复制代码


[url=]6[/url]、完美卸载
安装过程已经完成,接下来看如何完美卸载程序(删除文件,分离数据库,删除虚拟目录)
35.jpg
选择Installscript,找到你要卸载的Feature,默认是DefaultFeature,选择卸载事件,UnInstalling(卸载前)和UnInstalled(卸载后)
第一步:分离数据库
因为卸载界面已经脱离了安装的生命周期,那么所有变量都被回收了,要获取数据库信息只能从注册表获取(安装的时候已写进了注册表)

GetReg是一个自定义函数,参数则是注册表的键名
分离数据库还是使用dos命令下的osql.exe
删除数据库文件只能先分离,不然会有数据库质疑的字样
第二步:删除虚拟目录
  1. //删除虚拟目录
  2.      set objW3SVC = CoGetObject("IIS://localhost/W3SVC/1/Root", "");//获取Default站点   
  3.      if(IsObject(objW3SVC)) then
  4.         if(IsObject( CoGetObject("IIS://localhost/W3SVC/1/Root/"+RgVirDir+"",""))) then
  5.                 szWaitTxt="正在删除"+RgVirDir+"虚拟目录";   
  6.                 Delay(2);
  7.                 SdShowMsg (szWaitTxt, TRUE);      
  8.                 objW3SVC.Delete("IIsWebVirtualDir",RgVirDir) ;
  9.                 SdShowMsg (szWaitTxt, FALSE);      
  10.         endif;
  11.      endif;
复制代码


删除虚拟目录一样使用了ADSI
第三步:停止数据库服务和删除注册表键值
  1.     //停止数据库服务SQLSERVERAGENT,MSSQLSERVER
  2.     szCmdLine = " stop SQLSERVERAGENT";   
  3.     if(LaunchAppAndWait("sc", szCmdLine,LAAW_OPTION_NOWAIT | LAAW_OPTION_HIDDEN)<0) then
  4.        MessageBox ("无法停止数据库服务--SQLSERVERAGENT,请手动关闭该服务",SEVERE);
  5.     endif;
  6.    
  7.     szCmdLine=" stop MSSQLSERVER";
  8.     if(LaunchAppAndWait("sc", szCmdLine,LAAW_OPTION_NOWAIT | LAAW_OPTION_HIDDEN) <0) then
  9.         MessageBox ("无法停止数据库服务--MSSQLSERVER,请手动关闭该服务",SEVERE);
  10.     endif;  
  11.      
  12.      //删除完删除注册表
  13.      DelReg(KEY);
复制代码


DelReg是自定义函数,参数是注册表的键
第四步:删除文件夹和启动数据库服务(在UnInstalled卸载后触发)
  1. //---------------------------------------------------------------------------
  2. // The UnInstalled event is sent after the feature DefaultFeature
  3. // is uninstalled.
  4. // sented after delete defaultFeature
  5. //---------------------------------------------------------------------------

  6. export prototype DefaultFeature_UnInstalled();
  7. function DefaultFeature_UnInstalled()
  8. string szCmdLine;
  9. begin
  10.     //删除后重新启动数据库服务--MSSQLSERVER
  11.     szCmdLine=" start MSSQLSERVER";
  12.     if(LaunchAppAndWait("sc", szCmdLine,LAAW_OPTION_NOWAIT | LAAW_OPTION_HIDDEN) <0) then
  13.         MessageBox ("无法启动数据库服务--MSSQLSERVER,请手动启动该服务",SEVERE);
  14.     endif;            
  15.    
  16.     //可能删除不干净,手动执行删除文件夹
  17.     if(ExistsDir(TARGETDIR)=EXISTS ) then   
  18.         if(DeleteDir(TARGETDIR,ALLCONTENTS) < 0) then
  19.             MessageBox("删除失败",SEVERE)  ;
  20.         endif;
  21.     endif;
  22. end;
复制代码

启动数据库服务,删除文件夹。
整个卸载过程完成。
八、更新包制作
1、前言
更新包也是一个独立的InstallScript MSI Project,只不过相比于安装包少了一些步骤,更新包的原理就是从注册表读出安装时写进的信息,如:数据库服务器,用户名,密码,虚拟目录,安装路径。界面略……
直接跳过选择安装目录那个对话框,因为获取了注册表的那个安装路径了。代码如下:
  1. Dlg_SdStartCopy:
  2.     szTitle = "";
  3.     szMsg   = "";
  4.     nResult = SdStartCopy2( szTitle, szMsg );            
  5.     if (nResult = BACK) then
  6.        goto Dlg_SQL;;
  7.     endif;  
  8.    
  9.     //获取注册表的目标路径
  10.     TARGETDIR= GetReg("TargetDir");
  11.    
  12.     // Added in IS 2009 - Set appropriate StatusEx static text.
  13.     SetStatusExStaticText( SdLoadString( IDS_IFX_STATUSEX_STATICTEXT_FIRSTUI ) );

  14.     // setup default status
  15.     Enable(STATUSEX);

  16.     return 0;
  17. end;
复制代码


2、选择更新文件
方法跟安装的时候是一样的
[url=]3、[/url]修改Product Code,每次更新都要换一个Code,要不会出现(修复,卸载,重装的操作界面)
36.jpg
4、运行sql语句
假如有更新sql语句,将需要运行的sql语句整理成一个文件
  1. //---------------------------------------------------------------------------
  2. // OnEnd
  3. //
  4. // The OnEnd event is called at the end of the setup. This event is not
  5. // called if the setup is aborted.
  6. //---------------------------------------------------------------------------
  7. function OnEnd()  
  8.     STRING szKey, szClass, szMsg, szTitle,szCmdLine,sqlRoot;
  9.     string targetDir,server,user,pwd;
  10.     NUMBER nRootKey;
  11. begin   
  12. if(!MAINTENANCE)then
  13.     targetDir=  GetReg("TargetDir");
  14.     server= GetReg("Server");
  15.     user= GetReg("User");
  16.     pwd= GetReg("Pwd");
  17.     sqlRoot= targetDir+"sqlFile.sql" ;
  18.     LongPathToQuote(sqlRoot ,TRUE);                                   
  19.     if(Is(FILE_EXISTS,sqlRoot)) then
  20.         szCmdLine = "/U "+user+" /P "+pwd+" /S "+server+" /i "+sqlRoot+"";
  21.         if (LaunchAppAndWait("osql.exe", szCmdLine,LAAW_OPTION_NOWAIT | LAAW_OPTION_HIDDEN) < 0) then
  22.             MessageBox ("运行sql更新文件时失败,请联系供销商!",SEVERE);
  23.         endif;   
  24.     else
  25.          MessageBox ("找不到更新的sql文件,请联系供销商!",SEVERE);  
  26.     endif;
  27. endif;   
  28. end;
复制代码

执行更新的sql语句也是调用dos的osql.exe文件
5、屏蔽控制面板里添加删除程序的那个安装信息
37.jpg

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|手机版|Archiver|SgzyStudio

GMT+8, 2024-5-19 19:04 , Processed in 0.122319 second(s), 21 queries .

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表