I’m using AppVeyor CI for my small open-source projects and bumped into an issue with integration tests which need a different connection string in different environments. I’ll describe how this can be solved in two ways. The 1st is a similar to web.config XML transformation. The 2nd one is a workaround for AppVeyor using and approach which is called “monkey patching”.
App.Config XML transformation
If you have written web projects you already should have noticed two additional files web.debug.config and web.release.config. These files are used to patch and generate web.config with respect to build configuration (Debug or Release). You can read more about transformation on MSDN. This feature can be used to create a config for custom build configuration. The name of the file must correspond to the build configuration name as the follows: web.<BuildConfigurationName>.config (for example, web.TestEnv01.config must correspond to the build configuration TestEnv01).
This feature is disabled in non-web projects. If you try to add such additional files in your test project you won’t get expected functionality. But with a little hucking of a project file you’ll enable it. Just do the follwing:
- Unload *.csproj and open for edit
- Add or modify the following blocks:
<PropertyGroup> <ProjectConfigFileName>App.config</ProjectConfigFileName> </PropertyGroup>
<ItemGroup> <None Include="App.config" /> <None Include="App.Debug.config"> <DependentUpon>App.config</DependentUpon> </None> <None Include="App.Release.config"> <DependentUpon>App.config</DependentUpon> </None> </ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.targets" />
<Target Name="AfterBuild"> <TransformXml Source="@(AppConfigWithTargetPath)" Transform="$(ProjectConfigTransformFileName)" Destination="@(AppConfigWithTargetPath->'$(OutDir)%(TargetPath)')" /> </Target>
Save and load the project. The syntax for transformation you can find on MSDN (see links below). Also I’m not sure whether all versions of Visual Studio support that. At least you should be using .NET Framework not earlier than .Net 4.0
In the case with AppVeyor it’s possible to create AppVeyor build configuration. This configuration automatically will use app.AppVeyor.config. THe following code will patch a connection string.
<?xml version="1.0"?> <configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"> <connectionStrings> <add name="MyDB" connectionString="MyConnectionString" xdt:Transform="SetAttributes" xdt:Locator="Match(name)" /> </connectionStrings> </configuration>
The text in bold tells that the transformation engine should find an item with name MyDB and set it value to the given one.
The workaround uses “monkey patching” or even simpler static variable. The issue with AppVeyor is that the building fails with the message:
error MSB4019: The imported project "C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.targets" was not found.
Perhaps the path is incorrect and I have should used another one. But it’s possible to avoid explicit dependency on the AppVeyor folder structure. AppVeyor build agent defines environment variable APPVEYOR = True for every build.