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.
- 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>
- 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>
- 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.
- Download the binaries or sources.
- Follow steps one and two above.
- Build the assembly containing your nHibernate or ActiveRecord entities.
- 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:+
- --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>
- 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