Sunday, September 26, 2010

How To Get Fluent NHibernate, NHibernate And Castle To Work Using Medium Trust

There are times when open source projects can give you incredible joy. Then there are other times when you just want to go find the developers of a particular open source project and yell at them just a little bit. The truth is that we should all be thankful that open source developers care enough to create fantastic open source projects, but sometimes things can get hairy and scary. I had one such situation with NHibernate, Fluent NHibernate, Castle and StructureMap when I tried to get everything working in a medium trust environment. I'm going to tell you how to solve the problem so that you can have an easier go of things than I had.


I created a beautiful project using NHibernate, Fluent NHibernate , the part of Castle that NHibernate relies on and StructureMap. Everything worked perfectly in development and I was super happy and all smiles. Instead of just releasing the project, I decided to create a coming soon page for it. The coming soon page can be seen here - http://www.thedesigncoders.com/comingsoon. That page has a contact form on it that uses NHibernate to persist the data. This page looked and worked great on my development machine, but I got a rude awakening after deploying it. That rude awakening was an error - System.Security.SecurityException: That assembly does not allow partially trusted callers. What? OMG! Here was the first lesson for me - always run your project on dev using the same trust level as your production environment. Doing this would have shown me the error well before deployment. OK. Lesson learned.

Now I was in a pickle. The error was occurring in Castle according to the error message. I used Google to investigate the issue. There were a whole lot of different things that people tried. One of them was to disable lazy loading. I nearly lost my lunch when I read that! I had set up Fluent NHibernate using its AutoMap feature and I had an EXTENSIVE database system with a lot of interconnected many to one, one to one and one to many relationships. Disabling lazy loading would basically mean that I might as well remove NHibernate and Fluent NHibernate and use Entity Framework. That, however, would have taken me a long time to do and it simply wasn't anything I even wanted to think about. I don't have anything against Entity Framework, but it took effort for me to set up NHibernate, Fluent NHibernate and StructureMap and I wasn't about to abandon my beautifully done project because of one stupid error. I was GOING to figure this out.

OK. So after viewing some blogs AND the NHibernate website, which suggested that I would need to go through hell and high water to get things to work, I decided to keep searching. Here are some of the articles I came across.


  1. Use NHibernate Proxy Generators
    http://nhforge.org/blogs/nhibernate/archive/2008/09/23/introducing-nhibernate-proxygenerators.aspx
    This would be good, but I'm using Fluent NHibernate's AutoMap feature so I don't use mapping files. That means that this is useless to me and it is likely unnecessary for you.

  2. Disable Lazy Loading, Disable Reflection Optimization & Change Web.Config Permissions
    http://nhforge.org/wikis/howtonh/run-in-medium-trust.aspx
    No, no and NOOOOOOOOOOOO!!!!!!! Fluent NHibernate's AutoMap feature makes things REALLY easy for me. If I had to disable lazy loading on my project given how large the database is and how much work Fluent NHibernate saves me from doing, I would have a fit. This just WAS NOT an option. In fact, it was a beyond useless idea to me.

  3. Rebuilding The Castle Project, NHibernate and Fluent NHibernate
    http://blog.yeticode.co.uk/2010/03/running-nhibernate-in-medium-trust/
    Hmmmm....this sounds good...... or so I thought! I would SIMPLY download all three projects, change the assembly in Castle to AllowPartiallyTrustedCallers, build it and use the dlls to then rebuild everything else. Great! I download the latest version of Castle and I start down that road. God/Allah/Jehovah/Jesus/Messiah/ HELP ME!!! It is times like these that make you feel stupid. I did all of that without thinking about ONE important (very important) thing - I didn't initially pay attention to the various versions of the files! Doooh!! Things did not match up! This version needed that version and that version needed this version and so on and so on. The problem wasn't JUST the versioning. Castle rolled its Dynamic Proxy into Castle.Core. It used to be its own project, but they changed this in the latest version. This meant that I had to change various parts of NHibernate. NHibernate was looking for a reference to Castle.Core AND Castle.DynamicProxy. I was starting to think about looking for a drink - and that says a lot because I have never had a drink of alcohol in my life! Fortunately, I figured out a different way.

I started thinking about the problem. The problem was that I couldn't set this project up on my chosen host because they don't allow people's apps to use full trust and the components I was using required full trust to do certain things. Surely I wasn't the only person who had this issue. In fact, I was positive I wasn't the only person with this issue because Google told me so (lol). Therefore, someone else had to have come up with a solution. I found that someone or a group of someones (I know this isn't proper grammar) had already solved the problem for their project. That project is called Cuyahoga. That brings me to solution number 4 -


    4. When In Doubt, Use The Files Of Someone Else To Work It Out! (I love that rhyme)

    Yeah! Now that is my kind of solution. After pulling out my hair by the root, this “solution” left me with 5 strands left! Cuyahoga is using NHibernate with Castle. Since they have already conquered the medium trust issue, I knew that their latest files should be sufficient for me. They don't use Fluent NHibernate (shame on them), but I knew that it would be nothing for me to download the latest source of Fluent NHibernate, add the dlls I took from Cuyahoga to the src and then compile everything. That is what I did and it worked like a charm. I swapped out the dlls in my project and I didn't have to disable or change anything else. Yes! Yes! Yes!

    Here is the link to the Cuyahoga files.

    https://cuyahoga.svn.sourceforge.net/svnroot/cuyahoga/trunk/lib

There you have it! Using those files will allow you to get everything running in a medium trust environment!


There are a couple of things that I found during my search that troubled me. There have been a lot of people who have had this issue. I would think that the open source project creators, especially NHibernate, would create source code that works in a medium trust environment. They won't. Making people do it themselves isn't necessarily a bad thing, but everyone doesn't want to spend time struggling to get things done. That is one of the things that makes Entity Framework appealing to the masses - for the most part, it just works.


Here is a link to one particularly onerous discussion surrounding the issue involving users and the Nhibernate developers. I found the whole character of the discussion to be completely distasteful. It shouldn't be so hard to do something that is so easy.

http://groups.google.com/group/nhusers/browse_thread/thread/dbfa6840d42f4c12/0db76f949568f947?lnk=gst&q=medium+trust#0db76f949568f947


If you have this issue, don't fret, worry or drive yourself insane. Just get those files and make it happen. Do not, I repeat, do not disable lazy loading for NHibernate to make it work in a medium trust environment. That defeats the whole purpose of the tool.

Smooches,

Kila

8 comments:

Andrew McFall said...

Thank you, thank you, thank you!

Kila Morton said...

Andrew you are welcome, welcome, welcome :-)! Now go pat yourself on the back, get yourself some great chocolate and relax (for a minute at least).....

Mike Smith said...

Hi there. Just wondering what files were needed from the Cuyahoga to make nHibernate work in medium trust environment. All of the Cuyahoga files? Thanks a bunch.

Kila Morton said...

Hi Mike,

You don't need all of the files. You just need the files for Castle, NHibernate and any other libraries that you are using for your project. That should get you going!

Josh said...

Kila,

I'm running into this issue now with recent binaries from FluentHibernate 1.2 (for NH3.1). I thought this was resolved in Castle, (See comment: http://goo.gl/yyUGW). I'm sure you have read into this article too.

As stated I looked for the Cuyahoga binaries, but they are old versions. NHibernate.ByteCode.Castle.dll is at v3.1, Cuyahoga has v2.1.

Anyway, when using the latest release of FluentNhibernate, are you still running into this issue?

What suggestions do you have?


Thanks,
Josh

Josh said...

Oh boy. I just found out what I did wrong. Stupid mistake, look:

I typed "NHibernate.Bytecode.Castle.ProxyFactoryFactory"

Instead it should have been

"NHibernate.ByteCode.Castle.ProxyFactoryFactory"

Notice the difference?

SMH

Kila Morton said...

Ha! Bytecode and ByteCode - you have to love it! I'm glad you got things working!

gnaruna@gmail.com said...

After updating latest dll error is from global.asax only in server but works fine in my system...

error is null reference error while buliding the session in global.asax..


kindly suggest solution