Setting up NHibernate on medium trust hosting

Following my previous article about how I deployed this new ASP.NET MVC website on IIS 6 and .NET 2.0, now I'll explain how I made NHibernate (an Object-Relational mapper for .NET) work on the same platform (while in the next article I'll tackle Lucene.NET and NHibernate.Search).

NHibernate logo NHibernate is a port of the popular Hibernate library for Java, a complete and powerful object-relational mapper with a lot of features, allowing total control on how queries to the database are created and how your entities are fetched. It supports lazy fetching, has an own complete query language (HQL) and also has some contributed extension libraries (for instance NHibernate.Search, which I'll use to interface with Lucene.NET and provide full text searching).

First of all, we simply need to get a copy of the latest version of NHibernate (that is version 2.0.0 GA) from SourceForge. The library actually includes several dll files we will have to add to our website:

  • Castle.Core.dll and Castle.DynamicProxy2.dll which provide the framework NHibernate uses to generate "proxies" for your entities, thus enabling lazy fetching of interconnected entities,
  • Iesi.Collections.dll includes several types of collections not included in the standard .NET base classes, in particular ISet<T> and its implementations, which are enumerable collections without indexing and without repetitions (like mathematical sets).
  • log4net.dll is the logging library used by NHibernate. You can use the same library for your website's logging services.
  • NHibernate.dll: the core of the object-relational mapper.

In order to understand how to setup NHibernate you'd best read the 1.2 documentation (it's not perfectly aligned with the 2.0 version, but there are no groundbreaking changes). Intellisense is almost always enough to understand how the library works (except for HQL and some of the most advanced features which can be investigated in the docs or on the NHibernate forum).

Change some settings...

NHibernate works flawlessly and surprisingly well in most scenarios, but unfortunately there are still some problems if you need to publish your website on a "medium trust" server: first of all you'll have to change some of the settings in your web.config file.

<configSections> <section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate" requirePermission="false"/> </configSections>

This allows NHibernate to access its own configuration settings. And additionally, inside the NHibernate configuration section:

<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2"> <reflection-optimizer use="false"/> <session-factory> <property name="dialect">NHibernate.Dialect.MySQLDialect</property> <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property> <!-- other settings --> </session-factory> </hibernate-configuration>

This step apparently has some performance implications, but is needed to disable some features that might not be allowed by your host's security settings. However, the largest problem is still ahead...

Disable lazy loading... almost

When NHibernate needs to ensure lazy loading it sometimes has to create a proxy of your classes using the Castle.DynamicProxy2.dll library. This library makes use of some reflection features which are disallowed in the common "medium trust" environment.

My first suggestion is to do nothing initially and simply test your application online: there are some cases where it all can work painlessly (namely, when you have no lazy loading of types but only of collections, as explained later). Sometimes though, it simply won't work. You have two viable solutions of which I know of:

  1. Statically create all proxies needed by NHibernate: there is a long post about the solution on William C. Pierce's blog who implemented a ProxyGenerator for this case especially.
  2. Disable lazy loading of single types: this may sound like a very hindering thing, but it is not in most cases. Generally NHibernate only needs to generate a proxy for your entities when you have a direct single reference to another entity (that is, a many-to-one relationship): in this case NHibernate will populate one entity with a proxy instance and then fetch the effective value only if you access this said proxy. Anyway, you can still lazily load collections, because no proxy is generated for collections (they can always be loaded lazily).

Which solution to choose depends on you: the first one introduces a relatively complex post-compilation step because all proxies need to be generated at compile-time. The second one may introduce a heavy performance penalty on your application, but it depends on how your entity classes look.

In my case, I chose to disable lazy loading on all classes, except for all collections (which were 99% of all lazily loaded data anyway). To do so you'll have to change the NHibernate XML mapping file:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="..." namespace="..."> <class name="ClassName" table="TableName" lazy="false">> <cache usage="nonstrict-read-write" /> <id name="Id" type="Int32" column="Id" access="field.pascalcase-underscore"> <generator class="identity" /> </id> <!-- properties --> <set name="Collection" table="CollectionTable" inverse="true" lazy="true"> <key column="ForeignCol" /> <one-to-many class="ForeignClass" /> </set> </class> </hibernate-mapping>

NHibernate up and running

At this point NHibernate should work correctly, with lazy loading and everything.

In my case, the very last step to make it work on my host was to download an ADO.NET provider for MySQL and to add it to the website (also settings the correct references to it in the NHibernate web.config settings). You can download the official MySQL Connector/Net 5.2.3.