Why do I get "System.IO.FileNotFoundException: Could not load file or assembly" when setting reference to "copylocal=false"?

FireWingLead picture FireWingLead · Jul 22, 2014 · Viewed 8k times · Source

Here is the situation: I am trying to run unit tests using a test project that I'll call "TestProject". It is testing a class in another project that I'll call "Class1" and "Project1".

Project1 does some dynamic lazy-loading of various dll's at runtime, which I will call "TheDynamicDLLs". Project1 finds these dll's by looking in a directory relative to its own build output path.

The first part of the problem arises when TestProject references Project1. Obviously, it copies the newly built Project1.dll to its OWN build directory, and then when Project1.dll looks for TheDynamicDLLs in the path relative to its location, it can't find them, because it is running from TestProject's location, not its own.

To fix this, I went to TestProject's references, right clicked the Project1 reference, and opened up its properties. I then set "Copy Local" to "False". I also made sure that the reference's "Path" property was the same as Project1's build path.

Now I have a new problem, and I can't even figure out what it is. Whenever I run the unit test, it fails with a report of "System.IO.FileNotFoundException: Could not load file or assembly [information naming Project1 as the un-findable assembly]".

Furthermore, when I try to debug the unit test, instead of just running it, it never throws an exception, or complains, or anything, thereby preventing me from finding out any further info about the problem. I can't find any further helpful info in the test report either.

Here is the full test report with names and such swapped out for confidentiality purposes:

Test Name:  Class1_Tests
Test FullName:  TestProject.TestClass.Class1_Tests
Test Source:    c:\Code\Solution1\Tests\TestProject\TestClass.cs : line 175
Test Outcome:   Failed
Test Duration:  0:00:00.0348455

Result Message: 
Test method TestProject.TestClass.Class1_Tests threw exception: 
System.IO.FileNotFoundException: Could not load file or assembly 'Project1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.=== Pre-bind state information ===
LOG: DisplayName = Project1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
 (Fully-specified)
LOG: Appbase = file:///C:/Code/Solution1/Tests/TestProject/bin/Debug
LOG: Initial PrivatePath = NULL
Calling assembly : TestProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.
===
LOG: This bind starts in default load context.
LOG: Using application configuration file: C:\Code\Solution1\Tests\TestProject\bin\Debug\TestProject.dll.config
LOG: Using host configuration file: 
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.
LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
LOG: Attempting download of new URL file:///C:/Code/Solution1/Tests/TestProject/bin/Debug/Project1.DLL.
LOG: Attempting download of new URL file:///C:/Code/Solution1/Tests/TestProject/bin/Debug/Project1/Project1.DLL.
LOG: Attempting download of new URL file:///C:/Code/Solution1/Tests/TestProject/bin/Debug/Project1.EXE.
LOG: Attempting download of new URL file:///C:/Code/Solution1/Tests/TestProject/bin/Debug/Project1/Project1.EXE.
Result StackTrace:  at TestProject.TestClass.Class1_Tests()

From the logs, it looks like TestProject is STILL trying to load Project1's dll from its OWN #$%^ing build path despite my EXPLICITLY telling it NOT to copy local. (grrrr...)

What am I doing wrong?

Answer

FireWingLead picture FireWingLead · Jul 23, 2014

!!!PLEASE NOTE: The original question I posted was about a problem with my solution to a deeper problem. This answer is a solution to that deeper problem, not the problem the question asks about.

To further explain: The original question was how to get the runtime environment to correctly load referenced dependencies when those references were set to "CopyLocal=false".

That question was asked because I had been setting copylocal=false to keep the dependency dll running in its original build path, even when it was loaded and run as part of a different unit test project, so that it would be able to find items at runtime that were located in folder paths relative to its build path.

This answer is an answer to the FIRST problem, eliminating the need to set copylocal=false in the first place. Hence, I will NOT be choosing my answer here as the most helpful. If anyone has an answer to the direct question, they should still post it to help people who may be struggling with that problem for different reasons than mine.

That said, here is my solution to the reasons for which I needed to set copylocal=false:

  1. Added TheDynamicDLLs to Project1, but NOT as references. Simply right clicked on Project1 in the solution explorer and chose "Add Existing Item", then browsed to the each dll location and added it AS A LINK. (Is important to add as a link so that it gets refreshed whenever it is rebuilt by its DynamicDLLProject).
  2. Right clicked the newly added item in Project1 and chose "Properties". Set "Build Action" to "None" and set "Copy to Output Directory" to either "Copy if newer" or "Copy always".
  3. Repeat steps 1 and 2 for each dynamic dll that Project1 will/might load at runtime.
  4. Of course, in the TestProject, I set the Project1 reference back to "Copy Local = True".

The effect of this is that while the dynamic dlls are not actually referenced or compiled into Project1 (as should be the case to keep them from eager-loading when Project1 runs), any projects that reference Project1 and copy its dll to their output path, will also copy over the items that are added as part of that project's output (in this case TheDynamicDLLs).

I hope that helps anyone who has this problem for a similar reason as I did.