Updating web.config In Visual Studio Team Services During Build and Release.

One key task when automating builds and releases is the configuration of any given deployment. In the .NET world this often equates to setting a number of values in the web.config file so that when a build becomes a release and a release is ready for deployment, that release will be pre-configured to run in the targeted environment prior to the actual deployment.

Some of these settings might include...

  • Application Settings
  • Database Connection Strings
  • Rewrite Rules

Octopus Deploy

Those of us who have experience with Octopus Deploy are familiar with a handy built-in feature, that when enabled, allows for easy updates to be made to the web.config file.

This process works something like this...

  • Enable the "Configuration Variables" feature in your Octopus Project.
  • Define Variables to associate with a release.
  • When a release is triggered for deployment, Octopus will search for a defined variable (key/value) in your web.config file that matches a variable you defined in the Octopus web portal and will replace its value accordingly.

There are some limitations to the above workflow, of which are explained on there support pages, but most use-cases are managed for you.

Visual Studio Team Services

Team Foundation Server for you on-premises folks.

At the time this post was published this type of "feature" was not hardened into VSTS. That being said, with a few additional steps and considerations, we can achieve a similar workflow and automate our configuration during our release phase using VSTS.

Tokens

We will need a means to setup "Tokens" inside our web.config file so that during our Release build, we can locate these tokens and replace them with new values.

To achieve this, we can make use of a VSTS extension called Replace Tokens.

  • Log into your VSTS control panel.
  • Head to VSTS Marketplace and locate Replace Token.
  • Select the install button to initiate installation of this extension.

Applying Tokens To web.config

One of the biggest sticking points in this equation is figuring out how to apply these tokens to your development environment in a way that does not break your local workflow.

For example...

<add name="DefaultConnection" connectionString="#{connection-string}#" providerName="System.Data.SqlClient" />

For obvious reasons, this will cause issues in your local environment. So how do we manage this?

There are a few approaches you can take but the approach I currently prefer is to abstract configuration variables into their own files. What this does for us is limit the environment/process specific code that is located in our web.config file and instead off-loads it to a file that can be referenced.

Putting It All Together

Add the following files to your project.

  • ConnectionString.Local.config
  • ConnectionString.Production.config
  • AppSettings\AppSettings.Local.config
  • AppSettings\AppSettings.Production.config

In your web.config file, make the following changes.

<connectionStrings configSource="ConnectionStrings.Local.config" />
<appSettings file="AppSettings\AppSettings.Local.config"></appSettings>

Your ConnectionStrings.Local.config file can look like this...

<connectionStrings>
  <add name="DefaultConnection" connectionString="Server=localhost\SQLEXPRESS;Database=Pioneer;Trusted_Connection=True;" providerName="System.Data.SqlClient" />
</connectionStrings>

Your ConnectionString.Production.config file can look like this...

<connectionStrings>
  <add name="DefaultConnection" connectionString="#{connection-string}#" providerName="System.Data.SqlClient" />
</connectionStrings>

Your AppSettings.Local.config file can look like this...

<appSettings>
  <add key="Test" value="2" />
</appSettings>

Your AppSettings.Production.config file can look like this...

<appSettings>
  <add key="Test" value="#{test}#" />
</appSettings>

We now have our local configuration in our *.Local.config files and our production configuration in our *.Production.config files. During our release phase, all we will have to do is update our web.config file to reference our production configuration instead of local.

As a bonus, we can add our local configuration files to .gitignore and never have to worry about accidently publishing our personal environment variables.

Build - PowerShell

We are going to need to update our web.config file to point to our *Production.config files during our build step. To do this, we will need a way to run PowerShell commands during this phase.

Write-Host "$(build.artifactstagingdirectory)\Web.config"
$webConfig = "$(build.artifactstagingdirectory)\Web.config"
$doc = (Get-Content $webConfig) -as [Xml]
$connectionObj = $doc.configuration.connectionStrings
$connectionObj.configSource = 'ConnectionStrings.Production.config'
$appSettingsObj = $doc.configuration.appSettings
$appSettingsObj.file = 'AppSettings\AppSettings.Production.config'
$doc.Save($webConfig)

Variables

Now that we have a means of putting tokens in our web.config file, we will have to add Variables in VSTS that can be used to replace those tokens.

  • Head to your Release Definition in VSTS.
  • When editing that Release Definition, under the Variables tab, add the Tokens we set up earlier with a value you would like to replace those Tokens with.

Release - Replace Tokens

The last step is to tell VSTS is to actually replace your configuration tokens during the release phase. To do so, add the Replace Tokens extension as a step of your release phase. The default configuration should work for you out of the box.

Success!

Thats it, we have effectively setup a means to update your web.config files during the build and release phase of VSTS.

Any question or suggestions, as always, feel free to leave a comment.