In Part 1 of this series, we ran through an overview of transforms and how we can leverage then at build time rather than the default publish/deploy time. In Part 2, we went over how you can add your own transform to Web.config in addition to the Web.Debug.config and Web.Release.config. In Part 3 of this series, we are going to see how we can leverage transforms for other configuration files – not just Web.config.
What Other Config Files? Maybe Log4Net.config?
When you are working on a web project, you cannot help but use Web.config as it has essential elements needed for every web-based application. One thing that we do at my work is set up logging for every application. We use log4net as our logger of choice and we choose to keep the details of the log configuration in a separate file from Web.config. In the Web.config:
<add key="log4Net.ConfigurationFile" value="log4net.config" />
Which tells log4net to get its configuration from “log4net.config”.
Add a properly formatted log4net.config file to the project (RtClick Project >> Add >> New Item >> C# >> Data >> XML). Copy and paste this new file and rename the copy to log4net.BASE.config. You should now have 2 files in your project that look like this:
Create the Transformation Files!
What we want to do now is generate the transformation files for our Solution Configurations (like we have for our Web.Config). If you recall, for the Web.config files, we simply RtClick’ed on the Web.config file and we had a context menu item called “Add Config Transforms (it’s greyed out at this point because we have all the transforms for all of our solution configurations):
So to create the transforms, we should just do the same thing, right? Well, when we RtClick the log4net.config file, our context menu does not have the “Add Config Transforms” menu item!:
It seems that Microsoft assumed that transforms were only good for Web.config! There is a Visual Studio Add-on that will allow you to do this easily, but before we introduce this product, let’s first do it the “Hard Way”…
Adding Config Transforms Manually (The “Hard Way”)
Let’s say in our log4net.config file we are going to log to a database and in our BASE config file we have the connection string pointing to our Dev SQL server. You might see a config “connectionString” line that looks like this (lots of other keys have been removed):
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<log4net>
. . .
<appender name="AdoNetAppender_SqlServer" type="log4net.Appender.AdoNetAppender">
. . .
<connectionString name="Log4NetConString" value= "Data Source=otis-web02\otisdevsql;Initial Catalog=WebAppsLog;Persist Security Info=True;User ID=Logger;Password=L0gg3r02;MultipleActiveResultSets=True;" />
. . .
</appender>
. . .
</log4net>
</configuration>
We now want to create a log4net.Release.config that will transform this line to point to the Production SQL Server. We will add a new XML file to our project and name the file log4net.Release.config and place the following content in the file:
<?xml version="1.0" ?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<log4net>
<appender name="AdoNetAppender_SqlServer" type="log4net.Appender.AdoNetAppender">
<connectionString name="Log4NetConString" value= "Data Source=ReleaseSQLServer;Initial Catalog=WebAppsLog;Persist Security Info=True;User ID=LogUser;Password=xyz123;MultipleActiveResultSets=True;" xdt:Transform="SetAttributes" xdt:Locator="Match(name)" />
</appender>
</log4net>
</configuration>
Remember that transforms are, by default, only associated with Web.config files. So even when you Publish your project, MSBuild will ignore your log4net.Release.config file and will not automatically apply the transform. You must TELL MSBuild to do this. From Part 1 of this series, we can open the (Project).wpp.targets file and add the step for MSBuild to transform the log4net.BASE.config file using the log4net.
<?xml version="1.0" encoding="utf-8" ?>
<Project ToolsVersion="4.0"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<UsingTask TaskName="TransformXml"
AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll" />
<Target Name="TransformWebBASEConfig" BeforeTargets="BeforeBuild" >
<TransformXml Source="$(ProjectDir)Web.BASE.config"
Transform="$(ProjectDir)Web.$(Configuration).config"
Destination="$(ProjectDir)Web.config" />
</Target>
<Target Name="TransformLog4netBASEConfig" BeforeTargets="BeforeBuild" >
<TransformXml Source="$(ProjectDir)log4net.BASE.config"
Transform="$(ProjectDir)log4net.$(Configuration).config"
Destination="$(ProjectDir)log4net.config" />
</Target>
</Project>
Now, if we Build the project (using the Release configuration), we get the desired log4net.config line with the Connection string set to ReleaseSQLServer:
<connectionString name="Log4NetConString" value="Data Source=ReleaseSQLServer;Initial Catalog=WebAppsLog;Persist Security Info=True;User ID=LogUser;Password=xyz123;MultipleActiveResultSets=True;" />
Objective Complete: Transforming a non-Web.config Config File
Ok, so we accomplished the main objective of this post which is to make a config file other than Web.config do a transform when we build the project. You can follow the same technique to build your additional transforms (Debug, JDRLocal, etc.). For the remainder of this post, let’s dig just a little bit deeper.
In Part 4 of this series, I’ll just show you how to format your non-Web.config configuration files so that they appear in the Solution Explorer under the parent configuration file.
Transforms for ANY .config file: 5 Part Series
Part 1: Transforms on Build
This first part does an overview of the default behavior of transforms. It then shows how you can plug into the MSBuild process and apply your transforms at Build time rather than the default publish time.
Part 2: New Config Profiles
The second part of the series shows how to create a new solution configuration and the nuances of what happens behind the scenes (in case you want to delete a configuration). It also discusses having a local development configuration specific to an individual developer.
Part 3: Other Config Files
The third part discusses how to add a configuration for another element of the application (using log4net as an example). This post shows how this process differs from the handling of Web.config.
Part 4: Making the transforms look nice
This fourth part is just a quickie to show how you can manually make your other configuration files sit under their respective parent files.
Part 5: SlowCheetah & Advanced
This fifth and final post is where I try to bring together all of the elements from the previous posts together and introduce a Visual Studio extension that allows much of the previous posts to be accomplished easily and automatically.
No comments:
Post a Comment