WIX: persist session data between C# CustomActions and subsequently displayed WIX Dialog - installation

I am new to WIX and have been tasked with creating an installer that does
the following:
*Deploys a build of our application without overwriting the App.Config file
for the application
*Loads the key/values in the App.Config file and prompts the user with the
"defaults" (existing values) and allows them to modify them before finishing
*SAVES the values the user provided (or defaults if the user made no
changes) back to the App.Config file for use with the application.
I've got the WIX dilalogs and custom actions laid out successfully where
after InstallFinalize, my "LoadDefaultOptions" CustomAction is executed,
which successfully takes the installation directory and the app config file
name, loads it in an XML reader, and parses the key/value pairs, setting
them into the session variable in this manner:
session[key.toUpper()] = value;
My custom action(s) are defined as:
<CustomAction Id="LoadDefaultOptions" Return="asyncWait" Execute="immediate" BinaryKey="aeserverDbDialogPackage.dll" DllEntry="LoadDefaultOptions"/>
<CustomAction Id="SetConfigOptions" Return="check" Execute="immediate" BinaryKey="aeserverDbDialogPackage.dll" DllEntry="SetConfigOptions"/>
The LoadDefaultOptions executes as such:
<Custom Action="LoadDefaultOptions" After="InstallFinalize" />
I have the custom dialog edit properties set like this:
<Control Id="CCPDbConnString" Type="Edit" X="20" Y="62" Width="150" Height="18" Property="CCPCONNECTIONSTRING" Indirect="no" />
There's a matching Property tag earlier in the WXS file like this:
<Property Id="CCPCONNECTIONSTRING" Secure="yes" ></Property>
...And the LoadDefaultOptions customAction overwrites the session var like
this:
session["CCPCONNECTIONSTRING"] = <value parsed from file>;
According to session logs, this works as expected, the xml parse works, and
the session vars are set.
My problem is when my custom dialog comes around to prompt the user with
those stored defaults AFTER the LoadDefaultOptions CustomAction has run.
The ORIGINAL property values of the session variables seem to have "stuck"
instead of being overwritten by the custom action that loaded the defaults
via the xml file and stored them in the session. (they are blank as their
original properties are defined, or in the case I define them otherwise,
they show those values instead of the session written values)
How do you get Dialogs to "read" overridden session variables by
CustomActions?
Ultimately I want to load those values from the app config, prompt them back
to the user in an optional dialog prompt off the exit screen (which works so
far, aside from not getting updated session vars), and then on command from
that prompt dialog, run another custom action to re-write the App.Config
file with the settings provided from the custom dialog...
I just can't get the session vars to PERSIST!!!
Any ideas? am I completely off base attempting to use the session in this manner? how else could I parse the app.config file, and allow an installation user to change app settings if not by session?

Apparently, part of what I'm trying to do is more or less impossible... You cannot modify the session vars in the InstallExecuteSequence for use in dialogs... this can only be done in the InstallUISequence...
Therefore, I cannot READ AND PROMPT USERS FROM my App.Config on first installs as the file will never have been deployed during the period of time that it would be possible to do.... Seems the only time this would work is during an UPGRADE where the App.Config file exists from a prior install in the same location from which the original install occurred.
I'm going to go at it from this point of view, with NO (or hard-coded) default settings during a fresh installation, with an attempt to parse and use as defaults EXISTING app.config settings during upgrade installations... That should take care of my requirements!

If you schedule your custom action after InstallFinalize it won't run elevated during a managed installation / UAC type story. I also have a question, have you considered moving this configuration data to the application where it's easier to manage it as a first-run pattern?

Related

%USERPROFILE does not work with WiX

I am making a setup of my application with WiX. I want to copy/paste an .ini file in the current user folder on Windows (C:\Users\{username})
I saw on this post that I should use the tag [%USERPROFILE].
I use it this way :
<Directory Id="UserFolder" Name="[%USERPROFILE]">
<Directory/>
As a result, a folder [%USERPROFILE] is created in C:\ containing the .ini file. This is not what I want.
Does anyone have an idea how to make it work ?
[%USERPROFILE] is a valid environment variable reference, but I don't think it can be used in this context, as this context isn't formatted. See the Directory Table for details.
Note that, as mentioned in the comments, %USERPROFILE% is likely the wrong place for any files you may want to install. Consider using another predefined folder, such as AppDataFolder, LocalAppDataFolder, or PersonalFolder.
If you go with PersonalFolder, I believe you can just use that instead:
<Directory Id="PersonalFolder"> ... </Directory>
If there is no satisfactory predefined folder property, you can use either a type 51 or a type 35 custom action (depending on whether you schedule it before or after CostFinalize to set the run time value of your folder to [%USERPROFILE]. Those custom actions will format the value they use. Make sure to use an ALL-CAPS name so that it can be set at run time. For example, if the directory is called USERPROFILEFOLDER:
<SetDirectory Id="USERPROFILEFOLDER" Value="[%USERPROFILE]"/>
<!-- or -->
<SetProperty Id="USERPROFILEFOLDER" Value="[%USERPROFILE]"/>
(And don't forget to schedule the action somewhere.)

Wix and file search in installdir

I try to create installer for postgresql zip with binaries. On first installation I run initdb and it initializes postgresql cluster and create data folder. On removing my app this data directory doesn't remove. On next installation in the same dir initdb fails because directory is not empty.
I want to search file [INSTALLFOLDER]/PostgreSql/postgresql.conf and if it exists than ignore initdb custom action.
I can't use DirectorySearch because it is before INSTALLFOLDER exists. I read that there is a way to call directory search via custom action but I can't find any info about it.
How I can check that postgresql cluster has initialized already and skip init db custom action.
One solution would be to create an immediate execution custom action to check for the existence of the file. If so, set a property and use that property in a condition in your initialization custom action.
In the C# managed custom action example below, it takes the value of "SOMEPROPERTY" and if the corresponding directory exists, sets the property RUNINITDB=1. You could then use RUNINITDB in a condition in your initialization custom action. If the property RUNINITDB exists, then run your custom action.
[CustomAction]
public static ActionResult CheckInitDb(Session session)
{
session.Log("Begin CheckInitDb");
string dir = session["SOMEPROPERTY"]; //or you could figure this out programmatically
if(!Directory.Exists(dir))
{
session["RUNINITDB"] = "1";
session.Log("Setting RUNINITDB bit.");
}
return ActionResult.Success;
}
To create the custom action project above, create a new Visual Studio project and under the Windows Installer XML templates, select C# Custom Action Project.
To reference the custom action in your installer XML source code, assuming the custom action is in a dll named InstallHelper.CA.dll, you may have something similar to the code below. Note the custom action CallToRunInitDB will only run if the property RUNINITDB is set.
<Binary Id="InstallHelper" SourceFile="InstallHelper.CA.dll"/>
<CustomAction Id="CheckInitDb" BinaryKey="InstallHelper" DllEntry="CheckInitDb" Execute="immediate" Return="check"/>
<InstallExecuteSequence>
<Custom Action="CheckInitDb" Before="InstallInitialize">NOT (REMOVE ~= "ALL")</Custom>
<Custom Action="YourCallToRunInitDB" After="InstallInitialize">RUNINITDB</Custom>
</InstallExecuteSequence>
If you are unfamiliar with WiX managed custom actions you may be able to find some other sample code on SO: https://stackoverflow.com/search?q=wix+managed+custom+action

AppSettings external refresh

I have an external config file for my AppSettings, called ApplicationSettings.sgs.
This file is then in turn, reference in the my web.config as an external file source:
<appSettings file="Assets\Settings\application.sgs" />
However, when making changes to application.sgs, and I refresh my page where the new value should be pulling through, I still get the old value.
I've ensured that I'm refreshing the section, using ConfigurationManager.RefreshSection("appSettings"); but this is also brings back the default value. Is there something a miss in this solution?
Thanks,
Eric

Session handling into two different XSLT files

I have two XSLT files and I want to create session in one xslt file, then modify it in another XSLT file.
This is my first file:
<session:createcontext name="user_context"/>
<session:setxml context="user_context" path="/">
<NAME>HELLOWORLD</NAME>
</session:setxml>
and this is my second file:
<session:setxml context="user_context" path="/">
<NAME>HELLOINDIA</NAME>
</session:setxml>
Is this correct?
The code is not able to update the attribute "NAME" in session, and I am getting still "HELLOWORLD".
Environment: This implementation is running on Cocoon 2.2 with a Tomcat application.
In Cocoon, also same problem with the following scenario:
I have created session in XMAP (Cocoon config file), and I am accessing the same session in one pipeline's transform XSLT implementation. Here I have changed the session's an one attribute and I want to access the same attribute of same session in again xmap file.

Change the connection string in app.config with InstallShield 2011 setup

I'm creating an InstallShield 2011 basic MSI installer project.
I'm trying to change the connection string in my app.config according to the user selections from the database login dialog made in the setup. How can I apply these connection string settings to the connection string entry in the app.config of my windows application I'm trying to install?
XML File Change is the right place to start from. Since changing the connection string is a common task my hope was that there is a best practice to do exactly this task.
-- edit --
There are two main difficulties:
How do I reference a file in InstallShield which will be created on build? The App.config gets copied to MyAppName.config. I don't want to hardwire the application name into the setup at this place again.
The connection string in the config file is used by Entity framework, thus contains more information than given by the database selection from InstallShield. I have to patch an attribute within an element of the config file, if I just want to change the Server and InitialCatalog properties of the connection string. It looks like XML File Change only supports replacing of an entire element or attribute.
As far as I remember, the XML File Changes is designed for this purpose. You can place the user's choice as a property value when defining your XPath and element/attribute values. For me, it was one of the areas of InstallShield which worked quite good and as described.

Resources