Connection String in a WIX Custom Action Parameter

2019-07-18 11:17发布

问题:

Using WIX 3.7, I want to pass a connection string into a custom action. However, since the connection string contains ';' the custom action data is not being parsed correctly.

<CustomAction Id="PopulateActionPrep" Property="PopulateAction" Execute="immediate" Value="CONNECTIONSTRING=&quot;[CONNECTIONSTRING]&quot;;PRODUCTVERSION=[ProductVersion]" /> 

I tried using quotes to escape the connection string but that did not work. When I read the CONNECTIONSTRING property from CustomActionData it comes back with "Data Source=SqlServerName.

Is there a way to escape equal semicolons in WIX?

回答1:

The answer is yes, you escape ; using ;;:

/// <summary>
/// Escapes a value string by doubling any data-separator (semicolon) characters.
/// </summary>
/// <param name="value"></param>
/// <returns>Escaped value string</returns>
private static string Escape(string value)
{
    value = value.Replace(String.Empty + CustomActionData.DataSeparator, String.Empty + CustomActionData.DataSeparator + CustomActionData.DataSeparator);
    return value;
}

(https://github.com/wixtoolset/wix3/blob/wix311rtm/src/DTF/Libraries/WindowsInstaller/customactiondata.cs#L391-L400; see also Unescape and Parse right below.)

Potentially even better news, you can access the data as a raw string and be in total control of how it is deserialized:

var rawString = session["CustomActionData"];

This is all that Session.CustomActionData is doing:

/// <summary>
/// Gets custom action data for the session that was supplied by the caller.
/// </summary>
/// <seealso cref="DoAction(string,CustomActionData)"/>
public CustomActionData CustomActionData
{
    get
    {
        if (this.customActionData == null)
        {
            this.customActionData = new CustomActionData(this[CustomActionData.PropertyName]);
        }


        return this.customActionData;
    }
}

https://github.com/wixtoolset/wix3/blob/wix311rtm/src/DTF/Libraries/WindowsInstaller/Session.cs#L859-L874



回答2:

You don't say what language the deferred custom action is written in. Using a set property custom action is only useful for limited circumstances. What you typically do is use a code custom action for the immediate also. For example, if I was using C# DTF custom actions I'd write one custom action that creates a CustomActionData class and populate it with my dictionary. Then I'd serialize it out to the property that gets passed into the deferred custom action.

Once in the deferred custom action I create a new CustomActionData class by deserializing the CustomActionData property and then access the dictionary for my data.

By leveraging the CustomActionData class you avoid having to invent your own way of structuring and escaping the data. For a even more hard core example, see my blog where I use JSON.

Beam Me Up: Using JSON to serialize CustomActionData