References from class library are not copied to running project bin folder

developer82 picture developer82 · Nov 29, 2013 · Viewed 9.8k times · Source

I have a class library that represents my logic layer. To that library I've added a nuget package for Google.Apis.Analytics.v3 - it installed the package and all it's dependencies.

I have a console application that uses that logic class library (regular reference). everything is written and compiled fine.

The problem is that during runtime it threw an exception that Google.Apis.dll wasn't found. This DLL is a dependency that was downloaded with the nuget.

Checking the BIN folders, I've found that in the class library bin folder this DLL was present, but in the console application BIN folder it wasn't (while other related DLLs were). So this means that the not all references where copied during compilation.

I've searched online, and found all kind of workarounds that didn't really work (like manually editing the project file and removing a true xml line on that dll definition).

What I ended up doing is adding the same nuget library to my console application - it works but feels a little dirty and not the way it should be. I think the console app is the client who's supposed to get it's services from that logic class library which should know it's stuff without the "client" worrying about it.

Also, that console app is not the only one who's gonna use that service, I'm also planning on a web app that will use that functionality - so I will need to add the same nuget to that web app as well - again, feels a little messy...

Is it just me? is that the right way to go about it? I was thinking about writing a WCF project to handle that functionality - but that seems a little of a overhead for just on functionality, and probably slow my workflow down just to keep things "cleaner" in my opinion.

Am I just over-thinking it?

Thank

Answer

deadlydog picture deadlydog · Jan 10, 2014

Explanation

For a sample scenario let's say we have project X, assembly A, and assembly B. Assembly A references assembly B, so project X includes a reference to both A and B. Also, project X includes code that references assembly A (e.g. A.SomeFunction()). Now, you create a new project Y which references project X.

So the dependency chain looks like this: Y => X => A => B

Visual Studio / MSBuild tries to be smart and only bring references over into project Y that it detects as being required by project X; it does this to avoid reference pollution in project Y. The problem is, since project X doesn't actually contain any code that explicitly uses assembly B (e.g. B.SomeFunction()), VS/MSBuild doesn't detect that B is required by X, and thus doesn't copy it over into project Y's bin directory; it only copies the X and A assemblies.

Solution

You have two options to solve this problem, both of which will result in assembly B being copied to project Y's bin directory:

  1. Add a reference to assembly B in project Y.
  2. Add dummy code to a file in project X that uses assembly B.

Personally I prefer option 2 for a couple reasons.

  1. If you add another project in the future that references project X, you won't have to remember to also include a reference to assembly B (like you would have to do with option 1).
  2. You can have explicit comments saying why the dummy code needs to be there and not to remove it. So if somebody does delete the code by accident (say with a refactor tool that looks for unused code), you can easily see from source control that the code is required and to restore it. If you use option 1 and somebody uses a refactor tool to clean up unused references, you don't have any comments; you will just see that a reference was removed from the .csproj file.

Here is a sample of the "dummy code" that I typically add when I encounter this situation.

    // DO NOT DELETE THIS CODE UNLESS WE NO LONGER REQUIRE ASSEMBLY A!!!
    private void DummyFunctionToMakeSureReferencesGetCopiedProperly_DO_NOT_DELETE_THIS_CODE()
    {
        // Assembly A is used by this file, and that assembly depends on assembly B,
        // but this project does not have any code that explicitly references assembly B. Therefore, when another project references
        // this project, this project's assembly and the assembly A get copied to the project's bin directory, but not
        // assembly B. So in order to get the required assembly B copied over, we add some dummy code here (that never
        // gets called) that references assembly B; this will flag VS/MSBuild to copy the required assembly B over as well.
        var dummyType = typeof(B.SomeClass);
        Console.WriteLine(dummyType.FullName);
    }