Multi environment management with MSBuild using template files with metadata

Apr 13, 2014 at 6:53 PM
I'm trying to achieve multi environment deployment management with msbuild using the following method:
1) using configuration template files. For example:
<project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
      <MyConfig Include="app.config">
         <ConfigValue>
            <configuration>
               <appSettings>
                  <add key="SomeKey" value="$(SomeProperty)"/>
               </appSettings>
            </configuration>
         </ConfigValue/>
      </MyConfig>
   <ItemGroup>
</project>
2) Populating all the necessary properties and using FileTask to WriteLines
<PropertyGroup>
   <SomeProperty>abc</SomeProperty>
</PropertyGroup>
<MSBuild.ExtensionPack.FileSystem.File TaskAction="WriteLines" Files="%(MyConfig.Identity)"
Lines="%(MyConfig.ConfigValue)"/> 
This basically works fine, BUT there are some problems:
  • MSBuild namespace appears to become the default namespace in the newly created configuration file.
<configuration xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <appSettings>
      <add key="SomeKey" value="abc"/>
   </appSettings>
</configuration>
This can be avoided by specifying an empty xmlns attribute on the inner xml of ConfigValue metadata, like so:
<project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
      <MyConfig Include="app.config">
         <ConfigValue>
            <configuration xmlns="">
               <appSettings>
                  <add key="SomeKey" value="$(SomeProperty)"/>
               </appSettings>
            </configuration>
         </ConfigValue/>
      </MyConfig>
   <ItemGroup>
</project>
But then also the empty xmlns attribute will appear in the resulting configuration file.
  • The resulting xml config file will be a single line. This can be avoided by using the following xml:space directive:
<project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
      <MyConfig Include="app.config">
         <ConfigValue>
            <configuration xml:space="preserve" xmlns="">
               <appSettings>
                  <add key="SomeKey" value="$(SomeProperty)"/>
               </appSettings>
            </configuration>
         </ConfigValue/>
      </MyConfig>
   <ItemGroup>
</project>
This almost solves the problem but even though the resulting file consists of same number of lines as the template file, the xml identation is messed up. And ofcourse the xml:space="preserve" directive is also present in the resulting file.
  • Finally, suppose our value for $(SomeProperty) has to have a semicolon in it, like so: abc;def.
    Then, because a semicolon is a preserved character in msbuild, there will be no semicolons in the resulting file, and def will start on a new line in the file, for example:
<configuration xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <appSettings>
      <add key="SomeKey" value="abc
def"/>
   </appSettings>
</configuration>
This can be fixed by using the % notation for special characters. For a semicolon its %3B, so our property assignment will be as follows:
<PropertyGroup>
   <SomeProperty>abc%3Bdef</SomeProperty>
</PropertyGroup> 
This will work ok, BUT i hate to have to do it, because I would like to be able to easily copy values from special *.props files where all my properties are assigned for every environment type.


All these minor issues i'm having , it seems, could be solved if:
1) There was a WriteString action in the FileTask. Then a semicolon would not be a problem because the whole string literal would be passed completely to the FileTask.
2) There was an Ident or FormatXml option in one of the XML tasks, so The xml:space="preserve" would not be neccessary.

Hope this made sense to someone, and i'd be happy to hear some thoughts on it.
Thanks, Roman
Coordinator
May 26, 2014 at 4:12 PM
Make sense yes. will look at for vnext

Please log all discussions as issues on GitHub. This project has moved
Coordinator
May 26, 2014 at 4:38 PM
I think you are going to be better of using the Detokenise task.

Keep a version of your tokenised config files. Copy them somewhere. Parse them using detokenise.
Marked as answer by mikeFourie on 5/26/2014 at 9:38 AM