我有一个有趣的困境,我希望,有人可能有答案。我的公司有一个非常复杂的Web应用程序,我们通过 InstallShield多实例安装程序包提供给我们的客户。该应用程序使用 ASP.NET MVC3 (使用Web窗体视图引擎), C#4.0 和 Silverlight 编写。这是应用程序的 Silverlight 组件,我们在安装过程中遇到了问题。
我们的许多客户希望在我们称之为“混合绑定模式”的网站上安装我们的网络应用。这可能不是正确的术语。我的意思是客户端将Web应用程序安装在客户端防火墙内部的Web服务器上,并通过DMZ中的代理服务器将其公开给Web。 通过这种方式,防火墙内部的所有内容都将解析为HTTP,而每个外部请求都将解析为HTTPS 。
这对安装期间的大多数Web应用程序都不会造成问题,因为它将在防火墙内部运行,并且当应用程序以“混合绑定模式”安装时,它将始终为HTTP。 Silverlight组件不是这种情况。因为它在最终用户的浏览器进程空间中运行,所以它在代理和防火墙外部,必须通过HTTPS解析。
Silverlight 文件位于 XAP 文件中。在 XAP 文件中,我们有一个配置文件(XML格式),必须根据Web应用程序的绑定模式(HTTP,HTTPS或MIXED)进行修改。众所周知,XAP文件只是Zip文件,因此从理论上讲,编辑XAP中包含的文件所需要的只是将其从“ .xap”重命名为“ .zip”并使用任何文件。 zip兼容的实用程序或库组件,用于提取配置文件,通过某些手动或自动方式对其进行编辑,然后使用相同的zip组件将修改后的文件重新存档回XAP文件。
“这就好了!” 这必须在 InstallShield Basic MSI 过程中自动进行。首先,我们尝试使用 DotNetZip 库使用 InstallShield托管代码自定义操作;但是, DotNetZip 似乎与 InstallShield 不兼容。每次InstallShield启动自定义操作时,安装程序会在自定义操作尝试执行第一个 DotNetZip 命令时抛出 InstallShield 1603错误。 (是的,在尝试解压缩文件之前,我们确实将XAP文件从“ .xap”重命名为“ .zip”。)我们遇到了与 SharpZipLib 相同的问题。 / p>
接下来,我们使用 Shell32 库降低到较低级别的算法。我们知道使用此方法需要考虑时序因素,因为 Shell32 进程在一个单独的线程中运行,因此我们在进程中构建了等待状态,如下所示:
//从.zip存档中提取配置文件
Shell32.Shell shell = new Shell32.Shell();
string extractedFolderPath = tempZipFileName.Substring(0,tempZipFileName.Length - 4)+" \";
if(Directory.Exists(extractedFolderPath))
Directory.Delete(extractedFolderPath,true);
Directory.CreateDirectory(extractedFolderPath);
//文件夹名称将删除文件扩展名。
Shell32.Folder output = shell.NameSpace(extractedFolderPath);
Shell32.Folder input = shell.NameSpace(tempZipFileName);
foreach(inputItems()中的FolderItem F
{
string name = F.Name;
//我们只提取配置文件
if(name.Equals(CFG_FILE))
{
output.MoveHere(F,4); System.Threading.Thread.Sleep(LONG_TIMEOUT);
}
}
//你必须在这里睡一段时间,
//因为shell32在一个单独的线程中运行。
System.Threading.Thread.Sleep(MED_TIMEOUT);
这似乎与当时的“多数”有关。
注意: 使用上面的“多数”一词。该过程在快速服务器上运行不一致,而在较慢的机器上运行一致。不要问我为什么,我的数学教授总是教我一秒钟(至少在这个宇宙中)。
我们甚至尝试使用 PowerShell 脚本。在这种情况下,我们能够提取配置文件并将其重命名为提取它的目标文件夹;但是,我们试图将重命名的文件复制回ZIP存档的所有内容都失败了。这是非常不寻常的,因为我们添加了第二个调用来将目标文件夹及其所有子项推送到Zip存档中并且工作正常(请参阅下面的代码参考)!
#Extract_XAP.ps1
#===============
$ shell = new-object -com shell.application
#Establish当前位置作为当前位置
$ CurrentLocation = GET-位置
#Determine $ CurrentLocation的路径
$ CurrentPath = $ CurrentLocation.path
#使用$ CurrentPath
创建命名空间$位置= $ shell.namespace($ CurrentPath)
#将XAP文件重命名为ZIP文件以进行提取。
Get-ChildItem * .xap | Rename-Item -NewName {
$ _。姓名-replace" xap"," zip"
}
#使用ZIP文件创建一个ChildItem对象。
$ ZipFile = get-childitem SunGard.OmniWA.WebAdmin.zip
#Insure ZIP文件不是只读
(dir $ ZipFile).IsReadOnly = $ false
#为ZIP文件中的ZIP文件夹创建一个shell命名空间。
$ ZipFolder = $ shell.namespace($ ZipFile.fullname)
\迭代ZIP文件夹中的ZIP项目
foreach($ ZipFolder.items()中的$ CurFile)
{
if($ CurFile.name -eq" ServiceReferences.ClientConfig")
{
#Current item的名称与我们要提取的文件相匹配,
#所以将它从ZIP文件夹复制到当前$位置。
$ Location.Copyhere($ CurFile)
#Wait,以确保流程保持同步
Start-sleep -milliseconds 1000
#将扩展名更改为提取的文件,以便我们在
时从原文中告诉它#将其插回ZIP文件夹。
Get-ChildItem * .ClientConfig | Rename-Item -NewName {
$ _。姓名-replace" ClientConfig"," ClientConfig_Test"
}
#Create包含提取文件的对象。
$ ClientConfigFile = get-childitem ServiceReferences.ClientConfig_Test
#Wait,以确保流程保持同步
Start-sleep -milliseconds 2000
#No需要进一步搜索
断裂
}
}
#由于某种原因,这不会复制重命名的文件
#进入ZipFolder,即使它应该(见下文)!
$ ZipFolder.CopyHere($ ClientConfigFile)
#由于某种原因复制整个当前目录
#工作得很好!去图!
$ ZipFolder.CopyHere($位置)
#I希望这会奏效,但它并没有?
$ ZipFolder.Close
写入输出"重命名为原始扩展名"
#Rename ZIP文件回到XAP文件,因此Silverlight可以使用它。
Get-ChildItem * .zip | Rename-Item -NewName {
$ _。姓名-replace" zip"," xap"
}
这不应该这么难。有人必须先做过这样的事情!我的意思是任何复杂的Web安装都需要自动安装过程,并且最终必须使用代理和DMZ进行安装。
任何帮助将不胜感激。以下是我们必须遵循的规范:
Ken Jinks
高级网络开发人员
Sungard Omni Wealth Services
Birmingham AL
答案 0 :(得分:0)
解决1603错误。
我在this page上发现的一条说明:
验证入口点函数的正确原型语法 InstallScript自定义操作的声明(如果有的话) 包含在设置中。
正确原型的一个例子是:
export prototype MyFunction(HWND);
注意:必须专门引用HWND 在原型中。通过自定义调用的所有InstallScript函数 操作必须接受HWND参数。此参数是句柄 Microsoft Windows Installer(MSI)数据库。
在这里戴上我务实的帽子:
如果您只有两种情况,例如混合绑定和“正常”,我建议只在项目中生成两个ZAP文件并只安装一个,或者(我的首选项)安装两者并动态决定在运行时注入主机页面的ZAP文件名(如果可以识别你的MVC网络应用程序中的运行模式。)
这使得安装程序变得简单,并且在连接到同一Web项目的两个Silverlight项目中的每个项目中都没有添加太多工作来获得一些共享主文件。
您可以使用共享的TT包含文件,使用 共享配置模板生成任何配置。
答案 1 :(得分:0)
O.K。我终于使用PowerShell想出来了。事实证明,我无法使任何CopyHere标志参数设置起作用,并且CopyHere不会覆盖zip文件夹对象中的文件,除非Flags参数已经告知它。
最简单的解决方案是将所有CopyHere方法更改为MoveHere方法。通过这种方式,我永远不必尝试覆盖文件,我也不必删除我的工作文件,因为它已被移回Zip文件夹。
感谢您的所有帮助。
Ken Jinks