在安装期间解压缩和重新压缩 XAP 文件以修改配置文件时出现问题
Posted
技术标签:
【中文标题】在安装期间解压缩和重新压缩 XAP 文件以修改配置文件时出现问题【英文标题】:Problems Unzipping and Re-zipping an XAP file during installation to Modify a Config File 【发布时间】:2012-06-08 16:12:38 【问题描述】:我有一个有趣的难题,我希望有人能解答。我的公司有一个非常复杂的 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 时遇到了同样的问题。
接下来,我们使用 Shell32 库下降到较低级别的算法。我们知道使用这种方法需要考虑时间因素,因为 Shell32 进程在单独的线程中运行,因此我们在进程中构建了等待状态,如下所示:
//从 .zip 存档中提取配置文件
Shell32.Shell shell = new Shell32.Shell();
字符串提取文件夹路径 = tempZipFileName.Substring(0, tempZipFileName.Length - 4) + "\";
if (Directory.Exists(extractedFolderPath))
Directory.Delete(extractedFolderPath, true);
Directory.CreateDirectory(extractedFolderPath);
//文件夹名会去掉文件扩展名。
Shell32.Folder 输出 = shell.NameSpace(extractedFolderPath);
Shell32.Folder 输入 = shell.NameSpace(tempZipFileName);
foreach(input.Items() 中的FolderItem F)
字符串名称 = F.Name;
//我们只提取配置文件
if (name.Equals(CFG_FILE))
输出.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
#将当前位置建立为当前位置
$CurrentLocation=获取位置
#确定$CurrentLocation的路径
$CurrentPath=$CurrentLocation.path
#使用$CurrentPath创建命名空间
$Location=$shell.namespace($CurrentPath)
#将 XAP 文件重命名为 ZIP 文件以进行提取。
Get-ChildItem *.xap|重命名-Item -NewName
$_.Name -replace "xap","zip"
#使用ZIP文件创建一个ChildItem对象。
$ZipFile = get-childitem SunGard.OmniWA.WebAdmin.zip
#确保 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")
#当前项的名称与我们要提取的文件匹配,
# 所以将它从 ZIP 文件夹复制到当前 $Location。
$Location.Copyhere($CurFile)
#稍等片刻以确保进程保持同步
开始-睡眠-毫秒 1000
#把解压出来的文件改成扩展名,这样我们就可以和原来的区别开来了
# 将其重新插入 ZIP 文件夹。
Get-ChildItem *.ClientConfig|Rename-Item -NewName
$_.Name -replace "ClientConfig","ClientConfig_Test"
#创建一个包含提取文件的对象。
$ClientConfigFile = get-childitem ServiceReferences.ClientConfig_Test
#稍等片刻以确保进程保持同步
开始-睡眠-毫秒 2000
#不用再搜索了
休息
#由于某种原因,这不会将重命名的文件复制回来
# 进入 ZipFolder,即使它应该(见下文)!
$ZipFolder.CopyHere($ClientConfigFile)
#由于某种原因复制整个当前目录
# 工作得很好!算了!
$ZipFolder.CopyHere($Location)
#我希望这会起作用,但它没有????
$ZipFolder.关闭
write-output "重命名为原来的扩展名"
#将 ZIP 文件重命名为 XAP 文件,以便 Silverlight 可以使用它。
Get-ChildItem *.zip|Rename-Item -NewName
$_.Name -replace "zip","xap"
这应该不难做到。以前一定有人做过这样的事情!我的意思是任何复杂的 Web 安装都需要一个自动化的安装过程,并且最终必须使用代理和 DMZ 进行安装。
我们将不胜感激。以下是我们必须遵循的规范:
-
使用 InstallShield Basic MSI 作为安装程序。
任何 InstallShield 自定义操作都必须用 C# 编写。
安装程序将文件复制到服务器后,必须修改 XAP 文件。
管理层希望我远离 BSD 和 GNU “免费软件”,例如
Info-Zip、7Zip 等。
肯·金克斯
高级网页开发人员
Sungard Omni 财富服务
伯明翰铝
【问题讨论】:
您在前两种方法中提到了 1603 错误。详细日志是否有任何指示为什么会出现错误?它应该可以帮助您确定在大多数或所有导致 1603 的情况下出了什么问题。 Ken,仅供参考,给你头脑清醒的老板:DotNetZip 是“免费软件”。它没有获得 BSD 许可证或 GNU 许可证的许可,但它仍然是免费和开源的。 另外 - 我怀疑您无法复制修改后的 ZIP 的原因是有一些文件锁定正在执行。建议:将.ZIP-to-be-modified解压到一个临时目录,然后修改复制到最终目录。小心!在取消或安装失败的情况下,您需要解除它。 国际象棋;这两种我都试过了。 #1 公司律师按自己的节奏工作,看不起我们这些苦工。 #2。已经尝试过没有区别;但是,我已经让这个过程开始工作了。 【参考方案1】:选项 2
解决 1603 错误。
我在this page 上找到的一条注释说:
验证入口函数的正确原型语法 InstallScript 自定义操作的声明,如果有的话 包含在设置中。
一个正确原型的例子是:
export prototype MyFunction(HWND);
注意:必须专门引用 HWND 在原型中。通过自定义调用的所有 InstallScript 函数 动作必须接受 HWND 参数。这个参数是一个句柄 Microsoft Windows Installer (MSI) 数据库。
选项 1(不是选项)
在这里戴上我务实的帽子:
如果您只有两种情况,例如混合绑定和“正常”,我建议简单地在您的项目中生成两个 ZAP 文件并仅安装一个,或者(我的偏好)安装两者并动态决定在运行时将哪个 ZAP 文件名注入到托管页面中(如果您可以识别MVC Web 应用中的运行模式)。
这使安装程序保持简单,并且在连接到同一个 Web 项目的两个 Silverlight 项目中的每个项目中都有一些共享主文件不会增加太多工作。
您可以使用共享的 TT 包含文件来生成使用大部分共享配置模板的任何配置。
【讨论】:
抱歉,我遗漏了第三种情况:直接 HTTPS 协议。另外,我之前已经与我们的 silverlight 团队核实过,生成 3 个不同的 XAP 是不可接受的,因为不仅可以在安装期间修改绑定,而且可以修改其他 URL 本身以允许用户将站点安装到任何物理/虚拟路径中他们希望。 哎呀......允许如此多的安装灵活性使一切变得更加困难。用我找到的关于 1603 的更多线索更新了答案。【参考方案2】:好的。我终于用 PowerShell 弄明白了。事实证明,我无法让任何 CopyHere 标志参数设置起作用,并且 CopyHere 不会覆盖 zip 文件夹对象中的文件,除非标志参数告诉它这样做。
最简单的解决方案是将所有 CopyHere 方法更改为 MoveHere 方法。这样,我就不必尝试覆盖文件,也不必删除我的工作文件,因为它已移回 Zip 文件夹。
感谢您的所有帮助。
肯·金克斯
【讨论】:
以上是关于在安装期间解压缩和重新压缩 XAP 文件以修改配置文件时出现问题的主要内容,如果未能解决你的问题,请参考以下文章