Building a Local Tokenizer for Teams Leveraging Release Management

Release Management brings a lot to the table as far as DevOps go. Automating and controlling your releases is hairy business; this tool takes a swing at making it easy. While the original on-prem product is a bit rough around the edges, it’s good enough that we use it for my current customer — a school district serving almost a million students.

One feature of Release Management is Tokenization. This is an alternative to Web.config transforms and allows you to leverage Release Manager’s component paradigm to — in its most common use-case — define web.config values from within your various release templates (corresponding to environments) via the RM UI.

There’s a problem though — this means that you have to create a web.config.tokenfile, as well as a web.config file. The web.config file is used by developers while the web.token.config file is used by RM. When your development team makes changes to web.config, Release Management doesn’t care because it’s only looking for your .token file.

This means that your developers need to make changes to both web.config AND web.config.token. This is less than ideal.

The solution? Remove web.config, and leverage web.config.token to generate a web.config pre-build using a local file that contains the token values. This means that changes to web.configneed only happen once. Changes to the structure of the file or anything that does not change between environments would be made to web.config.token while changes to the token values would be made to the local token values file.

How can we achieve the above? Powershell, baby.

Step 1: Add a web.tokens file. This is an XML file containing the keys/values that you’d like to tokenize:

<Root> 
<Token>
<Key>Title</Key>
<Value>This Blog Rocks</Value>
</Token>
<Token>
<Key>Debug</Key>
<Value>true</Value>
</Token>
</Root>

Step 2: rename your web.config to web.token.config and update your values with tokens. For example:

<appSettings> 
<add key="Title" value="__Title__" />
<add key="webpages:Version" value="3.0.0.0" /> <add key="webpages:Enabled" value="false" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" /> </appSettings>

Step 3: Add this killer powershell script to the root of your project to generate a web.config for your local deployments using tokenization (mimicking what RM does behind the scenes):

try { 
# get xml
[xml]$tokens = (New-Object System.Net.WebClient).DownloadString($tokenConfig)
   # iterate through each line 
$initiated = $FALSE
   write-host Beginning iteration 
   foreach($token in $tokens.Root.Token) { 
$key = $token.Key
$value = $token.Value
      write-host Replacing __${key}__ with $value 

# find and replace corresponding token in web.config
if ($initiated){
(Get-Content $targetConfig) |
Foreach-Object {$_ -replace "__${key}__", "$value"} |
Set-Content $targetConfig
} else {
(Get-Content $tokenizedWebConfig) |
Foreach-Object {$_ -replace "__${key}__", "$value"} |
Set-Content $targetConfig
}
      $initiated = $TRUE; 
}
} catch {
write-host Error hydrating $webconfig with $tokens
}

Step 4: Add a Pre-Build event to your project to tie all this stuff together:

powershell.exe -file "$(ProjectDir)tokenize.ps1" -tokenizedWebConfig "$(ProjectDir)web.config.token" -tokenConfig "$(ProjectDir)Web.tokens" -targetConfig "$(ProjectDir)Web.config"

There you have it — now your developers don’t need to worry about updating two files with the same changes. You just need to update their development process to leverage the new token values file to change their values, and to update the token.config file instead of the web.config if they need to make changes to the actual web.config. Without this bit of risk (cost) reduction, the district would be wasting thousands of dollars any time someone forgot to manually update two files with the same change.

Thanks for reading!

Mick