Click here to Skip to main content
15,887,683 members
Articles / Security

App.Config Transforms Outside Of Web Project

Rate me:
Please Sign up or sign in to vote.
4.81/5 (6 votes)
7 Jul 2015CPOL2 min read 16.6K   7  
App.Config Transforms outside of Web Project

Introduction

This is a weird post in some ways as it is new for me, but certainly VERY old for others. I imagine for years web developers have known about how to use the Web.Config XSLT transforms MSBUILD task. If you have not heard of this, quite simply it allows you to have a single Web.Config file and a number of other config files where ONLY the transformations are declared. Such that when the XSLT transforms MSBUILD task runs, it will take the source Web.config file along with a transformation .config file and produce a new .config file which you would use as part of your deployment process.

I have myself known about this for years too, I have even known about the Microsoft MSBUILD teams Slow Cheetah project which allows you to use this same technique outside of web projects. Ting is what I have always done is had a bunch of .config files (so one for XXX.LIVE.config one for XXXX.QA.config) that I would rename and deploy by some clever scripts.

I recently had to do a bit of work on a project that made use of the Web.Config XSLT transforms MSBUILD task, and I could clearly see in the MSBUILD file that this just used a MSBUILD task. So I thought this must be easy enough to use stand alone. Turns out it is, you DO NOT really need to use Slow Cheetah at all. You just need to know where the Web.Config XSLT transforms MSBUILD task is and how to use it.

The rest of this post will talk you through how to do this.

Suppose You Have This App.Config You Wish to Transform

We will concentrate on just a few areas here, those areas are the ones that are going to change between environments:

XML
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
   <configSections>
      <section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog" />
      <section name="shareSettings" type="SimpleConfig.Section, SimpleConfig" />
   </configSections>
   <shareSettings productName="Shipping" ftpPath="D:\ShippingRoutes" />
   <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <extensions>
         <add assembly="Gelf4NLog.Target" />
      </extensions>
      <targets async="true">
         <target name="graylog" xsi:type="graylog" 
         hostip="dev-logging" hostport="12200" 
                  Facility="CoolService">
            <parameter name="exception" 
            layout="${exception:format=tostring}" optional="true" />
            <parameter name="processname" layout="${processname}" />
            <parameter name="logger" layout="${logger}" />
            <parameter name="treadid" layout="${threadid}" />
         </target>
         <target name="file" xsi:type="File" 
                 layout="${longdate} | ${level} | 
		${message}${onexception:${newline}EXCEPTION\:${exception:format=tostring,StackTrace}}" 
                 fileName="c:/temp/CoolService-${shortdate}.log" />
      </targets>
      <rules>
         <logger name="NHibernate.*" minlevel="Off" 
         writeTo="graylog" final="true" />
         <logger name="NHibernate.*" minlevel="Error" 
         writeTo="file" final="true" />
         <logger name="*" minlevel="Off" writeTo="graylog" />
         <logger name="*" minlevel="trace" writeTo="file" />
      </rules>
   </nlog>
   <startup>
      <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
   </startup>
   <system.serviceModel>
      <diagnostics performanceCounters="All" />
      <bindings>
         <netTcpBinding>
            <binding name="tcpBinding" 
            maxReceivedMessageSize="2147483647" closeTimeout="00:59:00" 
                     openTimeout="00:59:00" 
                     receiveTimeout="00:59:00" sendTimeout="00:59:00">
               <security mode="None" />
               <readerQuotas maxStringContentLength="8192" 
               maxArrayLength="20971520" />
            </binding>
         </netTcpBinding>
      </bindings>
      <client>
         <!-- CoolService -->
         <endpoint name="coolServiceEndpoint" 
         address="net.tcp://localhost:63006/CoolService" 
                    binding="netTcpBinding" bindingConfiguration="tcpBinding" 
                    contract="Services.ICoolService" />
      </client>
   </system.serviceModel>
   <system.diagnostics>
      <sources>
         <source name="System.ServiceModel" 
         switchValue="All" propagateActivity="true">
            <listeners>
               <add name="traceListener" 
               type="System.Diagnostics.XmlWriterTraceListener" 
                    initializeData="c:\temp\CoolService.svclog" />
            </listeners>
         </source>
      </sources>
   </system.diagnostics>
</configuration>
  • Custom config section (NOTE: I am using SimpleConfig to do that, which is awesome)
  • NLog logging settings
  • WCF client section
  • Diagnostics WCF section

So Now, Show Me The Transformations

Now this post will not (as is not meant to) teach you all about the Web.Config XSLT transforms MSBUILD task, but rather shall show you an example. So on with the example, suppose we want to create a LIVE config file where we change the following:

  • Custom config section (NOTE: I am using SimpleConfig to do that, which is awesome) (CHANGE ATTRIBUTES)
  • NLog logging settings (CHANGE Logger/Target)
  • WCF client section (CHANGE ADDRESS)
  • Diagnostics WCF section (REMOVE IT)

Here is how we could do that (say it's called “CoolService.LIVE.config”) :

XML
<?xml version="1.0" encoding="UTF-8"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
   <shareSettings xdt:Transform="SetAttributes" xdt:Locator="Match(productName)" 
                   productName="Shipping" ftpPath="\\shipping\ShippingRoutes" />
   <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <targets>
         <target xdt:Transform="SetAttributes" 
         xdt:Locator="Match(name)" name="graylog" 
                 hostip="app-logging" />
         <target xdt:Transform="SetAttributes" 
         xdt:Locator="Match(name)" name="file" 
                  fileName="D:/logs/CoolService-${shortdate}.log" />
      </targets>
      <rules>
         <logger xdt:Transform="SetAttributes" 
         xdt:Locator="Match(writeTo)" minlevel="trace" 
                 writeTo="graylog" />
      </rules>
   </nlog>
   <system.serviceModel>
      <client>
         <endpoint xdt:Transform="SetAttributes" 
         xdt:Locator="Match(name)" name="coolServiceEndpoint" 
                   address="net.tcp://appCoolService:63006/CoolService" />
      </client>
   </system.serviceModel>
   <system.diagnostics xdt:Transform="Remove" />
</configuration> 

So How Do We Apply These Transforms

To actually apply these transforms, we can easily craft a simple MSBUILD project file, such as (say it's called “Transforms.proj”):

XML
<?xml version="1.0" encoding="UTF-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0" 
         DefaultTargets="Release">
   <UsingTask TaskName="TransformXml" 
              AssemblyFile="
              $(MSBuildExtensionsPath)\Microsoft\VisualStudio\v12.0\Web\Microsoft.Web.Publishing.Tasks.dll" />
   <ItemGroup>
      <Config Include="LIVE">
         <Environment>LIVE</Environment>
      </Config>
      <Config Include="QA">
         <Environment>QA</Environment>
      </Config>
   </ItemGroup>
   <Target Name="Release">
      <MakeDir Directories="CoolService\Configuration\%(Config.Environment)" />
      <TransformXml Source="App.config" Transform="CoolService.%(Config.Identity).config" 
                    Destination="CoolService\Configuration\%(Config.Environment)\CoolService.exe.config" />
   </Target>
</Project>

Where the $(MsBuildExtensionsPath) will likely be something like “C:\Program Files (x86)\MSBuild\”. So once we have a MSBUILD file like this in place, it is just a simple matter of running MSBUILD something like:

MSBUILD Transforms.proj

Which will result in the following being produced:

XML
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
   <configSections>
      <section name="nlog" 
      type="NLog.Config.ConfigSectionHandler, NLog" />
      <section name="shareSettings" 
      type="SimpleConfig.Section, SimpleConfig" />
   </configSections>
   <shareSettings productName="Shipping" 
   ftpPath="\\shipping\ShippingRoutes" />
   <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <extensions>
         <add assembly="Gelf4NLog.Target" />
      </extensions>
      <targets async="true">
         <target name="graylog" xsi:type="graylog" 
         hostip="app-logging" hostport="12200" 
                 Facility="CoolService">
            <parameter name="exception" 
            layout="${exception:format=tostring}" optional="true" />
            <parameter name="processname" layout="${processname}" />
            <parameter name="logger" layout="${logger}" />
            <parameter name="treadid" layout="${threadid}" />
         </target>
         <target name="file" xsi:type="File" 
         layout="${longdate} | ${level} | 
         ${message}${onexception:${newline}EXCEPTION\:${exception:format=tostring,StackTrace}}" 
                 fileName="D:/logs/CoolService-${shortdate}.log" />
      </targets>
      <rules>
         <logger name="NHibernate.*" minlevel="trace" 
         writeTo="graylog" final="true" />
         <logger name="NHibernate.*" minlevel="Error" 
         writeTo="file" final="true" />
         <logger name="*" minlevel="trace" writeTo="graylog" />
         <logger name="*" minlevel="trace" writeTo="file" />
      </rules>
   </nlog>
   <startup>
      <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
   </startup>
   <system.serviceModel>
      <diagnostics performanceCounters="All" />
      <bindings>
         <netTcpBinding>
            <binding name="tcpBinding" 
            maxReceivedMessageSize="2147483647" closeTimeout="00:59:00" 
                      openTimeout="00:59:00" 
                      receiveTimeout="00:59:00" sendTimeout="00:59:00">
               <security mode="None" />
               <readerQuotas maxStringContentLength="8192" 
               maxArrayLength="20971520" />
            </binding>
         </netTcpBinding>
      </bindings>
      <client>
         <!-- CoolService -->
         <endpoint name="coolServiceEndpoint" 
         address="net.tcp://appCoolService:63006/CoolService" 
                   binding="netTcpBinding" bindingConfiguration="tcpBinding" 
                   contract="Services.ICoolService" />
      </client>
   </system.serviceModel>
</configuration>

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United Kingdom United Kingdom
I currently hold the following qualifications (amongst others, I also studied Music Technology and Electronics, for my sins)

- MSc (Passed with distinctions), in Information Technology for E-Commerce
- BSc Hons (1st class) in Computer Science & Artificial Intelligence

Both of these at Sussex University UK.

Award(s)

I am lucky enough to have won a few awards for Zany Crazy code articles over the years

  • Microsoft C# MVP 2016
  • Codeproject MVP 2016
  • Microsoft C# MVP 2015
  • Codeproject MVP 2015
  • Microsoft C# MVP 2014
  • Codeproject MVP 2014
  • Microsoft C# MVP 2013
  • Codeproject MVP 2013
  • Microsoft C# MVP 2012
  • Codeproject MVP 2012
  • Microsoft C# MVP 2011
  • Codeproject MVP 2011
  • Microsoft C# MVP 2010
  • Codeproject MVP 2010
  • Microsoft C# MVP 2009
  • Codeproject MVP 2009
  • Microsoft C# MVP 2008
  • Codeproject MVP 2008
  • And numerous codeproject awards which you can see over at my blog

Comments and Discussions

 
-- There are no messages in this forum --