Build once and deploy to multiple environments with msdeploy & Visual Studio 2012

22,105

Solution 1

We use option #1 and it works out well enough. We deploy to about 30-40 sites and applications using this approach.

I think option #2 will cause headaches for either you or the developers. You'll either have to make sure the sections with settings are removed from the config on deployment, or lock them on the server so that the local config can't add them.

For option #3 you will have to do multiple builds to get the transformed config files. It also isn't very feasible if you have a large number of sites to deploy.

Option #4 could work, but you might run into limitations here. It's either the whole section is in a separate file or its all in the main file so there's no in-between.

Option #5 looks interesting, but I haven't used it so I can't say much about it.

Solution 2

I can elaborate a bit on options #1/#3 and compare them. The previous reply was not accurate in stating that you have to build multiple times with PackageWeb, you only need to build once.

Option 1: Parameters.xml and SetParameters.xml

In this approach you will create a parameters.xml file in your web project which will declare additional Web Deploy parameters.

When you build the Web Deploy package the parameters declared in parameters.xml are created in the package. When this web deploy package is created the web.config file will be transformed based on the build config (and now potentially a profile specific transform as well).

You can use that package and a setparameters.xml to publish the package specifying the Web Deploy parameter values. You can create different setparameters.xml files and use that along with the same package to publish to multiple destinations. To publish using this technique you can use either the deploy.cmd which VS generates or call msdeploy.exe with the correct set of parameters.

Option 3: PackageWeb

PackageWeb extends the package process so that when you create a Web Deploy package the web.config transforms are included in the package as well as an assembly which can execute the transforms.

In addition to this when you create a web deploy package a publish-interactive.ps1 file is generated. You can use this file to publish your package. It will prompt you for; the web.config transform to be applied, the web deploy parameter values, and the web deploy endpoint info itself. When you run through a publish the values you gave are saved to publish-configuration.ps1.readme. You can remove the .readme and publish-interactive.ps1 will use the values from that file to automate the publish. You can also specify the file to be used for settings.

If you created a parameters.xml file when the web deploy package is created by VS it will result in web deploy parameters being included in the package. PackageWeb will pick those up and prompt you for those as well.

So what are the differences between these approaches?

With Option #1 the web.config which gets into the package is already transformed. You will not have an opportunity to transform the file again. With both approaches you can specify web deploy parameter values though so that may suit your needs. If you are modifying big chunks of XML from one env to the other then the web.config transforms may be beneficial. So PackageWeb may be a better choice.

With Option #1 you have to manually create the SetParameters.xml file. With PackageWeb you can run through the process using the WhatIf option. You will be prompted for the values and it will create the settings file for you.

You can easily automate both approaches. PackageWeb essentially builds on the parameters.xml/setparameters.xml technique and offers a super-set of the functionality.

If you want to keep things as simple as possible with the least # of moving parts I would recommend option #1, because you can directly call msdeploy.exe if needed.

If you want to simplify automating the publish and you prefer PowerShell to a standard command prompt then try out PackageWeb.

I have a 5 minute video on PackageWeb at http://sedodream.com/2012/03/14/PackageWebUpdatedAndVideoBelow.aspx. If you are publishing web deploy packages I encourage you guys to try it out. If it doesn't meet your needs please let me know because we may use what we learn in PackageWeb later in a more formal way.

Solution 3

We use #5 and it works very well. Using MSBuild for publish profiles provides a bunch of flexibility (Items are particularly useful).

In our deployment pipeline, only the website package, build/beployment targets and publish profiles are made available to deployment stages. Source code, including project files, are only utilised by the build/test stage.

FYI, we went with publish profiles specifically as you'll quickly run into the problem of keeping environment specific server details / credentials, skip clauses and parameter values together. WPP / Publish Profiles track all these things in the pubxml file, and MSBuild's features allow for some nice convention-over-configuration "helpers" for common-but-"noisy" tasks.

Solution 4

I ended up solving this problem with a combination of msbuild running on TeamCity to create NuGet packages which can be consumed by OctopusDeploy.

Octopus allow for an application packaged up into a nuget package (built once) to be pushed through multiple environments. Config can be transformed on a per environment or even a per machine basis using standard ms transforms. Links to relevent Octopus docs below.

Packaging for Octopus

Configuring config transforms

Share:
22,105
What Would Be Cool
Author by

What Would Be Cool

Creative senior software engineer with 20+ years of experience of full-stack development, leadership and collaborative skills helping to build winning, high performance teams to deliver innovative solutions to our customers in a fun environment.

Updated on October 16, 2020

Comments

  • What Would Be Cool
    What Would Be Cool over 3 years

    Working on centralizing configurations, app settings and connection strings, for multiple solutions, while also switching over to use msdeploy from command line to deploy web apps. Ideally I would want to build the packages once, and get up-to-date configurations as the packages are deployed to each environment. I need some advice on the best approach to take.

    1. Use Parameters.xml and SetParameters.xml file to dynamically swap out settings and connection strings. See http://vishaljoshi.blogspot.com/2010/07/web-deploy-parameterization-in-action.html
    2. Use machine.config or server level web.config files to store common app settings and connection strings.
    3. Use packageweb NuGet package from https://github.com/sayedihashimi/package-web which enables using web.config transforms with msdeploy.
    4. Use file or configSource attributes along with SetParameters to point to different config files, but must be relative from web root.
    5. Use publish profiles. See Deploying an existing package using publish profiles

    Thanks

  • Sayed Ibrahim Hashimi
    Sayed Ibrahim Hashimi over 11 years
    FYI for Option #3 (PackageWeb) you do not have to build multiple times. It embeds all the web.config transforms into the generated package. See my answer below.
  • Nelson Rothermel
    Nelson Rothermel about 11 years
    "You can create different setparameters.xml files". How/where do you create them? The default behavior is that you have a parameters.xml file in your project which determines which parameters end up in the one setparameters.xml file that gets created. We can have multiple files included in the project and then add an MSBuild step to copy them over to the package folder so they're available when MSDeploy runs. Is there any other built-in/automatic way to achieve this?
  • Nelson Rothermel
    Nelson Rothermel about 11 years
    It also seems to me that you need separate setparameters.xml files for replacements you could have done before generically with MSBuild variables. In other words, with one build per environment, an MSBuild task using variables like $(Configuration) would have sufficed. My understanding with this method is that now you need to create one setparameters.xml file per environment. Of course the benefit is only one build.
  • Sayed Ibrahim Hashimi
    Sayed Ibrahim Hashimi about 11 years
    There's no built in support for multiple setparameters.xml. You would have to manually manage those. You are correct the transforms would have already been kicked off and executed before that time. setparameteers.xml is passed to msdeploy.exe for the param values.
  • DrCopyPaste
    DrCopyPaste about 11 years
    Hi Sayed, I tried your PackageWeb-Solution myself and it seems to work fine, one thing that annoys me though: How can I avoid typing my password into the PublishConfiguration-file that is being generated by the interactive script? I don't like having to have it there hovering in plain text :)
  • Sayed Ibrahim Hashimi
    Sayed Ibrahim Hashimi about 11 years
    You can pass password as a parameter, see github.com/sayedihashimi/package-web/issues/42. If u want to store it encrypted in the file take a look at the built in support powershell has for encryption/decryption.
  • OK999
    OK999 about 8 years
    i am 4yrs late to this party, but i think #5 is not an answer to "Build ONCE and deploy multiple times". It requires us to execute MSBuild.exe with various publish profiles, to get the code deployed.
  • binarydreams
    binarydreams about 8 years
    @OK9999 true, we ended up moving to a model where msbuild ends at the packaging phase, and it's pure msdeploy during the deploy phase.
  • OK999
    OK999 about 8 years
    Care to share, how do you msdeploy to various environments (dev, test, stage....) using the package that was produced by the msbuild? A gist or something will be very helpful.
  • binarydreams
    binarydreams about 8 years
    We store the deployment scripts, alone with per-environment .publishsettings and .parameters.xml files, in a separate source repository. The scripts take an environment name and a path to a package to deploy, and call msdeploy with any common skip rules etc. We use bamboo to orchestrate our whole build/deploy process
  • Rames Palanisamy
    Rames Palanisamy about 7 years
    a little late to this answer, but i'm considering using option #1 to replace a custom msbuild task that manually munges config file values using an extension to MSBuild Extensions Pack XmlFile tasks. However we need to merge config values in multiple .config files, not just web.config. Does SetParameters support that (my research thus far has been inconclusive).