NHibernate in a Medium Trust Environment

Save/Share Google Yahoo! 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

10 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”

  6. Joel Says:

    are you still using NHibernate on a shared hosting environment at webhost4life? I quit my account at godaddy because nhibernate did not work and contacted webhost4life to make sure they support it before I sing up for the account. Their answer was that they do not support it on any shared hosting server. Now I’m a bit confused

    Are still using nhibernate on a shared hosting environment at webhost4life?

    Thanks

  7. Mike Gavaghan Says:

    Yes, but it’s an account that’s over a year old. Perhaps their new policy only applies to new accounts? I don’t know.

    You might ask if they offer a trial period. You could try out your apps, but then take a refund if it doesn’t work out.

  8. Joel Says:

    hi Mike,

    thanks a lot for your reply. They do have a “45 day money back guarantee” policy and I’ll do as you suggest.
    I’m in the situation you were sometime ago: I want to put a project online and don’t want to invest too much in hosting. Using NHibernate would also mean less work.

    Thank you once again,
    Joel

  9. Mario Says:

    Hi,

    I also had the problem making NHibernate work with medium trust and this is what I did:

    First..you need some sort of hosting that allows reflection in your server…There are some like crystaltech.com which will allow you to use reflection (in shared hosting) as long as it is used for assemblies within your designated app folder.

    Second…

    Download the Castle.DynamicProxy-vs2005 project. NHibernate ships with the dll, but you will need to modify the assembly to allow lazy loading under medium trust. Once you have the assembly, make sure nhibernate references this assembly and not the old dll.

    Open the Castle.DynamicProxy-vs2005 project and look for the ModuleScope.cs file (it is right in the main directory). There look for the method:
    private AssemblyName GetAssemblyName (bool signStrongName)
    In there comment out the following code:

    if (signStrongName)
    {
    byte[] keyPairStream = GetKeyPair();

    if (keyPairStream != null)
    {
    assemblyName.KeyPair = new StrongNameKeyPair(keyPairStream);
    }
    }

    Now give it a shot.

    Mario

  10. dev Says:

    To use NH in Medium Trust use Proxy Generators (of NHContrib)
    http://nhforge.org/wikis/proxygenerators10/introduction.aspx

Leave a Reply