TFS2013 Git multi-project automated build web.config transform not working - msbuild

I can't get MS Build to output a transformed Web.Config file. I've setup the build project using NuGet package restore as described in the NuGet docs. Every part of the build works (package restore, CI, web deploy packages) except for the transform. I have tried the base setup and a custom project file as well as lot of other options and I haven't gotten anywhere.
I've done config transform setups before without issue. I have Slow Cheetah installed and can preview my current transform and see that it works. When I run the build locally via MSBuild.exe, the transform actually happens:
TransformWebConfigCore:
Transforming Source File: G:\MyProject\Web.config
Applying Transform File: G:\MyProject\Web.Debug.config
Output File: obj\Debug\TransformWebConfig\transformed\Web.config
Transformation succeeded
(If I look at the -v output I can see the individual transform run)
Then Web Deploy parameterizes my web.config:
Transformed Web.config using G:\MyProject\Web.Debug.config into obj\Debug\TransformWebConfig\transformed\Web.config.
PipelineTransformPhase:
Publish Pipeline Transform Phase
PreAutoParameterizationWebConfigConnectionStrings:
Creating directory "G:\MyProject\obj\Debug\CSAutoParameterize\transformed\Views\".
Copying obj\Debug\TransformWebConfig\transformed\Web.config to obj\Debug\CSAutoParameterize\original\Web.config.
AutoParameterizationWebConfigConnectionStringsCore:
Transforming Source File: G:\MyProject\Views\Web.config
Applying Transform File: <?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<connectionStrings>
<add
connectionString="{% token='$(ReplacableToken_#(parameter)_#(tokennumber))' xpathlocator='name' parameter='$(name)-Web.config Connection String' description='$(name) Connection String used in web.config by the application to access the database.' defaultValue='$(connectionString)' tags='SqlConnectionString' %}"
xdt:Transform="SetTokenizedAttributes(connectionString)" xdt:SupressWarnings="True" />
</connectionStrings>
</configuration>
No element in the source document matches '/configuration/connectionStrings'
Not executing SetTokenizedAttributes (transform line 6, 15)
Output File: obj\Debug\CSAutoParameterize\transformed\Views\Web.config
Transformation succeeded
PostAutoParameterizationWebConfigConnectionStrings:
Auto ConnectionString Transformed obj\Debug\TransformWebConfig\transformed\Web.config into obj\Debug\CSAutoParameterize\transformed\Web.config.
The parameterized file is then moved into the package and the transformed file is deleted.
Copying obj\Debug\CSAutoParameterize\transformed\Web.config to obj\Debug\Package\PackageTmp\Web.config.
Deleting file "obj\Debug\CSAutoParameterize\transformed\Web.config".
So I have a transformed web.config file that doesn't end up in my build output. Why does the transform happen but not get copied to the output directory or the web deploy package?

I had the same issue here. This is caused by the Web Deploy Pattern. It uses the "project name".SetParameters.xml in the Web_Package to replace values on Deploy.
Since you want to use SlowCheetah you need to circumvent this.
You can accomplish this by replacing the connectionstrings setting in your web.config by:
<connectionStrings configSource="connectionStrings.config">
</connectionStrings>
Of course you will need the connectionStrings.config file. You van create this manually and put in the originasl connectionStrings section.
The node should be the only node in the file.
Now you can add SlowCheetah Transform on your connectionStrings.config file.

Related

Is it possible for csproj/msbuild to include files as optional content?

I have an optional config file in my application that is used for instance-specific configuration. The application works without it, and it is only necessary if you want to configure some additional features. It therefore shouldn't get included in the source control as every developer and client deployment doesn't need it and those who do will have different values.
I have a problem figuring out how to configure this for continuous deployment. I can generate the file on the build server without issues. However, since MsDeploy reads the csproj to determine which files to deploy, this file has to be tracked by my csproj to actually be moved to the deploy server. But if I have it tracked by my csproj, then it becomes no longer optional and I can't build the application without it. I'm using Mercurial which doesn't have a commit-one-version-ignore-subsequent feature (git's --assume-unchanged) so options seem pretty limited on that front. I am a very strong believer that it should be possible to clone a repo and run the project immediately, so I really don't like the idea of comitting something that cannot build.
Is there a way in the csproj file to indicate that a file should be included as content if present and ignored otherwise?
If this is the only .config file in the directory, then you can edit .csproj file manually to reference your file via file mask:
<ItemGroup>
<Compile Include="*.config"/>
</ItemGroup>

WebAPI project doesn't seem to post transformed web.config to bin folder?

I've bene doing well with .NET config transforms. I have them in place now on a class library for data usage and a WPF app.
However, when I attempt to set them up with an ASP.NET WebAPI project, something strange seems to happen.
The config file never shows up in my bin directory, and so the web.config always shows as the pre-formed config file.
If I run MSbuild with parameters of "/t:TransformWebConfig /pConfiguration=Test" on the csproj, I see the following:
CollectWebConfigsToTransform: Found The following for Config
tranformation: Areas\HelpPage\Views\Web.config, Web.config,
Views\Web.config, bin\Web.config PreTransformWebConfig: Skip copying
Web.config to obj\Test\TransformWebConfig\original\Web.config, File
obj\Test\TransformWebConfig\original\Web.config is up to date Skip
copying C:\Users\killesj1\Repositories\MRP Trunk\Macro
Projects\VEUploader\src\app\VEUploader.WebAPI\Web.config to
obj\Test\TransformWebConfig\original\bin\Web.config, File
obj\Test\TransformWebConfig\original\bin\Web. config is up to date
TransformWebConfigCore: Skipping target "TransformWebConfigCore"
because all output files are up-to-date with respect to the input
files. TransformWebConfigCore: Skipping target
"TransformWebConfigCore" because all output files are up-to-date with
respect to the input files. PostTransformWebConfig: Transformed
Web.config using Web.Test.config into
obj\Test\TransformWebConfig\transformed\Web.config. Transformed
C:\Users\killesj1\Repositories\MRP Trunk\Macro
Projects\VEUploader\src\app\VEUploader.WebAPI\Web.config using
C:\Users\killesj1\Repositories\MRP Trunk\Macro
Projects\VEUploader\src\app\VEUploader.WebAPI\Web.Test .config into
obj\Test\TransformWebConfig\transformed\bin\Web.config.
It appears that the transformation is tranforming the file, but somehow it's not making its way back into the bin directory, where the old Web.config remains.
Is this normal? How might I get this to behave similarly to other web transforms?
I had a similar problem, deploying Test projects on Appveyor that weren't being transformed, and followed the advice in the link below and now everything works nicely. I had all my projects set up to do xxx.config transforms in the [Target Name="AfterBuild"] and it worked perfectly on my local dev machine, but on pushing the code to Appveyor, the tests would fail because of untransformed files etc. Basically, move everything to the [Target Name="BeforeBuild"] and see if that helps.
MSBuild - how to force "AfterBuild" target when I do deployment?
web.config normally located in the root and is not copied to bin subfolder. To apply transforms you need to have some template web.config and transform it to root web.config.
E.g. see https://stackoverflow.com/a/16239488/52277 and Use Visual Studio web.config transform for debugging

Mixing web.config transforms and Parameters.xml, or something to that effect

I've been using web.config transforms for a while now, for deployment on a few of our projects. What I'm now trying to achieve, is to have Web Deploy's 'Import Package' screen to prompt to check & update several of the variables in , adjusted for each environment.
I know I can use Parameters.xml to introduce these editable variables, but I haven't yet found how to have the defaults updated for different environment targets.
Consider the following neat, but non-overlapping example of wanting to have the user edit the 'specialServer' AppSetting, and have it present a different default when compiled for the NewEnv target:
Sample entry in Parameters.xml:
<parameter name="Special server" description="" tags="" defaultValue="server1-dev.domain">
<parameterEntry kind="XmlFile" scope="\\web.config$" match="/configuration/appSettings/add[#key='specialServer']/#value" />
</parameter>
Sample transform for Web.NewEnv.config, setting a different value for
<appSettings>
<add key="specialServer"
value="other-server.domain2"
xdt:Transform="SetAttributes" xdt:Locator="Match(key)"/>
</appSettings>
Sample of the prompt in Web Deploy:
Any suggestions as to how to update the default value for different build targets?
Thanks.
You would have to generate and new parameters definition file and embed it in your WebDeploy package for each environment.
This would give you different deploy packages per environment and would allow you to specify different default values for those parameters. Obviously doing so undermines the point if parameter transforms and you essentially end up baking in your config, but it's the only way to achieve what you want.
I don't recommend the approach but it may fit your needs.
We use a batch script to call msdeploy. It allows for a parm to specify the Parameters.xml file. Then with multiple Parameters.xml files (one per environment), you can just call msdeploy like:
"C:\Program Files\IIS\Microsoft Web Deploy V3\msdeploy.exe" -source:package='D:\mysite.zip' -dest:auto,computerName="testcomp1",includeAcls="False" -verb:sync -disableLink:AppPoolExtension -disableLink:ContentExtension -disableLink:CertificateExtension -setParamFile:"D:\mysite.test.SetParameters.xml"

MSBuild or StyleCop task to verify key in App.config file?

In several projects’ App.config file, there is a line
<add key="url" value="http://www.example.com/"/>
Upon each build, I want to have a task to verify that the "url" key does not have the text "http://localhost". Is there a way to do this?
I'm assuming you have a team, and some of your team members inadvertently checkin those configs, changing that value to localhost.
If this is the case, why not have transform files for each environment, where your debug configuration can set the key to localhost, and your production/test/stage/qa/whatever configuration can set it to example.com or something else.
You might not have been aware that msbuild can transform your config files. Essentially you have your main config file, and then a config file containing just the things changed, for each environment. Upon doing a build, msbuild will modify the main one with whatever the changes are in the other "transform" files.
App.Config Transformation for projects which are not Web Projects in Visual Studio 2010?
Your transform file would look like:
<?xml version="1.0"?>
<!-- For more information on using web.config transformation visit http://go.microsoft.com/fwlink/?LinkId=125889 -->
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<appSettings>
<add key="url" value="http://www.example.com/" xdt:Locator="Match(key)" xdt:Transform="SetAttributes"/>
</appSettings>
</configuration>
The microsoft link is to http://msdn.microsoft.com/en-us/library/dd465326(VS.100).aspx
They can easily be used on web.configs, as well as app.configs, with a little tweaking to your project file.
An alternative solution would be to integrate unit tests as part of your build, and have the test verify the key in your web.config.
Go to your builds:
Right click on your build and click on edit build definition:
Choose process:
Now we can set fail on build here:

Can MS Deploy do a package and transform, but not deploy?

Using msbuild in .NET 4.0, I can build web project with the "Package" target, and it does a nice job of putting the package in a zip file. But, when I look at the web.config in there, it's not transformed, it has "$(ReplacableToken_Web_SiteConnection-Web.config Connection String_0)"
I can run the "TransformWebConfig" target and it will do the proper transform, but just in its own silo.
I can also run the "Build" target and pass the "DeployOnBuild=True;DeployTarget=MSDeployPublish" properties and it will deploy the package on my server with the proper web.config transform done.
But, if I want to manually deploy the package to the server, how do I do a "Package" with a "TransformWebConfig" so that the zip file has the final web.config in there?
If you want to skip this from happening then you need to set a property in your build. You can do this in two ways
Edit your project file
Create a .wpp.targets file
I would recommend #2. For this case create a new file in the same directory as your project file with the name {ProjectName}.wpp.targets where {ProjectName} is the name of your project. Then inside of this file you should place the following contents.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
ToolsVersion="4.0">
<PropertyGroup>
<AutoParameterizationWebConfigConnectionStrings>false</AutoParameterizationWebConfigConnectionStrings>
</PropertyGroup>
</Project>
In this case you are setting the property AutoParameterizationWebConfigConnectionStrings which tells the Web Publishing Pipeline to not insert those {} placeholders in the web.config for the connection strings.
The way we do this is by modifiying the project build to do the transform prior to packaging it up.
The Target is call TransformXml and is a part of Microsoft.Web.Publishing.Tasks.dll
In your own targets its
<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll" />
But it will be included in a default VS C# build.
So
<TransformXml Source="web.config" Transform="web.release.config" Destination="$(DeployPath)\web.config" />
Does the trick for us.
Set up those paths with the right ItemGroup ("content" most likely) and make sure that target gets fired prior to the call to Package in your .csproj, and the build output will contain a "Web.config" like normal, with the right transformed values.
Alternatively (we've used this for packages that need to be everything to everyone), you can use that trick to do ALL the transforms and include each of them in the final package.
Then you call Msdeploy manually and use its skip and replace directives (forgot the technical term) to only output the right one at deploy-time
Assuming you have a web.usethisone.config in your package, that looks like
-skip:objectname=filepath,absolutepath=web\..*\.config
-replace:objectName=filepath,match=.*web\.usethisone\.config,replace=web.config