Quantcast
Channel: hamang.net » .NET
Viewing all articles
Browse latest Browse all 10

Configuration Handling Reloaded

$
0
0

Configuration handling of web projects is a well discussed topic. There are lots of examples on how to configure web.config for different environments; using configSections, naming conventions, T4 transformations, web deployment projects etc.

Until now, this have been quite painful. Visual Studio 2010, however, has a new feature which opens up a lot of new possibilities; Config Transformations. This is a very cool feature and triggers when you publish your web application within Visual Studio.

Here is an example on how to handle advanced configurations and make them available locally too for testing and debugging purposes.

The challenge:

  • I want different config files for different environments.
  • I want to test different configurations locally and be able to debug them on my machine with a simple change. This means I must be able to compile my web.config file dynamically when building
  • I want my own settings which does not affect the configurations for my teammates.

XmlTransformation task to the rescue!

With the new XmlTransformation task for MSBuild, it is possible to manually trigger config transformations. This is great news because then we can control which files will be transformed and when they will be transformed. I can make more complex configurations and also have my own transformations which are personal and not checked into the version control system.

First, I would like to be able to test the different configurations. Lets say I have a web application which will behave different in different environments. This could be controlled in a database or it could be controlled in a config file.

As an example, I have created a simple solution with 2 themes, one red and one blue theme. Changing the configuration, should also change the theme on the web site. In order to achieve this I have created 2 themes in my solutions with a stylesheet for each theme that will set the background color of the header for the default ASP.NET site that comes with Visual Studio:


2 themes, one red and one blue


In order to be able to change this, I create some configurations in the Configuration manager in Visual Studio:

With the configurations, I am able to create additional transformation files for web.config:


Transformations files


Also notice that I have a Web.master.config file and a Web.mysettings.config file. The master file is the base file that will be used for all transformations. This should contain the settings which is most common for the different configurations. The mysettings file is my personal config file which I use for my personal configurations. For instance, I like to use Fiddler and this contains transformations for adding Fiddler proxy to the web.config file.

The content of the Web.mysettings.config file:

<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
    <system.net>
        <defaultProxy xdt:Transform='Insert'>
            <proxy proxyaddress="http://127.0.0.1:8888"/>
        </defaultProxy>
    </system.net>
</configuration>

Selecting the debug – blue configuration should result in the standard blue color for the default ASP.NET site when running/debugging the web application:

Selecting the debug – red configuration should result in having a red header in the web site:

In real life, a lot of different appsettings could be different for the different configurations.  In this example, the Web.debug – red.config file only contains

<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
    <system.web>
        <pages xdt:Transform="SetAttributes" theme="Red" />
    </system.web>
</configuration>

which will change the theme of the pages element.

Now, here comes the real magic. This is the code you have put into the project file of the web application to be able to modify the Web.config file. Edit the project file and paste this before the </Project> closing element

<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll" />
  <!-- This is a hack to perform the master => transform without mysettings of web.config when publishing the website. It will only trigger on -->
  <!-- publish within Visual Studio. It actually overrides the TransformWebConfig Target in the original Microsoft.Web.publishing.targets file, -->
  <!-- but since it is empty by default, it should work fine! -->
  <Target Name="TransformWebConfig">
    <Message Text="%09 ------------- Transforming web.config.master =&gt; web.config with $(Configuration) transformations --------------" />
    <TransformXml Source="web.master.config" Transform="web.$(Configuration).config" Destination="web.config" />
  </Target>
  <Target Name="BeforeBuild">
    <Message Text="%09 ------------- Transforming web.config with $(Configuration) transformations --------------" />
    <TransformXml Condition="Exists('web.mysettings.config')" Source="web.master.config" Transform="web.$(Configuration).config" Destination="web.transformed.config" />
    <TransformXml Condition="Exists('web.mysettings.config')" Source="web.transformed.config" Transform="web.mysettings.config" Destination="web.config" />
    <TransformXml Condition="!Exists('web.mysettings.config')" Source="web.master.config" Transform="web.$(Configuration).config" Destination="web.config" />
  </Target>
  <Target Name="AfterBuild">
    <!--<Delete Condition="Exists('web.mysettings.config')" FiThe BeforeBuoilles="web.transformed.config" />-->
  </Target>

Some comments on the code:

  • The TransformXml task comes with Visual Studio 2010, so all you have to do is make a reference to it with the using statement.
  • In the BeforeBuild Target,  this is where the transformations take place. This makes it possible to dynamically create Web.config every time a build triggers.
  • Using Source and Destination, it is possible to do transformations to all kind of XML file types, not only Web.config.- You could have appSettings.config, connectionsTrings.config etc. It would also be possible to make more hierarchical transformations by doing more than one transformation. Lets say there are some common settings for the red configuration which should be transformed in all environments, it would be possible to have this in a separate config file that will be transformed into the final web.config file.
  • The AfterBuild target should clean up the temporary config files. However, there seems to be a bug with the TransformXml task locking the files, so lets hope Microsoft fixes this in a future version.
  • The Web.mysettings.config transformation only triggers if there is a mysettings file available. This means not all teammembers have to create this file if they don't need to.
  • The target TransformWebConfig is a minor hack. In order to prevent the mysettings transformation when doing a Publish… within Visual Studio, I had to find a target in the Publish… event which triggers only when publishing. This target actually does nothing in the default Microsoft.Web.Publishing.targets file, so that's the reason for overriding this particular target. I wish it would be possible to actually hook into the publish event in Visual Studio through MSBuild, but that seems impossible. And using a target in MSBuild also overrides the target without having the option to call the base target which is overridden, so anything you do in that target will not be continued in the Microsoft.Web.Publishing.targets file. Lets hope MS don't put anything into that target in the future. I also tried to use DependsOnTargets, but that seems to trigger the target depending on, not listening to wheter the target has been run. That's a big difference.

Conclusion

Using the TransformXml task is a pretty simple solution to a complex problem. It comes with Visual Studio 2010 and makes environmental and application specific configurations much simpler to handle in real life. For Visual Studio 2008 and earlier, you still need to think different. Have a look at Andreas post on how to make complex transformations using T4 templates.

You can download the sample solution here: ConfigExample.zip.


Viewing all articles
Browse latest Browse all 10

Latest Images

Trending Articles





Latest Images