NHibernate in a Medium Trust Environment
Save/Share | ![]() |
![]() |
![]() |
![]() |
![]() |
|
![]() |
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:
[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.
October 2nd, 2007 at 5:44 am
great post, but do you know if the new version of nhibernate have addressed this isse. i am struggling with this issue myself!!
October 2nd, 2007 at 6:40 am
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.
October 23rd, 2007 at 2:15 am
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 :).
October 31st, 2007 at 3:08 pm
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).
October 31st, 2007 at 3:10 pm
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”
October 25th, 2008 at 3:47 pm
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
October 27th, 2008 at 5:33 am
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.
October 27th, 2008 at 10:44 am
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
March 21st, 2009 at 7:45 pm
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
July 3rd, 2009 at 10:08 pm
To use NH in Medium Trust use Proxy Generators (of NHContrib)
http://nhforge.org/wikis/proxygenerators10/introduction.aspx