MSBuild, assembly dependencies and the GAC

Today, while doing some .Net development I noticed something about MSBuild that is really annoying.  I’ve seen his before but didn’t know the reason behind it.  Now I do and it is a little frustrating.

If you have assembly A that depends on assembly B that depends on assembly C and assembly C exists in the GAC (Global Assembly Cache).  When assembly B is copied into assembly A’s “bin” directory during build, assembly C is not copied, even if you specify that assembly C is a “private” (copy local) dependency of assembly B.

The problem is that by default MSBuild’s ResolveAssemblyReference task will not copy referenced assemblies that are in the GAC to the build output directory unless the referenced assembly is specifically tagged as “private” by the build project being built.

So even though assembly A doesn’t directly reference assembly C in its code, it only uses C through the intermediate dependency B, you still need to add C to A’s referenced assemblies set for C to be copied into the build output of A.

There is a discussion of this issue here, on Microsoft’s developer forums.

6 thoughts on “MSBuild, assembly dependencies and the GAC

  1. You have just described much of my beef with the .Net platform. Scale the dependencies up to 50 projects to hold a few person years worth of work in its required web server and application projects, and you get this giant mess.

    I’ve sheen a shop where a tool was build to explicitly expunge old dlls from all over the goddam place.

    Nant looks promising, but I couldn’t get the debugging to run without it wanting to build the code itself.

    I have lisp book on my bookshelf now because all those brackets are just more attractive!

    1. I think of this problem more of an argument against the GAC than anything else. On our build server we don’t install anything in the GAC so builds drag all the assemblies they are dependent on around with them as they build.

      This problem shows up more prevalently on developer workstations where often 3rd party control libraries have to be installed in the GAC in order to show up in the Visual Studio form designer “toolbox”. Though I try and avoid the visual designer as much as I can.

      I actually quite like the C# language and most of the non-windows specific parts of the framework. There are lots of other good libraries out there and newer additions to the platform like LINQ, etc are very nice.

    1. There are a couple of reasons you would want to do this:

      1. The version of an assembly you have in the GAC is a different version to the version you want to ship with your app.
      2. You want to ship the referenced assembly with your app in the executable directory and your installer toolkit (eg Wix) builds the distributable from your build output directory.

      Or both, as was the case at my last job where I had no control over what was installed on my development machine (and therefore what was in the GAC).

  2. Ok. Sounds reasonable to me. I’ve always worked at clients where the app wasn’t being distributed – i.e. CDW, Motorola, Mercer, etc. Obviously, your scenario is much different and requires a different distribution strategy.

    There is another “variation” on the problem of assemblies not being copied to the Output dir of the MainApp:

    The main app (Web, WinForm, WCF, WPF, etc.) has a reference to Assembly A, Assembly B has a reference to Assembly C.

    If the reference from the MainApp to Assembly A is a “Project” reference, then Assembly C is NOT copied to the output directory of MainApp. If MainApp’s reference to Assembly B is a File reference, then Assembly C IS copied to the output directory of Main App.

    There are 3 ways around this that I can think of (none of them seem like a good solution to me):
    1. Have MainApp have a direct reference to Assembly C – NOT the best solution IMHO and highly undesirable.

    2. Use a File reference from MainApp to Assembly A instead of a Project reference.

    3. Use a post-build event or some other MSBuild, NAnt, PowerShell script, etc. to have Assembly C copied over to MainApp’s output directory.

    1. I was working at GS at the time I had this problem and the app was only distributed internally. But it was done so via an MSI install package.

      I can’t say I’ve experienced exactly what you are talking about. Sounds very similar to the problem I had. Most of our references were to other projects in the same solution and those projects had references to 3rd party binary assemblies. Those assemblies usually got copied OK. It was just stuff that was also in the GAC that hit us.

      On the whole it seems that MSBuild’s assembly resolution is a bit half-arsed.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s