views:

362

answers:

3

I'm organizing a VisualStudio 2008 solution using Fluent NHibernate and I would like to keep all the NHibernate dll dependencies buried in a "Back End" class library and let the front end Web app or Console app be ignorant of NHibernate.

My Solution structure is as follows:

BackEnd -- Class Library -- Business logic and Data Repositories & public API.. this level uses NHibernate privately for data storage and does not expose any NHibernate classes to the front end

Public -- Class Library --- POCO Objects with no dependencies used by both front end and back end. Backend uses NHibernate to persist these objects.

Front End -- Console App & a MVC Web App -- (Two front end apps (1) MVC2 Web app && (2) a console app) reference the Public & Back End projects and just use a few public methods on to interact with the Back End using Public objects.

What I would like to do is only reference NHibernate and its many dependencies once in Back End and have the Front End apps just reference the back end project. However, the Fluent BackEnd crashes at runtime if I don't reference every one of Nhibernate's dependencies in my front end app in addition to referencing them in the Back End. Here's the Back End code it crashes on complaining it can't find the nhibernate dlls when the front end omits the reference:

   public static ISessionFactory CreateSessionFactory()
    {
        return Fluently.Configure()
         .Database(SQLiteConfiguration.Standard.UsingFile(DbFile))
         .Mappings(m => m.AutoMappings
               .Add(AutoMap.AssemblyOf<EngineInfo>(type => type.Namespace.Contains("BackEnd"))
               .Conventions.Add(DefaultCascade.All())
               .Conventions.Add(DefaultLazy.Never())
               )
             ) //emd mappings
       .ExposeConfiguration(BuildSchema)//Delete and remake a fresh tmp db 
       .BuildSessionFactory();//finalizes the whole thing to send back. 


    }

It may be that I've accidentally exposed a NHibernate dependent resource to the Front End apps but I don't get any compile time errors, and I'd love a little direction.

If I do reference Nhibernate's dlls everything runs fine but in my front end apps I get the following warning at compile time:

*

Found conflicts between different versions of the same dependent assembly.

*

Any suggestions?

--Update--

I've narrowed the dlls that I have to reference in the front end down to NHibernate.ByteCode.Castle.dll and System.Data.SQLite I can skip all the others and not get runtime errors.. at least none yet.

I'm still not sure why either would be required because the front end never uses any NH or SQL lite resources except through the public interface of the back end which doesn't offer any Nhibernate or SQLite resources. All classes that touch NHibernate or SQLite are marked Internal so I'm not sure what could cause this dependency.

The visual studio dependency warning offers a solution that I'm a bit hesitant to apply since I don't know why the problem came up in the first place:

Do you want to fix these conflicts by adding binding redirect records to the appconfig file? --- MSDN on the option -- http://msdn.microsoft.com/en-us/library/bb383993.aspx

Any advice?

---Update--- Tom below seems to have replicated my problem so this is starting to sound like a NHibernate dll bug. I also tried upgrading from VS 2008 to 2010 and rebuilt the whole solution and replicated the error there. Any one want to take a look to make sure we're not missing something before I try to report it?

+2  A: 

Some of the NHibernate related dlls are probably referenced in the web project instead of the backend project. I you really can't find it, remove all NHibernate related dlls, clean your solution and just add them to the backend project.

Paco
That was my first thought when this problem popped up and so I removed every reference and added them back one by one. I'll double check that I got this right (there are a lot of NHibernate related dlls so I could have missed one).
Glenn
After remaking the solution and a lot of testing I'm certain that the required dlls are properly referenced on the backend, so I think I can rule this answer out.
Glenn
Sql lite is not used in any NHibernate related projects usable for a web project I know about, maybe it's reference somewhere else. You don't have to reference NHibernate.ByteCode.Castle.dll in the web project when you reference it in the backend. ByteCode.Castle might not be needed directly by the backend, but it is used indirectly by the castle proxy factory, unless you use a different proxy factory with NHibernate.
Paco
I should have been more precise in my description. In my repository I use NHibernate to query a sqllite db using system.data.sqlite as the connector.. so its not technically a NHibernate dependency just a resource Nhibernate happens to use. Does NHibernate inherit and override the virtual properties of my AutoMapped classes even if I don't use lazy loading? Maybe the POCO classes returned from the my Backend repository are really Nhibernate dependent children of my POCO classes?
Glenn
+2  A: 

I'm working on a project with a similar architecture, and ran into similar problems just yesterday - needed to include references for NHibernate in my project, even though there no direct references in the code to those assemblies.

Otherwise, got a runtime error, complaining about not being able to find NHibernate.ByteCode.Castle.

The problem turned out to be the way I was building. The NHibernate assemblies were not being properly propogated to my application's runtime directory, because I was using the standard VS2008 folder structure (bin\Debug, etc).

The first part of the fix was to create a single directory where all the assemblies are built and run. You can do this by setting the Output path (on the project's Build tab) for all the projects in your solution to point to this directory.

The second part of the fix was to set Copy Local = True for all the NHIbernate refs, and also the other assemblies in your solution (you don't need to set this for the standard assemblies - System, etc). This causes VS to copy all the assemblies used by a project to the common runtime directory everytime you build.

You should then be able to eliminate the NHibernate references from all the projects that don't use them directly.

This worked for me, but I can't help wondering if there's a better way to solve this problem. But it will do for now.

Edit:

After some more testing, it appears that there is a problem with all the Castle DLLs, NHibernate.ByteCode.Castle most notably.

One of the project's in my application is an assembly that contains the NHibernate logic, which contains references to all the NHibernate DLLs, including NHibernate.ByteCode.Castle.

When I add a reference to that assembly in another project, and build it, all the NHibernate DLLs get copied to the other project's Output directory - except the Castle DLLs!.

Other people have had similar problems I tried some of the workarounds suggested, with no luck.

I strongly suspect that the Castle DLLs don't properly support Microsoft's conventions for propagating dependant assemblies to other projects, but don't know enough to be sure.

Tom Bushell
Thank you! This sounds like what I need. I'll try out this option in the morning.
Glenn
I really appreciate your help. As I got into implementing this option the need to hand set the copy local and create the special output directory started worrying me because like you said, we really don't understand why it is necessary. Right now I just have a "problemlibs" folder where I can select all the problem dependencies at once and hit "add reference". I still get the vs warnings about version conflicts but no runtime errors. I kind of like having that warning flag as a reminder until I figure out the root cause.
Glenn
I've been doing some more testing as well, and getting different results from yesterday - and it's not at all clear to me why the behavior has changed! If you find "the Answer", please post it here!
Tom Bushell
I really appreciate your help. I'm going to un-select this answer and see if anyone can give us a better fix. If nobody does in a week or so I'll come back to flag this since its the closest thing we've got.
Glenn
+1  A: 

You need to eager load or NHibernateUtils.Initialize your objects before sending them over the wire, it is the castle proxy wrapper that is giving you grief I suspect.

Sky Sanders
I should have mentioned that I'm currently using .Conventions.Add(DefaultCascade.All()).Conventions.Add(DefaultLazy.Never())Shouldn't this address any initialization problems? Also, If I had a lazy loader problem it seems like I would still get run time errors even with the front end even with the extra dll references since the connection is closed at that point but instead everything works as long as I add the mysterious duplicate dll references.
Glenn
I updated the code section of my question to show how I'm turning off lazy loading and still having the same issue.
Glenn