I am currently attempting to modify my Wix(V3.5) installer to edit the Web.config settings of the .NET application i want to install. This is fine for normal ASP.NET applications but now im attempting to apply my Wix set up project to an Entity Framework .NET application , which as you may know has a more complicated Connection string setting with model .csdl and .ssdl settings.
So if my web.config connection string setting looks somehting like this :(where [DBSERVER] & [DBNAME] are properties retrived from a dialog )
<connectionStrings>
<add name="SSITacticalSolutionEntities" connectionString="metadata=res://*/Model.TacticalSolutionModel.csdl|res://*/Model.TacticalSolutionModel.ssdl|res://*/Model.TacticalSolutionModel.msl;provider=System.Data.SqlClient;provider connection string="Data Source=sd-sql2008r2;Initial Catalog=SsiTacticalSolution1.2.4;Integrated Security=True;MultipleActiveResultSets=True" />
</connectionStrings>
And i edit my Web.config in my Product.Wsx file with somehting like this :
<util:XmlFile Id="ModifyConnectionString" Action="setValue" Permanent="yes" File="[INSTALLLOCATION]Web.config"
ElementPath="/configuration/connectionStrings/add[\[]@name='!(loc.EntityName)'[\]]" Name="connectionString"
Value="Data Source=[DBSERVER];Initial Catalog=[DBNAME];Integrated Security=true;providerName=System.Data.EntityClient;MultipleActiveResultSets=True"" Sequence="5"/>
I get a connection string like this :
<connectionStrings>
<add name="SSITacticalSolutionEntities" connectionString="Data Source=sd-sql2008r2;Initial Catalog=SsiTacticalSolution1.2.4;Integrated Security=true;providerName=System.Data.EntityClient;MultipleActiveResultSets=True""/>
</connectionStrings>
Which of course makes sense , since im asking it to replace the current connection string attribute with what i have defined in the value.
But what i really need here is to edit specific parts of my connection string and leave the remainder (is there some sort of replace action i can use here) ,i.e. leave all my model settings in place and just replace the database server and name etc as i need to. I used to do this with the Visual Studio installers no problem and it was so easy to use.
So my question is can this be done using util.XMLFile , or perhaps util:XmlConfig ? I have tried both without any luck.
Or is this not possible to do with util.XMLFile and will i have to do this in a CustomAction instead ? Any ideas would be of great help , thanks in advance ...
I got this working in the end , in the end i didn't use custom actions for this particular setting , i use variables set up in my localisation file.
I did this because it would be the dev rather then the user who would know the model name and entities name (not a user via the install dialog , they wouldn't know this info), so i have a localisation file with different properties in it like product name etc , so i added in a model name and entites name to this. Everything else i get from the dialogs , entered by user : i.e. database name , virtual directory , impersonation user etc ...
If it helps anyone , here is what i came up with in the end for my web.config;This is the section of my product.wxs which deals with this issue. As you can see i have a connection string property at the top , with a placeholder for the loc.ModelName which is set in my localisation file:
<Property Id="CONNECTION_STRING"
Value="metadata=res://*/Model.!(loc.ModelName).csdl|res://*/Model.!(loc.ModelName).ssdl|res://*/Model.!(loc.ModelName).msl;provider=System.Data.SqlClient;provider connection string=""/>
<!-- The root of the installer. -->
<Directory Id='TARGETDIR' Name='SourceDir'>
<!-- Install into the inetpub/wwwroot directory -->
<Directory Id="IISMain" Name='inetpub'>
<Directory Id="WWWMain" Name='wwwroot' ComponentGuidGenerationSeed='C38ED13E-E1E3-40DB-B1FA-39400C6B2BC4'>
<Directory Id='INSTALLLOCATION' Name="!(loc.ProductName)">
<!-- The component to define the Virtual Directory.-->
<Component Id="WebVirtualDirComponent"
Guid="D814F88F-6E0C-4365-A411-2F9807522C3D">
<!-- WebVirtualDir: The virtual directory we are installing. -->
<!-- Alias: Alias attribute is the name that we will see in IIS.-->
<!-- Directory: The Directory attribute is the "Physical Path" property in
IIS and needs to tie to the ID specified above as the install location. -->
<!-- WebSite: The WebSite attribute ties to a <WebSite> element in the
setup file(see below). As this is an example of installing into the
"Default Web Site" so that element is not under a component.-->
<iis:WebVirtualDir Id="VDir" Alias="[VIRTUALDIRECTORYVALUE]"
Directory="INSTALLLOCATION"
WebSite="DefaultWebSite">
<!-- This turns the Virtual Directory into a web application. -->
<iis:WebApplication Id="MyWebAppApplication"
Name="[VIRTUALDIRECTORYVALUE]" WebAppPool="AppPool"/>
<iis:WebDirProperties Id="WebSite_Properties" AnonymousAccess="no"
WindowsAuthentication="yes" DefaultDocuments="!(loc.DefaultDocument)"
Script="yes" Read="yes" />
</iis:WebVirtualDir>
<CreateFolder/>
<RemoveFolder Id= "GuidFolders" On= "uninstall"/>
</Component>
<!-- Components - this decides what we want to incude in our install
Here we will alter our web.config for Impersonation , debug to false and connection string. -->
<Component Id="Web.config" Guid="2ED81B77-F153-4003-9006-4770D789D4B6">
<!--install our web.config file , this isnt part of our initial MSBUILD-->
<File Id="Web.config" Name="Web.config" Source="$(var.SolutionDir)!(loc.WebApplicationProjectName)\Web.config" DiskId="1" KeyPath="yes" />
<!--Modify our web.config - here we need to add Identity impersonation , changes session settings , add connection string settings and set debug setting-->
<!--Ensure that the identity setting exists-->
<util:XmlFile Id="system.webidentity"
File="[INSTALLLOCATION]Web.config"
Action="createElement"
ElementPath="/configuration/system.web"
Name="identity"
SelectionLanguage="XPath"
Sequence="1" />
<util:XmlFile Id="system.webIdentityAttribute"
Action="setValue"
File="[INSTALLLOCATION]Web.config"
ElementPath="/configuration/system.web/identity"
Name="impersonate"
Value="true"
SelectionLanguage="XPath"
Sequence="2" />
<util:XmlFile Id="system.webIdentityAttribute2"
Action="setValue"
File="[INSTALLLOCATION]Web.config"
ElementPath="/configuration/system.web/identity"
Name="password"
Value="[IMPERSONATIONUSERPASSWORD]"
SelectionLanguage="XPath"
Sequence="3" />
<util:XmlFile Id="system.webIdentityAttribute3"
Action="setValue"
File="[INSTALLLOCATION]Web.config"
ElementPath="/configuration/system.web/identity"
Name="userName"
Value="[IMPERSONATIONUSER]"
SelectionLanguage="XPath"
Sequence="4" />
<util:XmlFile Id="ModifyConnectionString"
Action="setValue"
Permanent="yes"
File="[INSTALLLOCATION]Web.config"
ElementPath="/configuration/connectionStrings/add[\[]@name='!(loc.EntityName)'[\]]"
Name="connectionString"
Value="[CONNECTION_STRING]Data Source=[DBSERVER];Initial Catalog=[DBNAME];Integrated Security=True;MultipleActiveResultSets=True""
SelectionLanguage="XPath"
Sequence="5"/>
<!--<authentication mode="Forms">-->
<util:XmlFile Id="AuthenticationModeWindows"
Action="setValue"
File="[INSTALLLOCATION]Web.config"
ElementPath="/configuration/system.web/authentication"
Name="mode"
Value="Windows"
Sequence="6" />
<!--Switch off debug-->
<util:XmlConfig Sequence="7"
Id="SwitchOffDebug"
File="[INSTALLLOCATION]\web.config"
Action="create" On="install"
Node="value"
ElementPath="/configuration/system.web/compilation"
Name="debug"
Value="false" />
<!--Session configuration <sessionState mode="InProc" timeout="15" />-->
<util:XmlFile Id="system.websessionState"
File="[INSTALLLOCATION]Web.config"
Action="createElement"
ElementPath="/configuration/system.web"
Name="sessionState"
Sequence="8" />
<util:XmlFile Id="system.websessionStateAttribute"
Action="setValue"
File="[INSTALLLOCATION]Web.config"
ElementPath="/configuration/system.web/sessionState"
Name="mode" Value="InProc"
Sequence="9" />
<util:XmlFile Id="system.websessionStateAttribute2"
Action="setValue"
File="[INSTALLLOCATION]Web.config"
ElementPath="/configuration/system.web/sessionState"
Name="timeout"
Value="15"
Sequence="10" />
<util:XmlFile Id="system.websessionStateAttribute3"
Action="setValue"
File="[INSTALLLOCATION]Web.config"
ElementPath="/configuration/system.web/sessionState"
Name="cookieName"
Value="[VIRTUALDIRECTORYVALUE]"
Sequence="11" />
</Component>
<iis:WebSite Id='DefaultWebSite'
Description='Default Web Site'
Directory='INSTALLLOCATION' SiteId ='[WEBSITEVALUE]' >
<iis:WebAddress Id="AllUnassigned" Port="80" />
</iis:WebSite>
<iis:WebAppPool Id="AppPool" Name="[APPPOOLVALUE]" />
<CustomAction Id="MapVirtualDirectory" Directory="INSTALLLOCATION" Return="asyncNoWait"
ExeCommand='[ASPNETREGIIS] -norestart -s "W3SVC/[WEBSITEVALUE]/ROOT/[VIRTUALDIRECTORYVALUE]"' />
<InstallExecuteSequence>
<Custom Action="MapVirtualDirectory" After="InstallFinalize" >ASPNETREGIIS AND NOT Installed</Custom>
</InstallExecuteSequence>
<CustomAction Id="GetIISWebSites" BinaryKey="IisManager" DllEntry="GetWebSites" Execute="immediate" Return="check" />
<CustomAction Id="GetIISAppPools" BinaryKey="IisManager" DllEntry="GetAppPools" Execute="immediate" Return="check" />
<InstallUISequence>
<Custom Action="GetIISWebSites" After="CostFinalize" Overridable="yes">NOT Installed</Custom>
<Custom Action="GetIISAppPools" After="CostFinalize" Overridable="yes">NOT Installed</Custom>
</InstallUISequence>
<Feature Id='ApplicationFeatures' Title="!(loc.ProductName)" Level='1'>
<ComponentRef Id='WebVirtualDirComponent' />
<ComponentGroupRef Id="MyWebApp_Project" />
<ComponentRef Id="Web.config" />
</Feature>
<!-- Specify UI -->
<Property Id="WIXUI_INSTALLDIR">INSTALLLOCATION</Property>
<UIRef Id="MyCustomUI"/>
Here is my localisation file:
<?xml version="1.0" encoding="utf-8"?>
<WixLocalization Culture="en-us" xmlns="http://schemas.microsoft.com/wix/2006/localization">
<!--application settings-->
<String Id="LANG">1033</String>
<String Id="ProductName">MyTestWebSite</String>
<String Id="ProductVersion">1.0.0.0</String>
<String Id="CompanyName">MyCompanyName</String>
<String Id="DefaultDocument">Default.aspx</String>
<String Id="WebApplicationProjectName">MyWebApp</String>
<!--database settings-->
<String Id="EntityName">MyEntities</String>
<String Id="ModelName">MyModel</String>
</WixLocalization>
XmlFile
and XmlConfig
both write attributes at an atomic level. To get the behavior you want, you'd want to write an immediate custom action to read the XML file and store the result in a Property
. Then manipulate that Property
as you see fit (you may need to do that in your custom action if the manipulation is complex), then have XmlFile
or XmlConfig
write the entire manipulated value back out.
This method will require the least complicated set of custom actions in your code by allowing XmlFile
and XmlConfig
to do the heavy lifting and handle rollback and all that stuff. Just make the modifications to the Property
idempotent.
Good luck!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With