I am using the solution to this question in order to apply configuration changes to App.config
in a Winforms project. I also have an installer project for the project that creates an installable *.msi file. The problem is, the config file bundled in the installers is the original, un-transformed config file. So we're not getting the production connection strings in the production installer even though the config file for the built winforms project has all the correct transformations applied.
Is there any way to force the installer project to use the output of project build?
First of all: it is impossible to make the Setup Project point to another app.config
file by using the Primary output
option. So my solution is going to be a work around. I hope you find it useful in your situation.
Overview:
The basic idea is:
app.config
from the Setup Project;app.config
, manually;vdproj
file, and change it to match the real output of the transformed app.config.Some drawbacks are:
Lets Work:
1) Go to your Setup Project, and select the Primary Output object, right click and go to Properties. There you will find the Exclude Filter
... add a filter for *.config
, so it will remove the hard-coded app.config.
2) Right click your Setup Project in the Solution Explorer -> Add -> File... select any file that ends with .config
.
3) Download MSBuild Community Tasks Project, I recomend the msi installer.
4) Unload your project (the csproj) and replace the code from the other question with this one:
Code:
<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll" />
<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets" />
<Target Name="AfterCompile" Condition="exists('app.$(Configuration).config')">
<!-- Generate transformed app config in the intermediate directory -->
<TransformXml Source="app.config" Destination="$(IntermediateOutputPath)$(TargetFileName).config" Transform="app.$(Configuration).config" />
<!-- Force build process to use the transformed configuration file from now on. -->
<ItemGroup>
<AppConfigWithTargetPath Remove="app.config" />
<AppConfigWithTargetPath Include="$(IntermediateOutputPath)$(TargetFileName).config">
<TargetPath>$(TargetFileName).config</TargetPath>
</AppConfigWithTargetPath>
</ItemGroup>
<PropertyGroup>
<SetupProjectPath>$(MSBuildProjectDirectory)\$(IntermediateOutputPath)$(TargetFileName).config</SetupProjectPath>
</PropertyGroup>
<!-- Change the following so that this Task can find your vdproj file -->
<FileUpdate Files="$(MSBuildProjectDirectory)\..\Setup1\Setup1.vdproj"
Regex="(.SourcePath. = .8:).*\.config(.)"
ReplacementText="$1$(SetupProjectPath.Replace(`\`,`\\`))$2" />
<FileUpdate Files="$(MSBuildProjectDirectory)\..\Setup1\Setup1.vdproj"
Regex="(.TargetName. = .8:).*\.config(.)"
ReplacementText="$1$(TargetFileName).config$2" />
</Target>
5) The previous code must be changed, so that it can find your vdproj file. I have placed a comment in the code, indicating where you need to make the change.
Now, everytime you build your main project, the MSBuild will change the Setup project, so that it uses the correct app.config file. It may have drawbacks, but this solution can be polished and become better. If you need leave a comment, and I'll try to respond ASAP.
Resources I Used
MSBuild 4.0 is needed because I need to use String's Replace function, to replace single "\" to double "\" in the path. See MSBuild Property Functions for details about using function in MSBuild.
I learned about the FileUpdate Task in this other question. The official project is MSBuild Community Tasks Project.
These two topics were important to my findings:
Trying to include configuration specific app.config files in a setup project