Added new application setting to app.config but MSI won't install it (doesn't overwrite)

We recently added a new application setting (not user setting) to the app.config (URL to a logging server) of our legacy winforms application (.Net 4.6.1).

Old version was 1.0.3, we changed the version of all assemblies to 1.0.4 and in the Setup project (Visual Studio 2017 Installer Project) changed the version to match which gave up the pop-up to change the product code, which we did.

The install runs correctly (other things were changed too by the way, and those changes are correctly in the new version), but our new app.config setting is not. Curiously, if you manually delete the config file and re-run the app, it re-creates the config file which causes the new setting to appear. Any idea what's happening here?

Thanks!


Solution 1:

You might not be using WiX, but I'll just add what I wrote before I noticed that you didn't add WiX as a tag. Got to learn to read.


This might be the most common problem of all for MSI / WiX deployment, along with wiped out config settings during major upgrade. I assume you have set the app.config file permanent during installation to preserve it during major upgrade?

What is likely happening is that you have installed the config file as a file, but it should be installed as a bunch of XML configuration settings that can be merged into the destination file instead.

The MSI file versioning rules attempt to preserve non-versioned files that have been modified after installation. Accordingly a non-versioned file will not be overwritten if the create and modify dates of the file are different on upgrades. Your file will appear untouched without the most recent, desired values. It has been "preserved".

You can update your WiX source to set the required values using the appropriate WiX XML elements. There are two different elements that are relevant:

  • XmlConfig Element
  • XmlFile Element

With regards to the differences between these two elements, I quote Bob Arnson (WiX developer): "You can do everything (and more) that XmlFile supports with XmlConfig but it requires extra authoring that's not necessary with XmlFile. XmlFile is best at modifying XML files that you're installing (e.g., to add an attribute reflecting the installed path of a file); it can't remove the modifications at uninstall time but if your setup installed the file, it will be uninstalled anyway. XmlConfig is best at modifying shared XML files because it supports uninstalling the modifications." (source).


I find this XML stuff quite fiddly, and I may not use the latest and greatest techniques, but here is a quick sample. Test thoroughly - particularly uninstall and upgrade scenarios - limited testing done on my part:

Here is my test XML file (that is actually installed as a file and then updated). Do check the encoding of the file you save - some issues with encoding have been reported - not sure what the current status is:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <ExistingConfig>
    <bindingRedirect oldVersion="0.0.0" newVersion="0.0.0" />
  </ExistingConfig>
</configuration>

Here is the WiX snippet that will update the file (and install the file). Put the above XML test file next to your WXS source file, or specify the correct source path before building your MSI.

<Component Feature='ProductFeature'>

 <!--Installs the base file-->
 <File Source='app.config' />

 <!--Create New Element-->
 <util:XmlFile Id='XmlSettings1' File='[#app.config]' Action='createElement' 
               Name='MyConfig' ElementPath='//configuration' Sequence='1' />

 <!--Set New Value-->
 <util:XmlFile Id='XmlSettings2' File='[#app.config]' Action='setValue' 
              Name='newVersion' Value='6.6.8' ElementPath='//configuration/MyConfig' Sequence='2' />

<!--Set New Value-->
<util:XmlFile Id='XmlSettings3' File='[#app.config]' Action='setValue' 
              Name='Server' Value='Pusevov' ElementPath='//configuration/MyConfig' Sequence='3' />

<!--Update Existing Value, Existing Element-->
<util:XmlFile Id='XmlSettings4' File='[#app.config]'
  Action='setValue' Name='newVersion' Value='7.7.7' ElementPath='//configuration/ExistingConfig/bindingRedirect' Sequence='4' />

</Component>

I hope that makes some kind of sense. Like I said, I find this fiddly and error prone at times, but so are other tools for this kind of updates. Remember to try first with a primitive test case and do test installs to test for runtime errors. Make something small that works and then build on it - which is obviously self-evident, but it is tempting to try it all in one go. "Fire in the hole, seek cover!".

Some links for safekeeping:

  • Firegiant Tutorial on XML
  • Deleting XML element with XmlConfig extension in WIX using XPath
  • WIX util:xmlfile File name is Source attribute
  • WIX v3 and XmlConfig / XmlFile troubleshooting (resurrected from Wayback Machine)
  • Very step-by-step blog on WiX and XML
  • How do I force wix to update a file before manipulating it on an upgrade
  • Getting app settings for config files during WiX based install