I’ve recently started experimenting with NHibernate – the C#/.NET version of the Hibernate O/R matpping tool that was originally developed for Java. The Java version is very powerful, and I’m a huge fan of it. The C#/.NET version is, for the most part, a straight port of the Java code base (and an ugly port, in some ways). Nevertheless, it appears to be just as robust as its predecessor.
Be warned, however, that the NHibernate DLLs require a high level of trust in the ASP.NET environment they’re deployed to. I spent an entire weekend beating my head against a wall trying to get a simple app up on my GoDaddy account. I suspect NHibernate probably wasn’t designed with a medium trust environment in mind. I was able to make a few tweaks to get the code running with fewer permissions requirements. However, the permissions required to enable dynamic proxies – a fundamental part of the NHibernate architecture – are non-negotiable.
I learned from GoDaddy tech support that their Deluxe Windows plan, a shared host environment, simply doesn’t allow those permissions. I’d need to upgrade to a dedicated server, and that’s just a little too pricey for an environment simply for experimentation. I was able to get NHibernate working without any hacks at Webhost4life, but I thought I’d share what I tried first at GoDaddy just to help you understand the permissions implications if you’re in a medium trust environment — and how you might need to address them on your own projects.
Step 1 – Allow Partially Trusted Callers
Right off the bat, ASP.NET was complaining that my domain object assembly didn’t allow partially trusted callers:
[SecurityException: That assembly does not allow partially trusted callers.]
This is because NHibernate, during its startup configuration, references the persistent classes it’s configured to manage. The callbacks were denied because partially trusted callers are not permitted unless explicitly enabled. So, I needed to enable partially trusted callers in my own domain object DLL by adding this attribute to the assembly:
Step 2 – Tweak NHibernate.Mapping.Attributes
I use NHibernate.Mapping.Attributes to map my domain objects to my database tables. It’s a lot cleaner and easier to maintain than the old fashioned XML configuration files. Unfortunately, this add-on library to NHibernate doesn’t explicitly allow partially trusted callers. So, we again run into the problem of security exceptions when other assemblies attempt to invoke the NHibernate.Mapping.Attributes library.
Fortunately, the NHibernate library comes with a source code download (isn’t open source software great?). I simply added the
AllowPartiallyTrustedCallers attribute to the NHibernate.Mapping.Attributes assembly and rebuilt the DLL using the solution and projects provided. Voila!
The next roadblock, however, was this exception coming out of NHibernate.Mapping.Attributes:
SecurityException: Request for the permission of type ‘System.Security.Permissions.FileIOPermission
This simply turns out to be a quirk in how the
HbwWriter class was implemented. The class attempts to construct a “Type Name” + “Assembly name” string like this:
string typeName = type.FullName + “, ” + type.Assembly.GetName().Name;
The problem here is that the
Assmbly.GetName() method requires
FileIOPermission in order to return the assembly path. It’s not necessary for
HbmWriter to get the assembly name in this fashion, so I refactored this code to build the string in a way that doesn’t require
string assemblyName = type.Assembly.FullName;
int comma = assemblyName.IndexOf(“,”);
assemblyName = assemblyName.Substring(0, comma);
string typeName = type.FullName + “, ” + assemblyName;
Step 3 – Get Stymied By DynamicMethod
I solved the problem of partially trusted callers and an unnecessary dependence on
FileIOPermission, but the next problem I encountered was a showstopper.
In the core NHibernate library, the
ReflectionOptimizer class attempts to instantiate
DynamicMethod instances to hang persistence-enabled methods off of your domain objects:
new DynamicMethod(string.Empty, returnType, argumentTypes, owner, canSkipChecks);
After decompiling the .NET SDK, I discovered this unavoidable permission demand in the DynamicMethod constructor:
ReflectionEmit is denied, this line of code throws a security exception. Alas, it’s not permitted in the GoDaddy environment I was using. It’s also nothing that can be reasonably worked around because dynamic proxies are an integral part of how NHibernate is built.
Everything works fine when I deploy to my new Webhost4life account because the shared environment permissions are more lax. So, the lesson learned is to scrutinize the trust level of your target platform before making an investment in NHibernate.
It’s unfortunate that most ASP.NET hosting providers aren’t explicit about the trust levels they provide in their different environments. I also discovered that their level one support techs generally can’t provide that information, either. Your best bet is to rely on the experience of others and to share your own.