Thursday, January 24, 2013

MSBuild doesn't copy DLL references from dependent projects

Recently in one of my projects we came across an interesting problem.  To explain the I will try and simplify it a bit. 

The Problem:

The problem was that there were two projects in my solution.  Lets say Project A and Project B.
  • Project A refers Project B 
  • Project B refers a third party DLL in my case it was the NHibernate.ByteCode.Castle.dll 
  • This DLL was referenced by Project B and had the Copy Local attribute set to True
  • However, when we build the projects using MSBuild, the Reference DLL NHibernate.ByteCode.Castle.dll was not copied to the output folder of Project A
There was no explanation for this behavior.  I had checked the project file as well, the NHibernate.ByteCode.Castle.dll was included in the Project B correctly with Private node set to true.  Then why was it that the reference DLL was not copied in the output folder for Project A?

The Analysis:

After some initial investigation, I noticed that there was no code in Project B that was directly making use of NHibernate.ByteCode.Castle.dll.  This DLL is loaded internally by NHibernate to enable Lazy Loading at the property level.

Since there is no Code that directly makes uses of the NHibernate.ByteCode.Castle.dll, MSBuild does not think its necessary to copy the DLL to the output folder of Project A.

The Solution:

The solution is a cheap trick, we need to make MSBuild think that we are actually using some classes from the NHibernate.ByteCode.Castle.dll.

What I did was, add a class into Project B called DynamicLoadedClasses.  This class will have a private constructor which simply instantiate any class from the NHibernate.ByteCode.Castle DLL.  Here's how my DynamicLoadedClass looks like
As we can see the DynamicLoadedClasses simply has a private constructor that instantiates the NHibernate.ByteCode.Castle.ProxyFactory class from the NHibernate.ByteCode.Castle DLL. This fools MSBuild that we are acutally using a class from the referenced DLL.

Now when we build the solution using MSBuild, we find that in the output directory of Project A, the DLL NHibernate.ByteCode.Castle.DLL actually gets copied.

You can find more details about this problem here.
Have some Fun!