NHibernate and xmlpoke

Some time ago I wrote about targeting multiple environments through NAnt.  The basic concept is to use the xmlpoke task in NAnt to modify any XML configuration files your application might use.  One setting that changes in each deployment we have is the “connection.connection_string” setting in the NHibernate hibernate.cfg.xml file.  This setting controls the connection string NHibernate uses to connect to the database.

Unfortunately, I ran into some annoying problems that caused me a lot of frustration.  When I tried to use the xmlpoke task:

<xmlpoke file="${dir.website}hibernate.cfg.xml"
 xpath="//*/property[@name='connection.connection_string']"
 value="Data Source=${database.server};Initial Catalog=${database.name};Integrated Security=true">
</xmlpoke>

I kept getting this from NAnt:

[xmlpoke] No matching nodes were found with XPath expression '//*/property[@name='connection.connection_string']'.

I double, triple, and eleventy-tuple-checked the XPath and tried many other XPath combinations.  But the problem wasn’t with the XPath, it was with the hibernate.cfg.xml file.  Looking at the top at the NHibernate configuration file, I saw that the root element had an XML namespace applied to it:

<hibernate-configuration xmlns="urn:nhibernate-configuration-2.0">

I’ve used XML namespaces in the past to add prefixes to element names.  The xmlpoke documentation mentions namespaces, and this post confirmed it: I have to specify a namespace in the xmlpoke task for the XPath query to work correctly.

Armed with this, I was able to get my xmlpoke task working correctly:

<xmlpoke file="${dir.website}hibernate.cfg.xml"
         xpath="//*/hbm:property[@name='connection.connection_string']"
     value="Data Source=${database.server};Initial Catalog=${database.name};Integrated Security=true">
  <namespaces>
    <namespace prefix="hbm" uri="urn:nhibernate-configuration-2.2" />
  </namespaces>
</xmlpoke>

I had to do few things to get it to work:

  • Add the namespace element with the correct uri attribute
  • Give it a prefix, “foo” if you want, it doesn’t matter
  • Changed the XPath to use the prefix specified earlier on each element in the query

Now the XPath works and my property is changed correctly.  Even though I don’t specify a prefix in the namespace in the configuration file, I still have to declare the prefix in the xmlpoke task.  I’m sure there’s some smarty-pants XML guru that could tell me the details, but all I care is that my build is deploying the correct connection strings.

One less future headache for me.

Related Articles:

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Jimmy Bogard

I'm a technical architect with Headspring in Austin, TX. I focus on DDD, distributed systems, and any other acronym-centric design/architecture/methodology. I created AutoMapper and am a co-author of the ASP.NET MVC in Action books.
This entry was posted in Continuous Integration, Tools. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://www.bluespire.com/blogs Christopher Bennage

    I ran into this same issue a couple of weeks back (proof that I should be blogging more.) It was painful. Ugh.

  • http://www.flux88.com Ben Scheirman

    The way I tackle this is to take any file that has variable content in it, like:

    * web.config’s
    * app.config’s
    * db pro project settings
    * nhibernate xml files
    * IOC config files

    and create a template file that is stored in source control under the /config folder. Then I put the environment settings into the local-properties.xml file that gets loaded into NAnt to provide machine specific settings.

    These template files have tokens in them like @DB_SERVER@ or @OUTPUT_SQL@, and then I just use the nant task to copy the files to their actual location, specifying a filterchain to replace the tokens with properties from the build config.

    This works very well, so far… and I don’t have to worry about xml poking :)

  • http://jimmybogard.lostechies.com Jimmy Bogard

    @Ben

    Yeah I go back and forth between templating and poking. Neither of them seem particularly easy to maintain in the long run, but that seems to stem from the fact that NAnt is a programming language in XML.

  • Matt Hinze

    Great call. This saved us today.

  • goku_da_master

    Perfect. Just what I was looking for. This example should be in the nant documentation since nhibernate is widely used now a days.

  • John Dhom

    Still good info, don’t lose this post! I was able to sort out how to use msbuild XmlPoke, for NHibernate, based on your info. Thanks. I’ve pasted a snippet below even though the formatting will likely be bad… as your post is still top of the list for “msbuild xmlpoke nhibernate”. Ha.

    note: %3B escaping of ‘;’ in msbuild

    Best,
    /jhd

    ==== property file====


    some-db-server
    some-database-name
    Server=$(DatabaseServer)%3BInitial Catalog=$(DatabaseName)%3BTrusted_Connection=True
    $(SourceDir)Configuration

    ==== build file====

    <Namespace Prefix=’hbm’ Uri=’urn:nhibernate-configuration-2.2′ />