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
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:
Load the project from the link provided in the question
Add the NUnit3TestAdapter NuGet package to the Test project (personal preference - the error was present when using the VS test runner)
Run the tests to verify the errors
Clean the solution
Run msbuild /verbosity:diag ReferenceTest.sln > build.txt from the Developer Command Prompt in the solution folder
Modify the Test project as described above
Run msbuild /verbosity:diag ReferenceTest.sln > build2.txt
Run devenv /diff build.txt build2.txt or your favorite compare tool
It seems that Newtonsoft.Json library which you are referencing from Common is referencing by itselft to System.Runtime ver 4.0
But all your project are targeted to 4+ framework.
That`s the point of conflict.
Try upgrade or reinstall NuGet package with Newtonsoft.Json library or downgrade the targeted framework of all project to ver 4.0.
Related
I'm using command dotnet build in order to build a game in the MonoGame framework in Ubuntu 20.04 using .NET 5.0.
It was fine in Windows, but now that I'm using it here, it gives me this error:
error CS1069: The type name 'PrivateFontCollection' could not be found in the namespace 'System.Drawing.Text'. This type has been forwarded to assembly 'System.Drawing.Common, Version=0.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' Consider adding a reference to that assembly. [/home/mrwoto/Ali/Programming/csharp/SAO/SAO/SAO.csproj]
So, is there anyway to resolve it? How can I add a reference to it in .csproj file?
One option is to add it from the terminal with
dotnet add package System.Drawing.Common
After this, you should be able to see something like the following in the .csproj file.
<PackageReference Include="System.Drawing.Common" Version="5.0.2" />
Please note that dotnet add is more than just adding some text to csproj.
From dotnet add package:
The dotnet add package command provides a convenient option to add a package reference to a project file. After running the command, there's a compatibility check to ensure the package is compatible with the frameworks in the project. If the check passes, a <PackageReference> element is added to the project file and dotnet restore is run.
I've now updated to Visual Studio 16.8, and with that, my existing (large) solution fails to build any WPF projects. Error messages such as the following everywhere:
10>C:\...\src\UserInterface\DataWriterMonitor\App.xaml.cs(5,25,5,28): error CS1558: "App" hat keine passende statische Main-Methode.
10>C:\...\UserInterface\DataWriterMonitor\App.xaml.cs(9,4,9,23): error CS0103: Der Name "InitializeComponent" ist im aktuellen Kontext nicht vorhanden.
Obviously, it's failing to pre-process the xaml files. When I change the csproj header of the offending project from <Project Sdk="Microsoft.NET.Sdk"> to <Project Sdk="Microsoft.NET.Sdk.WindowsDesktop"> I get:
10>C:\Program Files\dotnet\sdk\5.0.100\Sdks\Microsoft.NET.Sdk.WindowsDesktop\targets\Microsoft.WinFX.targets(240,9): error MC1000: Unbekannter Buildfehler, "Could not find assembly 'System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. Either explicitly load this assembly using a method such as LoadFromAssemblyPath() or use a MetadataAssemblyResolver that returns a valid assembly."
This even happens if I remove all direct references from the project.
Different other approaches (including setting the sdk to 4.8 in global.json) generated different error messages, but didn't work either.
How can I make that the build does not use the 5.0 SDK? I need it installed for other projects, but here I just want my solution to build as before with .NET Framework 4.8.
Note: I've tried the sample .NET 4.8 WPF app. This one builds, but it uses the old project file format. If I change it to the new format, I get similar problems. After some fiddling, that now works, possibly because this otherwise empty project has no references at all.
I apparently did too many things at once. Using a global.json with
{
"sdk": {
"version": "3.1.101"
}
}
and no other changes (especially no change to <Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">) fixed the build.
I removed <usewpf>true</usewpf> from my projects
The Problem
The Microsoft.Win32.Registry nuget package is giving me a lot of issues . We had .NET Framework 4.7.2 library that had a helper class that used that package and worked fine from a .NET Framework 4.7.2 unit test project. We recently converted the library to target .NET Standard 2.0, and now this class breaks when used with the following error:
ERROR: System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.Win32.Registry, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.
File name: 'Microsoft.Win32.Registry, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
at NetStandardRegistryLib.RegistryUtil..ctor(String remoteMachineName)
at NetStandardRegistryLib.Program.Main(String[] args) in C:\src\Microsoft.Win32.Registry-IssueRepro\FrameworkRegistry\RegistryEditor\Program.cs:line 21
When I look at output of the Console project, I don't see the Microsoft.Win32.Registry.dll in the output.
Using ILSpy and loading my .exe - it seems it would try to resolve the .dll from my dotnet core installation, which wouldn't work since it's a .NET Framework app.
To Reproduce
I've created a repo that reproduces for me on my Windows 2010 machine. You can find it here: https://github.com/TylerNielsen/Microsoft.Win32.Registry-IssueRepro
Clone the repo, then open and build the RegistryEditor project.
Using Powershell or your favorite editor - call the tool with three required arguments [remoteMachineName] [Environment variable name to set] [Value to set on the environment variable] **
** Note, this actually requires a remote machine you can reference by IP address. For some reason using 127.0.0.1 doesn't work for me, but I'm unsure why. The use case for this utility is for accessing remote machine environment variables.
Other Notes
When I create a .NET Framework Class Library to use for unit tests and reference the same .NET Standard Library - the Microsoft.Win32.Registry package is included and the utility runs just fine.
In your repo, if you look into both csproj files you'll see they are quite different. The NetStandardRegistryLib.csproj is the new format, the RegistryEditor.csproj is the old one.
Your problem is that old style projects do not resolve dependencies transitively. RegistryEditor will not copy dependencies of its own dependency NetStandardRegistryLib.
There are at least two ways to solve your problem:
Just add Microsoft.Win32.Registry Nuget package to RegistryEditor project explicitly. That'll make the Microsoft.Win32.Registry.dll to appear in the RegistryEditor build folder.
Convert the RegistryEditor.csproj to new format. It's not limited to netstandard builds, you can use it for builds targeting .Net Framework versions as well. And it does resolve dependencies transitively!
Here's a long guide for how to do the conversion in general https://natemcmaster.com/blog/2017/03/09/vs2015-to-vs2017-upgrade/
Since your project is quite simple, I've converted it for you. Just replace the content of RegistryEditor.csproj with the code below. It's still targeting net472.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net472</TargetFramework>
<AssemblyName>RegistryEditor</AssemblyName>
<RootNamespace>RegistryEditor</RootNamespace>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\NetStandardRegistryLib\NetStandardRegistryLib.csproj" />
</ItemGroup>
</Project>
Note that several properties that used to be in AssemblyInfo.cs file are provided by csproj file properties now, so you need to remove them from AssemblyInfo.cs to fix compilation errors:
[assembly: AssemblyTitle("RegistryEditor")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("RegistryEditor")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
Dealing with CVE-2018-8409, noted that our dotnet publish (.NET Core 2.1.403 ASPNET Core app) is publishing v4.0.0.1 of System.IO.Pipelines.dll in our output directory.
I added a nuget package reference to v4.5.3 of System.IO.Pipelines.
I see no reference to v4.0.0.1 in the build output, aside from this:
Unified primary reference "System.IO.Pipelines, Version=4.0.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51".
Using this version instead of original version "4.0.0.0" in "<home_dir>\.nuget\packages\microsoft.aspnetcore.connections.abstractions\2.1.3\lib\netstandard2.0\Microsoft.AspNetCore.Connections.Abstractions.dll" because AutoUnify is 'true'.
Using this version instead of original version "4.0.0.0" in "<home_dir>\.nuget\packages\microsoft.aspnetcore.http.connections\1.0.4\lib\netstandard2.0\Microsoft.AspNetCore.Http.Connections.dll" because AutoUnify is 'true'.
Using this version instead of original version "4.0.0.0" in "<home_dir>\.nuget\packages\microsoft.aspnetcore.server.kestrel.core\2.1.3\lib\netstandard2.0\Microsoft.AspNetCore.Server.Kestrel.Core.dll" because AutoUnify is 'true'.
Using this version instead of original version "4.0.0.0" in "<home_dir>\.nuget\packages\microsoft.aspnetcore.server.kestrel.transport.abstractions\2.1.3\lib\netstandard2.0\Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.dll" because AutoUnify is 'true'.
Using this version instead of original version "4.0.0.0" in "<home_dir>\.nuget\packages\microsoft.aspnetcore.server.kestrel.transport.sockets\2.1.3\lib\netstandard2.0\Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.dll" because AutoUnify is 'true'.
Using this version instead of original version "4.0.0.0" in "<home_dir>\.nuget\packages\microsoft.aspnetcore.signalr.core\1.0.4\lib\netstandard2.0\Microsoft.AspNetCore.SignalR.Core.dll" because AutoUnify is 'true'.
Resolved file path is "<home_dir>\.nuget\packages\system.io.pipelines\4.5.3\lib\netstandard2.0\System.IO.Pipelines.dll".
Reference found at search path location "{HintPathFromItem}".
This reference is not "CopyLocal" because at least one source item had "Private" set to "false" and no source items had "Private" set to "true".
The ImageRuntimeVersion for this reference is "v4.0.30319"
NOTE : <home_dir> is my user directory, it's not actually part of the output, fyi.
Yet when I check in VS2017, I clearly see that the nuget package says System.IO.Pipelines (4.5.3)
I'm expecting that System.IO.Pipelines 4.5.3 would be in the output, including any necessary assembly binding redirects.
Any ideas what I'm missing?
Thanks!
In an extremely annoying move, further analysis has revealed to me that nuget package 4.5.3, contains assembly version 4.0.0.1
Whyyyyyyy Microsoft, Whyyyyyyy
I have an assembly created in NetStandard2.0. It reads AppSettings using System.Configuration.ConfigurationManager. I have installed nuget package of System.Configuration.ConfigurationManager with version 4.4.X which is suitable for NetStandard2.0.
When I refer this assembly in console app (.Net Core) it is reading AppSettings properly, but when I refer this assembly in old .NetFramework(4.6.X) console app it is not working and throwing an exception.
Please see the code below.
Assembly 1: NetStandard 2.0
Nuget: System.Configuration.ConfigurationManager 4.4.0
using System.Configuration;
namespace Bootstrapper.Lib
{
public class Bootstrapper
{
public Bootstrapper()
{
}
public void LoadAppSettings()
{
string serachPattern=
ConfigurationManager.AppSettings["AssemblySearchPattern"];
}
}
}
Console App: NetFx 4.6.X
using System;
using Bootstrapper.Lib;
namespace Bootstrapper.Console
{
class Program
{
static void Main(string[] args)
{
new Bootstrapper().LoadAppSettings();
}
}
}
Exception After Run:
'Could not load file or assembly 'System.Configuration.ConfigurationManager,
Version=4.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' or one
of its dependencies. The system cannot find the file specified.'
It will work with Console App developed using .NetCore.
Please help!!!
As #kiran mentioned in a comment you can solve this by running:
Install-Package System.Configuration.ConfigurationManager
in NuGet Package Manager
It is not possible to create .NET Standard library which references System.Configuration.ConfigurationManager package and uses ConfigurationManager class. Once library adds reference to .NET Core specific package it ceases to be portable .NET Standard library since it is bound to framework specific package.
.NET Standard 2.0 does not contain System.Configuration.ConfigurationManager API. Therefore, the only way to use this API is to build one version of the library against .NET Core System.Configuration.ConfigurationManager package which can be used on .NET Core and have a second version of the library which is build against .NET FX System.Configuration assembly and can be used on .NET FX.
Had the same issue and after installing the same System.Configuration.ConfigurationManager package in the FX4.6 project resolved this issue.
Alternative solutions are the following:
1. Copy .Net Standard dependencies
Add below line to your .Net Standard csproj file (Assembly 1) as described here.
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
Then rebuild Console App and System.Configuration.ConfigurationManager.dll with other dependencies of Assembly 1 will be copied to bin directory of Console App.
In my case it copies the below list of dlls
Interesting thing is that when I use another solution and install System.Configuration.ConfigurationManager NuGet package to FX4.6 Console App directly, I have another set of dependencies in result:
Notice that System.Configuration.ConfigurationManager.dll as well as other dlls have different size. As I understand, in first case it was copied from %userprofile%\.nuget\packages\system.configuration.configurationmanager\5.0.0\lib\netstandard2.0, but in second case from %userprofile%\.nuget\packages\system.configuration.configurationmanager\5.0.0\lib\net461
Anyway, both solutions work, so I'm not sure which is more correct.
or
2. Use multi-targeting
In your .Net Standard csproj file (Assembly 1) set second target to net461 as described here with line
<TargetFrameworks>netstandard2.0;net461</TargetFrameworks>
Then on build two versions of library will be generated - in \bin\Release\net461 and in \bin\Release\netstandard2.0. If your Console App targets .Net Framework 4.6.1 or higher, it will automatically take correct version of Assembly 1 as dependency (the one from \net461).
The benefit of that approach is that net461 version of library doesn't require dependency from System.Configuration.ConfigurationManager.dll and can be distributed without it.