Intro

There are many ways to run a find and replace in a config file to environmentalize it: you can update files in the build before they are compiled into the MSI, and even here there are multiple choices: SlowCheetah being one of them. This only works if you know at runtime the servers you are deploying to, or you only want a direct 1 to 1 connection. So on those occasions that you want to deploy to more than one box, updating at runtime does not work. Fortunately there is a way to update using WiX, and is surprisingly straightforward.

Your WiX project will need a reference to the WixUtilExtension dll. Within the Product.wxs file, within the “Feature” key value pair I added a ComponentRef and gave it the Id of “XmlUpdateConfig”.


<Feature Id="ProductFeature" Title="Red.Phoenix" Level="1">
<ComponentRef Id="XmlUpdateConfig"/>
</Feature>

I added a separate wxs file to the installer project.Below I will discuss the values you have to enter:


<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<Fragment>
<DirectoryRef Id="WebBin">
<Component Id="XmlUpdateConfig"
Guid="{5AEF24F2-022C-4B19-8F44-91663AC2EB62}" >
<CreateFolder />
<util:XmlFile Id="DataServiceCommand"
Action="setValue"
ElementPath="//system.serviceModel/client/endpoint[\[]@name='tcpMarketService'[\]]/@address"
Value="net.tcp://[MARKETDATASVCLOCATION]:[MARKETDATATCPPORT]/Services/data/DataServiceCommand.svc"
File="[INSTALLLOCATION]Website\web.config"
SelectionLanguage="XPath"
Sequence="1" />
<util:XmlFile Id="DataServiceQuery"
Action="setValue"
ElementPath="//system.serviceModel/client/endpoint[\[]@name='tcpWorkingService'[\]]/@address"
Value="net.tcp://[MARKETDATASVCLOCATION]:[MARKETDATATCPPORT]/Services/data/MarketDataQuery.svc"
File="[INSTALLLOCATION]Website\web.config"
SelectionLanguage="XPath"
Sequence="1" />
</Component>
</DirectoryRef>
</Fragment>
</Wix>

The two endpoint addresses I am editing look like this:

<pre><client>
<endpoint address="net.tcp://localhost:809/Services/data/DataServiceCommand.svc" binding="netTcpBinding" bindingConfiguration="MarketTcp" contract="ServiceFacade.Interfaces.Service.MarketService" name="tcpMarketService" behaviorConfiguration="largeMessage" />
<endpoint address="net.tcp://localhost:809/Services/data/MarketDataQuery.svc" binding="netTcpBinding" contract="ServiceFacade.Interfaces.Service.DayService" name="tcpWorkingService" behaviorConfiguration="largeMessage" />
</client>

Summary

Wow, something in WiX that is quick and simple and works well! Facetiousness aside, it's very straightforward to update files on deployment and the more i think about it, the more sense it makes to use this method over any other method as it makes the MSI's environment agnostic.

Sources