将 ConnectionString 传递给 WiX 安装程序中的自定义操作转义分号

问题描述

这是我使用 WiX 的第一个项目。
我正在为 Windows 服务创建安装程序,在安装过程中,我需要收集该服务将使用的一些配置数据。这包括数据库的连接字符串。

<Binary Id="CustomActionBinary" SourceFile="$(var.ServiceSetupActions.TargetDir)$(var.ServiceSetupActions.TargetName).CA.dll"/>
  <CustomAction
    Id="ServiceSetupActions"
    BinaryKey="CustomActionBinary"
    DllEntry="SaveCompanySettings"
    Execute="deferred"
    Return="check"
    Impersonate="no" />
  <CustomAction
    Id="SetupCustomProperties"
    Property="ServiceSetupActions"
    Value="DBTYPE=[DBTYPE];CONNECTIONSTRING=[CONNECTIONSTRING];INSTALLFOLDER=[INSTALLFOLDER]"/>

<InstallExecuteSequence>
  <Custom Action="SetupCustomProperties" Before="ServiceSetupActions" />
  <Custom Action="ServiceSetupActions" After="InstallFiles">NOT Installed</Custom>
</InstallExecuteSequence>

问题是 WiX 使用分号作为数据分隔符 (https://github.com/wixtoolset/Dtf/blob/09dc7b4e4494182c0906bf5492f12e09c918444f/src/WixToolset.Dtf.WindowsInstaller/customactiondata.cs#L32),因此在设置期间输入的连接字符串在我的自定义操作中被错误地反序列化。

问题是:如何将包含分号的字符串正确传递给自定义操作(使用 session.CustomActionData),以免其格式错误

另一种选择是完整的 sql 连接对话框,它会询问服务器、数据库用户名和密码,但该服务可以处理 Postgressql 和 MS sql,有时连接字符串可能包含一些修改

解决方法

我看到你标记了这个 C#,所以我假设你使用 DTF 自定义操作。

在 DTF 中,您可以创建另一个自定义操作并立即执行。在该操作中,您可以创建一个 CustomActionData 集合,填充键值对,然后调用 session.DoAction() 并将延迟的自定义操作的名称传递给它以安排和 CustomActionData 集合。序列化魔法会神奇地发生,键值对将在延迟的自定义操作中可用,只需说 session.CustomActionData(key);

,

请检查此示例,看看它是否适合您: https://github.com/glytzhkof/WiXDeferredModeSample

这是示例的另一个版本,这个版本使用 DTF CustomActionData 类来实现更多的“自动魔术”:https://github.com/glytzhkof/WiXDeferredModeSampleDTF - 它会为您安排自定义操作,您只需在延迟模式下访问属性.已完成有限测试。

  1. 在显示 "PUT-GUID-HERE" - in this source line 的地方设置升级 GUID you can create a GUID here

  2. 更改属性 MYPROPERTY 以包含分号 ;。在 this WiX source line 这样做。如果您愿意,您可以使用以下示例文本(当然可以使用其他任何方法):

    <Property Id="MYPROPERTY" Hidden="yes" Secure="yes">Test;Test1;Test2</Property>
    
  3. 编译并进行测试运行。将显示一个消息框,其中应包含您在源文件中指定的完整字符串。


如果您想在发送到延迟模式的字符串中组合多个属性值,您有几个选项。最简单的方法是使用您需要的值设置多个属性,然后将它们组合成一个发送到延迟模式的字符串。您可以通过多种方式设置属性:对话框、命令行、输入框等...:

  • MYCOMPANY = "某家公司"
  • MYDATABASE = "数据库名称"
  • 等等...

然后在立即模式自定义操作中调用 Session.Format 来解析字符串中的值。像这样:

COMPANYID=[COMPANYID];DBTYPE=[DBTYPE];CONNECTIONSTRING=[CONNECTIONSTRING];INSTALLFOLDER=[INSTALLFOLDER]

var CAdata = Session.Format("MYCOMPANY=[MYCOMPANY];MYDB=[MYDB];MYDBTYPE=[MYDBTYPE]");
session["MYPROPERTYSENTTODEFERREDMODE"] = CAdata;

您还需要一个 Type 51 CA 来将该字符串实际发送到延迟模式自定义操作。您可以在上面的示例中看到这是如何完成的。

然后您在延迟模式自定义操作中检索MYPROPERTYSENTTODEFERREDMODE 的字符串值,您应该可以直接使用它吗?


链接