NHibernate in a Medium Trust Environment

Save/Share Google Yahoo! Add to Technorati Favorites Digg It Reddit
del.icio.us My Zimbio

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.


Join WebHost4Life.com

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:

[assembly: AllowPartiallyTrustedCallers()]

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 FileIOPermission:

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:

new ReflectionPermission(ReflectionPermissionFlag.ReflectionEmit).Demand();

If 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.


Join WebHost4Life.com

Save/Share Google Yahoo! Add to Technorati Favorites Digg It Reddit
del.icio.us My Zimbio

5 Responses to “NHibernate in a Medium Trust Environment”

  1. sarmaad Says:

    great post, but do you know if the new version of nhibernate have addressed this isse. i am struggling with this issue myself!!

  2. Mike Gavaghan Says:

    I’m not sure what they plan to do. Reflection and dynamic invocation are fundamental to the NHibernate design, so I don’t think anything can be done to change the code.

    On the other hand, I don’t think this is a bug in NHibernate. I think the hosting providers are being unreasonable in their security settings. I think the “fix” is to pressure the hosting providers into permitting the use of this basic and conventional programming mechanism.

  3. Andrey Says:

    Thanks for post, i bought shared hosting at 1and1.com, they too have same restrictions which doesn’t allow Nhibernate works properly. I will ask them to allow using reflection without restrictions for my application, maybe i won’t replace them on Webhost4life :).

  4. Manuel Abadia Says:

    Mike,

    you can disable the reflection optimizer setting putting this in the NHibernate config section:

    That should work in medium trust if you don’t access private members through reflection (forget using the accessor nosetter.camelcase-underscore).

  5. Manuel Abadia Says:

    I guess the less than and greater than characters are not friendly. This is what didn’t show up before:

    add key=”hibernate.bytecode.provider” value=”null”

Leave a Reply