Search code examples
visual-studio-2012msbuildbuild-process

Visual Studio 2012 assembly reference and "Copy Local" clarification


I have an existing project that I recently started maintaining and when updating a couple of the assemblies upon which one of the class libraries relies I ran into something that I don't quite understand.

  • 2 assemblies needed to be updated, neither was initially tracked by NuGet
  • Assembly A was no available on NuGet and had to be downloaded and referenced manually. I unzipped it to my desktop, removed the old reference, and added the new reference using "Add Reference > Browse"
  • Assembly B was available via NuGet so I removed the old reference and then added it back with package manager.
  • Both references have "copy local" set to true
  • Upon building in for both Debug and Release configurations the dlls were copied to their respective bin folders under the project.
  • At this point I delete the dll for assembly A that I had on my desktop, and the reference path now points to ..\solution\project\bin\Debug\assemblyA.dll when using the Debug configuration and ..\solution\project\bin\Release\assemblyA.dll when using the Release configuration.
  • Assembly B exists under ...\solution\packages\[packagepath]\assemblyB.dll as well as its respective Debug and Release bin folders, but the reference path points to the original copy in the NuGet packages folder.

Now here's where things get a little fuzzy to me. Just so I'm crystal clear on this and making no assumptions, my initial question for clarification is- when Copy Local is set to true in the above situations, which one is referenced- the original or the bin/[configuration] copy?

Once that's sorted, the real problem I'm having is that when rebuilding the solution for Release configuration, it wipes out my local copy of the assemblyA.dll. For the Debug configuration this does not happen. Why does this happen? Am I missing a setting or is this by design? If it's by design why the behavior discrepancy between builds and at that point what's the point of the Copy Local setting?


Solution

  • and the reference path now points to ..\solution\project\bin\Debug\assemblyA.dll

    Which is the problem. The CLR will only look in a two places for a DLL when you debug your app. It will look in the GAC first, in the same directory as your EXE next. So it will never find assembly A on your desktop, nor the NuGet assembly B in the packages subdirectory and your program won't run.

    Copy Local was designed to solve this, it is automatically set to True when you add a reference to a DLL that is not stored in the GAC. It is always False for .NET Framework assemblies, it will be True for your A and B assemblies.

    So what went wrong is that you first added the reference to the DLL that was on your desktop. And you built your app and got a copy in the bin\Debug directory. You then deleted the original that was on the desktop and changed the reference to the only one you had left, the one in bin\Debug.

    That works for a while. Until you use Build + Clean or Build + Rebuild. Commands that empty the build directory. Now your reference assembly is gone.

    What you should have done instead is copy it to a better location. The project directory is certainly a good one. Or a subdirectory of it, like NuGet does.