views:

665

answers:

4

We had a very interesting problem with a Win Forms project. It's been resolved. We know what happened, but we want to understand why it happened. This may help other people out in the future who have a similar problem.

The WinForms project failed on 2 of our client's PCs. The error was an obscure kernel.dll error. The project ran fine on 3 other PCs.

We found that a .DLL (log4net.dll - a very popular open-source logging library) was missing from our release folder. It was previously in our release folder. Why was it missing in this latest release?

It was missing because I must have installed a program on my Dev box that used log4net.dll and it was added to the Global Assembly Cache.

When I checked the solution's references for log4net.dll, they were changed to "copy local=FALSE". They must have changed automatically because log4net.dll was present in my GAC.

Here's where my question starts:

Why did my reference for log4net.dll get changed from COPY LOCAL = TRUE to COPY LOCAL = FALSE? I suspect it's because it was added to my GAC by another program.

How can we prevent this from happening again? As it stands now, if I install a piece of software that uses a common library and it adds it to my GAC, then my SLNs that reference that DLL will change from Copy Local TRUE to FALSE.

A: 

Can you ensure yours is used by adding a hintpath to the msbuild/proj file?

From the above link:

HintPath : Relative or absolute path of the assembly.

Preet Sangha
+2  A: 

That happened because it makes zero sense to have Copy Local = True if an assembly is installed in the GAC. Because the local copy will never be used, the GAC is always searched first. Leaving it unchanged would cause major confusion. Changing it causes a confusion too, that could perhaps have been addressed with a message box at solution load time.

The real problem here is the sloppy distribution model for log4net. It is quite irresponsible to have so many copies of that assembly floating around in untold project directories with no way for Apache to be ever able to deploy an effective security update. Buy the vendor of that program you installed a cigar for doing something about it.

Consider posting to connect.microsoft.com to ask for a warning when Visual Studio automatically updates the Copy Local property.

Hans Passant
From nobugz: "Consider posting to connect.microsoft.com to ask for a warning when Visual Studio automatically updates the Copy Local property."Thanks, bugz. This is a great idea. A notification when "copy local" changes would be great. This is VS2K5, btw. It reminds me of VS2K3's magical markup mangling. Thanks for the insight, too.
D-Sect
True, and +1, although I wouldn't lay the blame entirely on Apache (or Neoworks, the original author) - I doubt they anticipated just how widespread the ad-hoc deployments would become. *Most* open source products aren't so arrogant as to try to weasel their way into your GAC, and if Apache changed the model now, it would break existing code (as has been demonstrated here).
Aaronaught
Any way to prevent it from changing? I suspect that, "This is by design." If this is true, then I need to check refs periodically if my dev / build box is my main PC and I add / remove stuff frequently?
D-Sect
It makes *perfect* sense to honor Copy Local = True ... the app will never run on the build server (except possibly in testing scenarios). Even if the version is identical, you're building for the purposes of deploying, not running locally, so copying to the output folder does not harm the build in any way.
ZeroBugBounce
It makes even more sense to *not* put assemblies in the GAC on your build server.
Hans Passant
A: 

Hi D-Sect

At run time, assemblies must be in one of two locations: the output path of the project or the global assembly cache (see Working with Assemblies and the Global Assembly Cache). If the project contains a reference to an object that is not in one of these locations, then when the project is built, the reference must be copied to the output path of the project. The CopyLocal property indicates whether this copy needs to be made. If the value is true, the reference is copied. If false, the reference is not copied.

The project-assigned value of CopyLocal is determined in the following order:

  1. If the reference is another project, called a project-to-project reference, then the value is true.
  2. If the assembly is found in the global assembly cache, the value is false.
  3. As a special case, the value for the mscorlib.dll reference is false.
  4. If the assembly is found in the Framework SDK folder, then the value is false. Otherwise, the value is true.

Regards... Muse VSExtensions

Muse VSExtensions
A: 

I just encountered this problem on our build servers too. This is very annoying (and unexpected) behaviour by Visual Studio. Two workarounds:

  1. Remove the assemblies from the GAC.
  2. Add a PostBuild event to manually copy the assemblies into the output directory.
Richard Dingwall