安装期间解压缩和重新压缩XAP文件以修改配置文件时出现问题

时间:2012-06-08 16:12:38

标签: c# silverlight zip installshield dotnetzip

我有一个有趣的困境,我希望,有人可能有答案。我的公司有一个非常复杂的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进行安装。

任何帮助将不胜感激。以下是我们必须遵循的规范:

  1. 使用InstallShield Basic MSI作为安装程序。
  2. 任何InstallShield自定义操作都必须用C#编写。
  3. 安装程序将文件复制到服务器后,必须修改XAP文件。
  4. 管理层希望我远离BSD和GNU"免费软件"喜欢 Info-Zip,7Zip,et.al。

  5. Ken Jinks

    高级网络开发人员

    Sungard Omni Wealth Services

    Birmingham AL

2 个答案:

答案 0 :(得分:0)

选项2

解决1603错误。

我在this page上发现的一条说明:

  

验证入口点函数的正确原型语法   InstallScript自定义操作的声明(如果有的话)   包含在设置中。

     

正确原型的一个例子是:export prototype MyFunction(HWND);

     

注意:必须专门引用HWND   在原型中。通过自定义调用的所有InstallScript函数   操作必须接受HWND参数。此参数是句柄   Microsoft Windows Installer(MSI)数据库。

选项1(不是选项)

在这里戴上我务实的帽子:

如果您只有两种情况,例如混合绑定和“正常”,我建议只在项目中生成两个ZAP文件并只安装一个,或者(我的首选项)安装两者并动态决定在运行时注入主机页面的ZAP文件名(如果可以识别你的MVC网络应用程序中的运行模式。)

这使得安装程序变得简单,并且在连接到同一Web项目的两个Silverlight项目中的每个项目中都没有添加太多工作来获得一些共享主文件。

您可以使用共享的TT包含文件,使用 共享配置模板生成任何配置。

答案 1 :(得分:0)

O.K。我终于使用PowerShell想出来了。事实证明,我无法使任何CopyHere标志参数设置起作用,并且CopyHere不会覆盖zip文件夹对象中的文件,除非Flags参数已经告知它。

最简单的解决方案是将所有CopyHere方法更改为MoveHere方法。通过这种方式,我永远不必尝试覆盖文件,我也不必删除我的工作文件,因为它已被移回Zip文件夹。

感谢您的所有帮助。

Ken Jinks