Lazy Loading with nHibernate Under Medium Trust

***Please visit NHForge.org for the latest information on NHibernate ProxyGenerators.***

Medium Trust is the Devil.  If you do not know what Medium Trust is in the context of ASP.Net, then I will leave you with one request and you can skip the rest of this post.  I entreat you to please mark all of your assemblies with AllowPartiallyTrustedCallers unless you have a compelling reason not to.  By adding this single attribute you remove the first of many hurdles that users of your software must contend with when running under Medium Trust.  If Medium Trust is such a pain, why would you ever subject your application to it?  Most third party hosting companies (GoDaddy, 1and1, WebHost4Life, etc.) lock down their servers to Medium Trust.  If you own a box or rent your own dedicated/virtual private server, then you don't have to deal with the pain that all of the other budget hosters are subjected to.

I am a big fan of nHibernate and am currently working on a little application in my free time that uses it.  It is a small time application and I don't have a lot of spare scratch so I started researching some shared hosting environments.  That is when I ran into Medium Trust and began investigating what that meant for nHibernate.  There are a lot of posts and forum entries out there on the topic so make sure and do your homework.  Mike Gavaghan has a nice chronicle on his Medium Trust adventure.  I compiled a list of what was needed to determine the feasibility of running nHibernate in Medium Trust.

  1. Add 'requirePermission="false"' to your nHibernate configuration section in your web.config file.  Ok, no big deal, nice and easy.
    <configSections>   
    <section name="hibernate-configuration" requirePermission="false" type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate"/>
    </configSections>
  2. Disable the Reflection Optimizer.  The docs say you may see a performance boost during initialization but see a performance hit over the long term operation of your app.  Run your own tests to determine the impact.  Again a simple configuration change.
    <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
    <reflection-optimizer use="false" />
    <session-factory>
    ...
    </session-factory>
    </hibernate-configuration>
  3. Disable all lazy loading of entities.  Whoa!  Big deal!  No Way!  Can't do it!

nHibernate saves me a lot of coding and pain by abstracting my datastore and provides a sweet Criteria API.  It also lets me structure my object associations to transparently retrieve entities from my data store in an 'on demand' fashion.  That statement glosses over a lot of details that you really need to familiarize yourself with if you decide to start using nHibernate.  But suffice it to say I consider it a critical feature. 

Why can't I use lazy loading in Medium Trust?  Lazy loading requires the generation of 'proxy' classes that delay the retrieval of associated entities from the data store until they are actually accessed in code.  I tried to find a better explanation but the best I could come up with is a dated Server Side.net article.  The generation of proxy classes requires Reflection permissions that are not granted in a Medium Trust environment.

After all this research it looked like I wouldn't be able to use nHibernate the way I wanted to in a Medium Trust environment.  I cried for a while and my wife comforted me and said maybe I should try Linq to SQL which made me cry even more.  Eventually I settled down and started thinking some more.  nHibernate needs to make a proxy for my entity.  OK, I've come to terms with that.  My entities do not change during the execution of my app, so I would think that the proxies wouldn't change.  Is there a reason why the proxies need to be generated at run-time?  Why couldn't they be pre-generated and deployed with the app?  Hmm...I need to do some spelunking in the nHibernate sources.  What creates the proxies?  A ProxyFactory of course.  OK, I will need to make one of those.  How do I tell nHibernate to use my ProxyFactory?  Well, I need a ProxyFactoryFactory and a small configuration addition...let's escape from the dark inner workings of my mind and cut to the chase.

I labored for a few hours and came up with a free tool that will allow you to generate an assembly containing pre-generated proxies for the purpose of enabling lazy loading in a Medium Trust environment.  That's right, free.  Not free as in speech.  Free as in I did all of the hard work so you wouldn't have to.  This tool is creatively named NHibernate Proxy Generator (NPG.exe) and it should be a nice addition to your nHibernate tool chest (right next to NHibernate Query Generator).  The implementation is quite...ghetto...the reason is due to the fact that my programming skills are sick, not IL, and I failed weaving in Home Ec.  My immediate plans are some refactorings that remove some of the dependencies that were used out of expediency (Boo Compiler and ILMerge).

NPG is currently of a quality between Meware and Alpha.  I want to stress that it is still very raw but I have tested it with both nHibernate mappings and ActiveRecord entities.  The command line syntax is very basic and it integrates nicely as an AfterBuild target with MSBuild.  Here is what you need to get started.

  1. Download the binaries or sources.
  2. Follow steps one and two above.
  3. Build the assembly containing your nHibernate or ActiveRecord entities.
  4. Run from the command line, passing the name of the input assembly from step two, and the name you would like to use for your output assembly.
    NPG.exe /in:My.Entities.dll /out:My.Entities.Proxies.dll /lazy:+
  5. --or--   You could add something similar to the following in the project file for your entities project:
    <Target Name="AfterBuild" Inputs="$(OutputPath)$(AssemblyName).dll" Outputs="$(OutputPath)$(AssemblyName).Proxies.dll">
    <Exec Command="..\..\tools\NHibernate.Proxy.Generator\NPG.exe /in:$(OutputPath)$(AssemblyName).dll /out:$(OutputPath)$(AssemblyName).Proxies.dll /lazy:+" />
    </Target>
  6. Add the following to your nHibernate configuration:
    <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
    <reflection-optimizer use="false" />
    <session-factory>
    ...
    <property name="proxyfactory.factory_class">StaticProxyFactoryFactory, My.Entities.Proxies</property>
    ...
    </session-factory>
    </hibernate-configuration>

The tool should work with any nHibernate Trunk build at revision 3090 or better.  When you run into issues with the tool, have suggestions for improvement, or want to add functionality please let me know.

posted @ Sunday, February 17, 2008 4:35 PM


Print

Comments on this entry:

# re: Lazy Loading with nHibernate Under Medium Trust

Left by hammett at 2/17/2008 6:14 PM
Gravatar

Lazy load of TYPES require proxy generation, but not of collections. Those are handled differently.

# re: Lazy Loading with nHibernate Under Medium Trust

Left by Marouane at 3/25/2008 8:01 AM
Gravatar

could you please include a simple sample web projet ?

# re: Lazy Loading with nHibernate Under Medium Trust

Left by Paul Anthony at 3/31/2008 3:02 PM
Gravatar

If this works.



I going to wet my pants. And love you forever.

# re: Lazy Loading with nHibernate Under Medium Trust

Left by PabloDG at 6/20/2008 3:59 PM
Gravatar

Really nice idea. My nhibernate scenario could require something similar: my nhibernate objects have to be serialized (through remoting), and nhibernate proxies can't be serialized. We I disable proxies, nhibernate stop getting aware of dirtiness of the objects. Do you think you invention could carry the dirty attribute propertly through my layers?

# re: Lazy Loading with nHibernate Under Medium Trust

Left by Dan Donovan at 8/21/2008 11:26 PM
Gravatar

This is exactly what I needed to get my app running on GoDaddy! Nice job... thanks!

# re: Lazy Loading with nHibernate Under Medium Trust

Left by Yannick Compernol at 8/23/2008 12:28 PM

This is exactly what I was looking for. But I'm getting the following exception while running your command line tool: (using your binaries zip)

Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'DynamicProxyGenAssembly2' or one of its dependencies. The system cannot find the file specified. File name: 'DynamicProxyGenAssembly2'.

Any thoughts?

# re: Lazy Loading with nHibernate Under Medium Trust

Left by Bill Pierce at 8/24/2008 6:55 AM
Gravatar

Hey Yannick,
I recommend grabbing the sources because I have made updates but haven't yet updated the binary distribution.

Make sure that Castle.DynamicProxy2.dll is in the same directory as NPG.exe. If that does not solve your problem, make sure it is in the same directory as your "in" assembly for which you are generating the proxies. If neither of those work I would grab the sources and give it a shot.

# re: Lazy Loading with nHibernate Under Medium Trust

Left by Yannick Compernol at 8/25/2008 1:57 PM

Used the source, it builds just fine, the Caste.DynamicProxy2.dll is in the same folder, but I still encounter the same error.

# re: Lazy Loading with nHibernate Under Medium Trust

Left by chris at 8/28/2008 7:44 AM
Gravatar

Thank you for the informative post. I was able to follow your instructions and get my nhibernate application running on godaddy shared hosting without using your proxy generator tool. I just used the AllowPartiallyTrustedCallers assembly attribute, as well as the config settings you supplied and all works great! Thanks!

# re: Lazy Loading with nHibernate Under Medium Trust

Left by Jose at 9/15/2008 12:57 PM
Gravatar

Hi, good approach.
Sadly I was not able to use it because it is tied to ActiveRecord (which is using NH 2.0.0.1001) and I need to use it with NH 2.0.0.4000
I would like to make some refactor to remove ActiveRecord from the mix.
What do you think about publishing this code to the community as a project inside NH.Contrib?

Regards

# re: Lazy Loading with nHibernate Under Medium Trust

Left by Mario at 3/21/2009 7:44 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

# re: Lazy Loading with nHibernate Under Medium Trust

Left by Verzekeringen auto at 6/8/2009 6:02 AM
Gravatar

The slides are gone?

Your comment:



 (will not be displayed)


 
 
 
Please add 5 and 3 and type the answer here:
 

Live Comment Preview:

 
«July»
SunMonTueWedThuFriSat
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678