Wednesday, February 9, 2011

[General-Dev]–Getting NHibernate configuration to work with Web.Config transformations

Web.config transformations are a great new feature of Visual Studio 2010. They let you have a base Web.Config file, and then make modifications to it based on wether you are in a Debug or Release configuration. This simplifies scenarios such as using a test database in debug mode. You can read more on this feature on MSDN.
I’m currently using NHibernate on an ASP.NET project, and wanted to use web config transformations to swap the databases that I am using. To do this, I setup the nhibernate configuration sections in the web config as per usual, that is, similar to this:
 
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
  <session-factory name="PmqccSessionFa ctory">
    <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
    <property name="connection.connection_string">
      Data Source=SQL_SERVER;Initial Catalog=TEST_DATABASE;Integrated Security=SSPI;
    </property>
..... etc 
Here I setup using my test database details, and then in the web.release.config I chose to replace these with the real database.
 
<hibernate-configuration>
  <session-factory name="PmqccSessionFactory" >
    <property xdt:Transform="Replace" xdt:Locator="Match(name)" name="connection.connection_string">
      Data Source=SQL_SERVER;Initial Catalog=REAL_DATABASE;Integrated Security=SSPI;
    </property>
  </session-factory>
</hibernate-configuration>
However this did not seem to work – after pulling my hair out for a while, this stack overflow post helped me to find the solution. It appears the problem is to do with the xmlns attribute on hibernate-configuration. It conflicts with some part of the transformation procedure.
To solve the issue, I tried to remove the namespace attribute, which appeared to work when I deployed it, but then I ran into some issues with cassini not using the hibernate configuration from the web.config and instead looking for nhibernates own config xml file.
In the end, the solution was to go to my web.release.config file and add the following to the <configuration> tag:
xmlns:hib="urn:nhibernate-configuration-2.2"
this declares the hib: prefix on tags to relate to the hibernate namespace, so then I updated my hibernate transformation code to be
<hib:hibernate-configuration>
  <hib:session-factory name="PmqccSessionFactory">
    <hib:property xdt:Transform="Replace"  xdt:Locator="Match(name)" name="connection.connection_string">
      Data Source=SQL_SERVER;Initial Catalog=REAL_DATABASE;Integrated Security=SSPI;
    </hib:property>
  </hib:session-factory>
</hib:hibernate-configuration>
and all worked correctly.

2 comments:

Sami said...

Was the resulting web.config correct? I tried similar setup to yours but the resulting web.config had namespace attribute on the property. element. <property name="default_schema" xmlns:hib="urn:nhibernate-configuration-2.2">xxx</property>

Rod Howarth said...

I believe this is the desired result isn't it? We just remove the xmlns from the original to the release and then I believe the web config transformation combines the two.

Did your NHibernate connect successfully after doing this?