I've recently been tasked with implementing deployment automation for each component of a relatively large project. Armed with a colleague who had done similar work before, I dove into WiX with a great resource at hand :)

Let me preface this whole thing by saying that, despite the snags I've ran into, WiX is absolutely worth the effort. For as easy as WiX is to implement, it's criminal to *not* implement it in your project. Currently, the entire deployment process we have takes around 10-15% of the team's time. Dev and Test come up with a release plan, review with the program manager and release manager, refine, revise, rinse and repeat. Then, when the time to deploy actually comes, a hole in the document everyone signed off on becomes apparent. WiX helps solve that dilemma.

My goal was to add an entry to the machine.config file's appSettings node. I needed to output: <add key="MSCOM/Environment" value="[MyVariable]" />

I wasn't able to find a lot of great documentation on this, so I'm hoping to save someone else some time :) That said, let's move ahead to the XmlConfig/XmlFile issues I ran into:

  1. XmlConfig, despite my best efforts, didn't seem to actually *do* anything. Taking known-good examples yielded absolutely no edits to my target file. The root cause? At the time of this post, the latest build of WiX available on the Sourceforge download page 3.0.2925; however, the actual latest build is 3.0.3405 (http://wix.sourceforge.net/releases/). In build 2925, XmlConfig seems totally broken, but in build 3405, it functions as expected.
  2. Before realizing that a newer build was available, I resigned and tried to utilize an XmlFile to perform the same task. This proved difficult for a variety of reasons; XmlConfig lets you pass an ID to a new element, where XmlFile makes you do an XPath query each time. This results in a hacky solution where you create a temporary value, do queries based on that temporary value, and then null the value of the newly created node when done. Once this has been done, uninstalling doesn't remove the nodes. For manipulating Xml documents, XmlConfig is the way to go.
  3. Once I updated builds and XmlConfig was "working", the XmlConfig node wasn't actually creating a new element. The second XmlConfig node that added an attribute couldn't find the XmlElement created previously. I had to scope down from all attributes to a specific set of attributes to get something to create.
  4. Once I had my <add> node being written to the file, my attributes wouldn't get written. To successfully write attributes to a newly created node, I had to scope down my XmlConfig node to a few select attributes. Specifically, I believe having "Action" and "Node" values trips up the Util assembly.
  5. Once I had my attributes writing to the correct node, my uninstall process wouldn't remove the node it added. I added an XmlConfig node with On="uninstall" that *seemed* right. However, the parameters you expect to pass to XmlConfig vary by operation; it takes using the same attributes differently to actually do something on an uninstall. Specifically, ElementPath points to the *parent* node of the node you want to delete, and the VerifyPath is an XPath query to the node you want to delete, relative to the ElementPath.
  6. Documentation on XmlConfig is not good enough; the way you utilize parameters vary based on operation. The documentation doesn't make this apparent, leaving you to trial and error and a dozen searches that don't yield a solution.

The actual XML snippet I ended up using to get a successful uninstall/reinstall process was:

                <util:XmlConfig
                    Id="MachineConfigAdd"
                    File="[DOTNETCONFIGPATH]\machine.config"
                    Action="create"
                    ElementPath="//configuration/appSettings"
                    Name="add"
                    Node="element"
                    Sequence="1"
                    On="install" />
               
                <util:XmlConfig
                    Id="MachineConfigKey"
                    File="[DOTNETCONFIGPATH]\machine.config"
                    ElementPath="MachineConfigAdd"
                    Name="key"
                    Value="MSCOM/ConfigEnvironment"
                    Sequence="2" />
               
                <util:XmlConfig
                    Id="MachineConfigValue"
                    File="[DOTNETCONFIGPATH]\machine.config"
                    ElementPath="MachineConfigAdd"
                    Name="value"
                    Value="[ENVIRONMENT]"
                    Sequence="3" />
               
                <util:XmlConfig
                    Id="MachineConfigRemoveNode"
                    File="[DOTNETCONFIGPATH]\machine.config"
                    Action="delete"
                    Node="element"
                    VerifyPath="add[\[]@key='MSCOM/ConfigEnvironment'[\]]"
                    ElementPath="//configuration/appSettings"
                    On="uninstall"
                    Sequence="1" />

I can only hope that this saves someone, somewhere a headache :)