Friday, July 6, 2012

Transforms for *.config Files, Part 5: SlowCheetah & Advanced

Can this be made any easier? Yes: SlowCheetah!
Ok… at this point you may be asking yourself if this process can be made any simpler. First, you have to be certain that you spell your transforms and Solution Configurations EXACTLY the same, otherwise they won’t get picked up properly. Additionally, you probably wouldn’t want to take the time to add the nice little <DependentUpon> tags to the transforms so they show up under the live config file.

Fortunately, you don’t have to. There is a Visual Studio Extension called SlowCheetah that will do this for you! SlowCheetah was originally developed for the same use we have described in these blog posts, but for modifying App.config files for console apps. See even App.config files do not have the transform capabilities of Web.config. SlowCheetah was developed by some Microsoft employees that wanted this transform capabilities. In fact, for console apps, SlowCheetah even hooks into your project script to run the transforms on application build, but only for Console apps – not web apps, so we still need our (Project).wpp.targets file.

Installing SlowCheetah
Tools >> Extension Manager >> Online Gallery >> Search for “Slow Cheetah”
Click “Download” and follow the instructions to install. When finished, you will need to restart Visual Studio to have the changes take effect.

Delete the log4net.Release.config and log4net.Debug.config files from your project. Now, RtClick on the log4net.config file and you should see a context menu like this:
image_thumb2_thumb
We now have a new options called “Add Transform”. Go ahead and select that option. You will get a notice that in order for your project to support transforms, the .csproj file will need to be modified and the project will be unloaded and reloaded to make that change happen. Go ahead and accept that message and you will end up with a project that looks like this:
image_thumb3_thumb

SlowCheetah went ahead an created the transform files we needed for all of our defined Solution Configurations and added them to our project and even added the <DependentUpon> tags to the files so they show up nicely under our log4net.config file.

The “REAL” Kicker: SlowCheetah’s Preview!
Ok… SlowCheetah is cool in that it will create our base transforms for any config file (including Web.config). But as I showed, it’s really nothing that you couldn’t do already. So what’s the real kicker to using SlowCheetah? Slow Cheetah will do a PREVIEW of your transform! You don’t even have to compile your code to see it!

Ok, but the problem we have right now is that our transforms are associated (read: <DependentUpon>) the transient Web.config and log4net.config. The “Preview” function of SlowCheetah compares the transform against is <DependentUpon> target. So what we need to do is move our transforms so that they hang from the *.BASE.config files.

SlowCheetah thinks any Web.*.config Pattern is a Transform
Another caveat to this process is that it appears that SlowCheetah thinks that ANY file with the pattern Web.*.config is a transform file. When I right click on Web.BASE.config, it gives me the option to “Preview Transform”:
image_thumb5_thumb

What I expected was the ability to “Add Transforms”. By renaming the file to Web.Main.BASE.config, I achieved what I was looking for:
image_thumb7_thumb

When finished, you should end up with log4net.BASE.config which is your main log4net configuration with 2 transforms: log4net.BASE.Debug.config and log4net.BASE.Release.config. and a log4net.config file which is the result file for the transform process. On the Web.config side, you should end up with a Web.Main.BASE.Config file which is your main Web configuration with 2 transforms: Web.Main.BASE.Debug.config and Web.Main.BASE.Release.config and a web.config file which is the result file for the transform process. You project should look similar to:
image_thumb8_thumb

Now, if you RtClick and of the transform files, you will get a content menu option to “Preview Transform” like this:
image_thumb10_thumb

Select the “Preview Transform” option and a window will display showing the original config file (Web.Main.BASE.config) and a temporary file with the transforms applied where you can then jump through the “differences” between the 2 files to confirm that your transforms worked!
image_thumb12_thumb

Final Step: Make the (Project).wpp.targets Use the New Names
So we almost have SlowCheetah working. Through this process, we have done a lot of naming changes. Our original log4net.config file is now really log4net.BASE.config. Our Web.config has morphed from Web.config to Web.BASE.config to Web.Main.BASE.config. Subsequently, out transforms have changed as well. In the end, after the transforms are complete, we still want the result of the transforms to become Web.config and log4net.config. So we modify the (Project).wpp.targets file to look like this:

<?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.Main.BASE.config"
Transform="$(ProjectDir)Web.Main.BASE.$(Configuration).config"
Destination="$(ProjectDir)Web.config" />
</Target>

<Target Name="TransformLog4netBASEConfig" BeforeTargets="BeforeBuild" >
<TransformXml Source="$(ProjectDir)log4net.BASE.config"
Transform="$(ProjectDir)log4net.BASE.$(Configuration).config"
Destination="$(ProjectDir)log4net.config" />
</Target>
</Project>


Advanced Issue: TFS
I was going to make this series a 4 part-er, but I think I can wrap up the final issues here. How do these changes effect TFS? Our web.config and log4net.config files are the most important files when we publish, but are not important to save in Source Control (TFS). To accomplish this scenario, you should exclude the result config files from TFS:
Click the Web.config/log4net.config in Solution Explorer then:
File >> Source Control >> Exclude (file) from Source Control
image_thumb[14]_thumb

Now, if these files have ever been in Source Control, they will have their Read-Only flag set. If you do not remove this, MSBuild will fail when it tries to write the result of the transform to these files.

Advanced Issue: PUBLISHING
As far as “publishing” goes, You want the log4net.config and web.config files to be copied always to the output folder, but you want the *.BASE.config files to never get copied. Recall that the publish process is where MSBuild tries to do transformations. However, with this new format, there are no transformation files hanging from the root Web.config or log4net.config files, so no transforms are attempted and the files are simply copied to the output folder.

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