Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Missing project dependency when referring project

Tags:

c#

.net

nunit

I'm facing some issues with dependencies when referring projects in Visual Studio. Here is how my solution ReferenceTest is structured:

  • Common. A class library containing a static CommonClass.HelloWorld() method returning a string. The string returned by this method is read from a JSON config file using Microsoft.Extensions.Configuration (and a large set of its dependencies) installed using NuGet.
  • ConsoleApplication1. A console application writing the CommonClass.HelloWorld() string to the console using a static Worker.DoWork() method. This console application has a project reference to the Common project.
  • ConsoleApplication1Test. A class library using NUnit for testing that the Worker.DoWork() method from the ConsoleApplication1 is returning the expected string. This class library has a project reference to the ConsoleApplication1 project.

The ConsoleApplication1 console application is working as expected, but when running the unit test in ConsoleApplication1Test I get this exception:

System.IO.FileNotFoundException : Could not load file or assembly 'System.Runtime, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.

The System.Runtime.dll file (and perhaps others) is not copied to the bin-folder when compiling the ConsoleApplication1Test project. Why is this happening?

A zip-file with the demo solution can be found here: http://www.filedropper.com/referencetest

like image 888
dhrm Avatar asked Jul 11 '17 14:07

dhrm


People also ask

How do you add references to a dependency?

If you see a Dependencies node in Solution Explorer, you can use the right-click context menu to choose Add Project Reference. You can also right-click the project node and select Add > Project Reference.


1 Answers

Solution

I was able to reproduce and resolve this issue, and generate build logs that illustrate the differences.

First, the solution. I noticed that the ConsoleApplication1.csproj file had a line of configuration that the Test project did not. So, I added:

<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>

to the Test project file. The first <PropertyGroup> section now looks like this:

<PropertyGroup>
  <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
  <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
  <ProjectGuid>{A97E82A2-2EF9-43AB-A46B-882131BAF1D0}</ProjectGuid>
  <OutputType>Library</OutputType>
  <AppDesignerFolder>Properties</AppDesignerFolder>
  <RootNamespace>ConsoleApplication1Test</RootNamespace>
  <AssemblyName>ConsoleApplication1Test</AssemblyName>
  <TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
  <FileAlignment>512</FileAlignment>
  <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>

The unit test now fails because it can't find config.json. Success!

Edit: after running the build from the command line per below, the unit test passed. I'm not sure why config.json wasn't present when building from Visual Studio.

Partial Explanation

This AutoGenerateBindingRedirects property seems to change the way that the build process resolves references to libraries that are part of the .NET Framework. For example, a before and after verbose log output comparison shows that:

Unified Dependency "System.Runtime, Version=4.0.20.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a". (TaskId:97)
    Using this version instead of original version "4.0.0.0" in "C:\Users\User\Desktop\ReferenceTest\ConsoleApplication1\bin\Debug\Microsoft.Extensions.Configuration.Abstractions.dll" because there is a more recent version of this framework file. (TaskId:97)
    Using this version instead of original version "4.0.0.0" in "C:\Users\User\Desktop\ReferenceTest\ConsoleApplication1\bin\Debug\Microsoft.Extensions.Configuration.dll" because there is a more recent version of this framework file. (TaskId:97)
    Using this version instead of original version "4.0.0.0" in "C:\Users\User\Desktop\ReferenceTest\ConsoleApplication1\bin\Debug\Microsoft.Extensions.Configuration.Binder.dll" because there is a more recent version of this framework file. (TaskId:97)
    Using this version instead of original version "4.0.0.0" in "C:\Users\User\Desktop\ReferenceTest\ConsoleApplication1\bin\Debug\Microsoft.Extensions.Primitives.dll" because there is a more recent version of this framework file. (TaskId:97)
    Using this version instead of original version "4.0.0.0" in "C:\Users\User\Desktop\ReferenceTest\ConsoleApplication1\bin\Debug\Microsoft.Extensions.FileProviders.Abstractions.dll" because there is a more recent version of this framework file. (TaskId:97)
    Using this version instead of original version "4.0.0.0" in "C:\Users\User\Desktop\ReferenceTest\ConsoleApplication1\bin\Debug\System.Runtime.CompilerServices.Unsafe.dll" because there is a more recent version of this framework file. (TaskId:97)
    Resolved file path is "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7\Facades\System.Runtime.dll". (TaskId:97)
    Reference found at search path location "{TargetFrameworkDirectory}". (TaskId:97)

Changes to:

Unified Dependency "System.Runtime, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a". (TaskId:97)
  Using this version instead of original version "4.0.0.0" in "C:\Users\User\Desktop\ReferenceTest\ConsoleApplication1\bin\Debug\Microsoft.Extensions.Configuration.Abstractions.dll" because AutoUnify is 'true'. (TaskId:97)
  Using this version instead of original version "4.0.0.0" in "C:\Users\User\Desktop\ReferenceTest\ConsoleApplication1\bin\Debug\Microsoft.Extensions.Configuration.dll" because AutoUnify is 'true'. (TaskId:97)
  Using this version instead of original version "4.0.0.0" in "C:\Users\User\Desktop\ReferenceTest\ConsoleApplication1\bin\Debug\Microsoft.Extensions.Configuration.Binder.dll" because AutoUnify is 'true'. (TaskId:97)
  Using this version instead of original version "4.0.0.0" in "C:\Users\User\Desktop\ReferenceTest\ConsoleApplication1\bin\Debug\Microsoft.Extensions.Primitives.dll" because AutoUnify is 'true'. (TaskId:97)
  Using this version instead of original version "4.0.0.0" in "C:\Users\User\Desktop\ReferenceTest\ConsoleApplication1\bin\Debug\Microsoft.Extensions.FileProviders.Abstractions.dll" because AutoUnify is 'true'. (TaskId:97)
  Using this version instead of original version "4.0.0.0" in "C:\Users\User\Desktop\ReferenceTest\ConsoleApplication1\bin\Debug\System.Runtime.CompilerServices.Unsafe.dll" because AutoUnify is 'true'. (TaskId:97)
  Resolved file path is "C:\Users\User\Desktop\ReferenceTest\ConsoleApplication1\bin\Debug\System.Runtime.dll". (TaskId:97)
  Reference found at search path location "C:\Users\User\Desktop\ReferenceTest\ConsoleApplication1\bin\Debug". (TaskId:97)

I'd imagine that the assembly binding redirects in the app.config file are influencing some aspect of the assembly reference path resolution during the build process. This is supported by the appearance of this build output, only after adding the specified property:

Added Item(s): 
    _ResolveAssemblyReferencesApplicationConfigFileForExes=
        app.config
                OriginalItemSpec=app.config
                TargetPath=ConsoleApplication1Test.dll.config

I have not seen this particular property before and I don't know why it would be included in some projects but not others, or if there is a UI to alter this setting.

For reference, to produce the build output comparisons above, I did the following:

  1. Load the project from the link provided in the question
  2. Add the NUnit3TestAdapter NuGet package to the Test project (personal preference - the error was present when using the VS test runner)
  3. Run the tests to verify the errors
  4. Clean the solution
  5. Run msbuild /verbosity:diag ReferenceTest.sln > build.txt from the Developer Command Prompt in the solution folder
  6. Modify the Test project as described above
  7. Run msbuild /verbosity:diag ReferenceTest.sln > build2.txt
  8. Run devenv /diff build.txt build2.txt or your favorite compare tool
like image 121
Rob Hill Avatar answered Sep 20 '22 17:09

Rob Hill