C# project, compiler complaining missing reference to log4net - c#

I am using Visual Studio 2017 to build a big C# project (200+ projects in the solution). When compiling one of the projects, I got many errors as shown below:
error CS0012: The type 'BufferingAppenderSkeleton' is defined in an assembly that is not referenced. You must add a reference to assembly 'log4net, Version=1.2.11.0, Culture=neutral, PublicKeyToken=1b44e1d426115821'.
The project in question, however, does reference to log4net 1.2.11. The only thing suspicious is the net40-full found in the package path of log4net: "C:\XXXX\Src\packages\log4net.1.2.11\lib\net40-full\log4net.dll"
in the package.config of the project, it contains this line:
<package id="log4net" version="1.2.11" targetFramework="net461" />
and in its app.config, it contains this line:
<dependentAssembly>
<assemblyIdentity name="log4net" publicKeyToken="1b44e1d426115821" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-1.2.11.0" newVersion="1.2.11.0"/>
</dependentAssembly>
I wonder if it's the mismatch of the .net version (4.0 vs. 4.61) that causes the compiling error?
C# is not my primary area of expertise, but my understanding is that nuget looks into those config files to download needed packages, in this case, log4net. Then how come did it download the 4.0 version rather than that of 4.6.1?

my understanding is that nuget looks into those config files to download needed packages, in this case, log4net.
NuGet's job is just to download packages and extract whatever's in them, at least in the restore scenario of a package.config project. The targetFramework attribute in the packages.config file is only written, never read by the nuget client. I have no idea what it's purpose or intention was. Anyway, I believe the value of targetFramework is just the .NET Framework your project was using when the package was installed.
Then how come did it download the 4.0 version rather than that of 4.6.1?
Background information, skip to the next paragraph if you really don't care. If you go to the package page on nuget.org, you'll see in the version history that 1.2.11 isn't shown. However, if you look at the URLs for other versions, you can guess the URL for version 1.2.11. Quick off-topic comment, Fabio M was close, but not quite correct in saying the package doesn't exist any more. "nuget.org does not support permanent deletion of packages. Doing so would break every project depending on the availability of the package, especially with build workflows that involve package restore.". On the package version page, there's a message saying "The owner has unlisted this package. This could mean that the package is deprecated or shouldn't be used anymore".
Back to my point, once you're at this URL, change the n to an f in nuget.org to see the package version on fuget.org. Next to frameworks you can see a list of frameworks the package supports. net40 is the highest version that the package supports.
So, the reason why NuGet "downloaded the 4.0 version" is because that's the closest version that the nuget package provides that is compatible with your project. .NET is generally considered to be forward compatible, so net45 binaries work on the net462 runtime, so it's generally ok to use net45 binaries when your project is using a newer version.
Finally, about the error you're getting, as I said in my first paragraph, in packages.config projects, nuget's job is just to download and extract the package. At install time it adds some information to the csproj so the compiler can try to find the dll. So, if you look at your csproj, you should find a reference to log4net.dll, and it will contain a hint path that the compiler uses. If that hint path is wrong, then you'll get the errors you see. This is most common when projects are moved in the directory structure, but don't re-install the package. For example if the repo structure was origignally "project\project.csproj" and it's changed to "src\project\project.csproj", then the hint path of "..\packages\log4net.1.2.11\lib\net45\log4net.dll" is wrong, because an additional "..\" needs to be added so the relative path to the packages folder is correct. There may be other reasons the hint path is wrong, but this is the most common reason.

Related

How to publish this C# Source Generator with dependencies on Nuget?

I've created a C# source generator, and would like to publish it to Nuget.
But I run into warnings/errors such as:
Some target frameworks declared in the dependencies group of the nuspec and the lib/ref folder do not have exact matches in the other location. Consult the list of actions below: - Add lib or ref assemblies for the netstandard2.0 target framework
An instance of analyzer Cosmogenesis.Generator.CosmosGenerator cannot be created from [..]\Cosmogenesis.Generator.dll : Could not load file or assembly 'netstandard, Version=2.1.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' or one of its dependencies. The system cannot find the file specified.. (or Version=2.0.0.0 depending on what I'm trying)
There are a few resources explaining how, but none seem to work in my exact scenario, which is:
Cosmogenesis.Core
.NET Standard 2.1
Not depended on by the generator, but the generated source code depends on it
Cosmogenesis.Generator (published on Nuget as just Cosmogenesis)
.NET Standard 2.0
This is the source generator
Ideally, I'd like to be able to just install Cosmogenesis from Nuget and it would automatically bring in Cosmogenesis.Core along with the generator.
Use functionality from NuGet packages <-- explains my scenario (except for differing .net standard requirements). ....And as a side question: Why does it have code to check if an assembly is referenced if it's explaining how to make it be automatically referenced?....
Anyway...
Here is Cosmogenesis on Github
Cosmogenesis.Core is published without any trouble.
Cosmogenesis.Generator is published using this .csproj as well
It works. However, the consumer needs to reference BOTH packages. I'd like them to only need to reference one package.
When I add <IncludeBuildOutput>false</IncludeBuildOutput> (as per tutorial above), on build I get this warning: Some target frameworks declared... [see above]. If I ignore it and publish it anyway, when I consume the package in a project and build it, the generator does not run and I get this warning: An instance of analyzer... [see above].
When I add <PackageReference Include="Cosmogenesis.Core" Version="0.0.1" /> (as per tutorial above), I get an error. The generator is .NET Standard 2.0 while the .Core package is 2.1. The error is: error NU1202: Package Cosmogenesis.Core 0.0.1 is not compatible with netstandard2.0 (.NETStandard,Version=v2.0). Package Cosmogenesis.Core 0.0.1 supports: netstandard2.1 (.NETStandard,Version=v2.1). Understandable.
When I set the generator project to 2.1 to fix the mismatch, no warnings appear while building, however the consumer again gets the An instance of analyzer... error. C# Source Generators - Write code that writes code - David Wengier says they have to be .net standard 2.0.
This is my first nuget package. And my first source generator. Can anyone advise?
EDIT: I'm 75% sure a solution to this roslyn github issue would solve my problem here.

Mix of .netstandard2.0 and .netframework47 DLLs in nuget package - .netstandard not available

First of all I don't know if what I'm doing is fundamentally the wrong idea, so the answer could be to just not do this, but here goes..
I have a package that I'm creating from a .nuspec file, in its "files" section it contains references to both .net standard and .net framework DLLs. It also has dependencies on both .netstandard20 and .netframework47.
The reason behind this being that the legacy libraries are written in framework, and the new ones are being written in standard.
We have a consuming project (actually, several), written in .netframework 4.7 that needs to address both sets of DLLs. I have changed the project to use PackageReference rather than packages.config, and
Visual Studio shows that the package is being referenced (rather than the individual namespaces) in the References section. When I build, the .netframework DLLs get copied into the bin folder, but not the .netstandard DLL.
I've created a scratch project to isolate the issue, and I'm seeing the same there as well. The project basically just refuses to acknowledge the standard one. If I add a using statement into a class with a type from the .netstandard DLL it just puts a red squiggly under it and tells me it doesn't exist in the namespace.
It's been suggested that I break the .netstandard DLLs out into their own NuGet package, is that the answer or am I missing something?
Here's some examples..
The .nuspec file:
<?xml version="1.0" encoding="utf-8"?>
<package >
<metadata minClientVersion="2.5">
<!-- other tags removed for brevity -->
<dependencies>
<group targetFramework=".NETStandard2.0"></group>
<group targetFramework=".NETFramework4.7">
<dependency id="NLog" version="3.1.0.0" />
</group>
</dependencies>
</metadata>
<files>
<file src="..\Src\MyProj1\bin\Release\netstandard2.0\NetStandardClass.dll" target="lib\netstandard2.0" />
<file src="..\Src\MyProj2\bin\Release\NetFrameworkClass1.dll" target="lib\net47" />
<file src="..\Src\MyProj3\bin\Release\NetFrameworkClass2.dll" target="lib\net47" />
</files>
</package>
The package is referenced as a package, not the individual types within it:
If I try to manually add a using statement referencing the NetStandardClass's namespace it's marked as an error
The package itself contains all 3 DLLs as expected:
Yet when I build the project and inspect the bin folder, the NetStandardClass DLL is not there:
It's been suggested that I break the .netstandard DLLs out into their own NuGet package, is that the answer or am I missing something?
Basically, yes, splitting the package is the answer. Another possibility is to move the netstandard assemblies into the net47 folder, or maybe the net47 assemblies into the netstandard2.0 folder, but either way has potential for problems. Although solution is to recompile all your assemblies so they all use the same target framework, but that also has its own issues.
If you had read the NuGet docs and came to the conclusion that what you're attempting should work, please point me to which docs lead you to believe that, so I can update the docs and try to remove the confusion.
The first thing to understand about why NuGet supports a package having multiple target framework folders is because a package might want to use new framework features where possible, but have support for users of the package using older frameworks. Therefore, the package author needs multiple versions of their assembly, depending on which one is compatible with their users project. So, the point is that NuGet needs to select assets from the package depending on which target framework moniker (TFM) the project uses. The way NuGet actually does asset selection is as follows:
NuGet looks are which TFM folders exist in the package, to get a list of TFMs that the package supports. Generially it looks for lib/<tfm>/ and ref/<tfm> folders, but contentFiles/<tfm> and build/<tfm> files might be relevant as well. Notice it doesn't look at any filenames. Which assemblies exist under lib/net47/*.dll or lib/netstanard2.0/*.dll are not yet considered.
Once it has this list of package TFMs, it looks at the project TFM, and it selects the "best" TFM. For SDK style projects that multi-target, it does this once per project TFM. "Best" TFM means same "family" (net* projects always choose net* assets, if available. only when no net* assemblies exist does netstandard compatible .NET Framework TFMs look for netstandard* assets).
Once a package TFM is selected for the project's TFM, then NuGet selects all the files like lib/<tfm>/*.dll, ref/<tfm>/*.dll, contentFiles/<tfm>/<lang>/*, build/<tfm>/<package_id>.<props|targets>, and so on.
So, you can see that if your package contains lib/net47/assembly1.dll and lib/netstandard2.0/assembly2.dll, NuGet will only ever select one of the two assemblies, never both, depending on if net47 or netstandard2.0 is more compatible with the project.
Although it might seem desirable for you if NuGet did TFM selection per TFM, rather than selecting TFM first and then selecting only the assemblies that exist in that folder, consider when a package adds an additional helper utility to "polyfill" old TFMs with features that the package uses in newer TFMs. This helper utility is not needed for newer TFMs, so it would be undesirable for NuGet to select it.
The NuGet team suggests creating one package per assembly, in which case this problem never would have occured, because NuGet would have done asset selection per package, and assuming each package was authored correctly, everything just selects selected correctly. If you insist on bundling all the assemblies in a single package, from my description above I hope you see you need to put all the assemblies in a single TFM folder, but since different assemblies were compiled against different TFMs, there's potential for problems, particularly if some developers are using older versions of Visual Studio that might not support .NET Standard. I very strongly recommend at the very least creating one package per TFM, or recompiling all the assemblies to use the same TFM.

Could not load file or assembly 'Newtonsoft.Json, Version=10.0.0.0

I do not understand the following problem I am facing.
I have 3 projects, A, B and C. All of them have a reference to Newtonsoft.Json, version 12.0.1
Project a has a reference to both projects B and C. Project B, has a references to Microsoft.IdentityModel.Tokens.Jwt
When I run project A, I get the following runtime error when trying to execute the function necessary for creating my token.
Message:
"The type initializer for 'System.IdentityModel.Tokens.Jwt.JsonExtensions' threw an exception."
Inner Exception:
"Could not load file or assembly 'Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed' or one of its dependencies. The system cannot find the file specified."
I have verified that all projects reference the same Newtonsoft.Json package with version 12.0.1.
I have also checked my project files, to make sure there is no reference to Newtonsoft.Json version 10.0.0.0
What am I missing?
Newtonsoft Json while useful is the source of many issues.
You will need to check all the NuGet packages referenced by every project in your solution to see what version of Newtonsoft Json they require. Some specify a minimal version, in which case you don't have an issue ( like > 10, anything higher than 10 will work ), others require a certain, fixed version ( = 10, must be 10, not less, not higher). This is up to the author of that particular NuGet package.
When you hit build, the dlls required by the referenced packages will be copied over, then the dlls required by any referenced projects will copied over and it is possible a certain version will be copied over and when you run your application, you get the error you have seen.
You can check this by looking in the bin folder of your build profile, right click the dll file and inspect its version to see what you have. Assembly redirection should help, when done in the right place, but there is an alternative solution, although it's not always possible.
If you can drop the Newtonsoft Json to the minimum version which satisfies all requirements then that is a good way to solve the problem. Chances are you don't need version 12, depending on what you are using from it and depending on what other packages require. You might be able to change all projects to reference the lower version without any side effects. If you can, you're golden, just make sure you don't upgrade by mistake. If not, you'll have to do the version redirecting like indicated in other answers.
The basic idea is to make sure, that in your solution, you only use one version of Newtonsoft. you can check this package at solution level, there is a consolidate option as well.
So, check all projects in the solution, make sure they all use one version of Newtonsoft and that version is the same across all of them.
Once you manage to get everything on one level make sure that:
you delete the Temporary ASp.Net folder contents, in Windows / Microsoft.Net, Framework23 or 64 depends which one you're using.
remove all dlls from all bin folders, a simple Cleanup may not be sufficient.
With all this done, providing you have one version everywhere, you should be able to run you project without issues
I think some of your project is referring version 10, while other is referring version 12 of newtonsoft.json.dll.
It seems the v12 DLL is getting copied to output directory. The project which refers v10 is throwing this error.
For all the strong named assemblies, the specific version of DLL is searched in the application directory or GAC. You can overwrite this default behavior by using below configuration file entry - which instructs .net framework to always look for v12 whenever any version from 0 to 12 is called.
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-12.0.1.0" newVersion="12.0.1.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
Hope this helps to resolve your issue.
I finally got this working. In order to do Assembly Redirect Binding in Azure Functions, it takes a little more effort than a normal .Net application.
I followed the following post:
https://codopia.wordpress.com/2017/07/21/how-to-fix-the-assembly-binding-redirect-problem-in-azure-functions/
Find out what project trying to load this library. Right click on project->Manage Nuget Packages->Find NewtonJson library in installed libs and click Uninstall, maybe this will help. Also like people provided before use could you assembly redirect.
Where you are using Microsoft.IdentityModel.Tokens.Jwt don't add it as a using to the page instead make a direct reference to it.

Binding Redirect being added to every app.config

I have 20 projects in a solution file. 1 of the projects is a standard library project that all the the projects reference.
About a year ago we added a new nuget package, we'll call it Package A Version 5.0.0.0. It had a bunch of files that it would transfer all over when we compiled but we eventually dealt with it. We added the package to our standard library project (the one the other 19 reference).
I am new to Nuget (so maybe I did something wrong) so I made a new package to serve as a helper for Package A. I had set everything up so that the helper has a dependency on Package A version 3.0.0.0 to 5.0.0.0 (So it works for others who have a lower version than us). Lets call this new package Package A helper
I install Package A helper and everything is working as it should. I go to do a pull request and every single app.config in our solution now has
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Package.A" publicKeyToken="8FC3CCAD86" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-5.0.0.0" newVersion="5.0.0.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
It will compile fine without it, but visual studio complains and gives a warning. What gives? My manager won't let me merge my code now because it adds too much noise into app.config and depends too much on Package A.
why did adding a nuget package that depended on Package A then have to have this new bindingRedirect when the main dependency was already met before we installed Package A Helper?
And why does it say 0.0.0.0-5.0.0.0 when I specified 3.0.0.0-5.0.0.0 in the nuget package and package.config
Update:
When I build Package A helper with references to Package A version 5.0.0.0 then all the bindingRedirects don't get auto-populated in every app.config but instead warnings are generated. I had originally built it with 3.0.0.0 because I figured it was best to build it with the lowest dependency. The problem still exists because visual studio is still warning and suggesting bindingRedirects are created.
No way to resolve conflict between "Package A, Version=5.0.0.0, Culture=neutral, PublicKeyToken=83hfhsd33" and "Package A, Version=3.0.0.0, Culture=neutral, PublicKeyToken=83hfhsd33". Choosing "Package A, Version=5.0.0.0, Culture=neutral, PublicKeyToken=83hfhsd33" arbitrarily.
Consider app.config remapping of assembly "Package A, Culture=neutral, PublicKeyToken=83hfhsd33" from Version "3.0.0.0" [] to Version "5.0.0.0" [path to Package A dll] to solve conflict and get rid of warning.
Is the solution just to change my nuget package dependency from 3.0.0.0 to 5.0.0.0 and just allow 5.0.0.0 and get rid of my allowedVersions="[3,6)" in me packages.config? I don't want to reduce the helpfulness and backwards compatiblity of my nuget package but at the same time I want no warnings or bindingRedirects required for my main solution.
Update 2: So setting Copy Local in the reference properties to False actually solved my issues, but I don't understand why.
I had originally built it with 3.0.0.0 because I figured it was best ...
That is where the problem started. Your solution now depends on two distinct versions of A.dll, one is going to overwrite the other. Which version of A.dll ends up getting copied into bin\Debug is random. Whatever project was built last.
This can not come to good end, the solution is doomed to fail to execute. If will either be the code in A-helper.dll, it will fail when version 5.0.0.0 ends up getting copied. Or it will be the code in whatever other project uses A.dll, it will fail when version 3.0.0.0 gets copied. End result is that the solution will always fail.
So you are seeing the build system doing something about it. It notices the discrepancy and elects one of the versions to win. It picks 5.0.0.0, that was the correct choice. And it also modifies app.config, adding the bindingRedirect so code that asks for the 3.0.0.0 version to be loaded will actually get 5.0.0.0. That could work if you made version 5 compatible enough with version 3. Or not, two increments in the major version number usually spells trouble. You'll find out when you test.
So setting Copy Local in the reference properties to False actually solved my issues
That did not solve an issue, you merely prevented the build system from assuming that it should solve this problem for you. Since it no longer had to copy the DLL, it guesses that you'll install the assemblies in the GAC so that both versions can co-exist. Maybe you did, it is not common and in general very unwise to do so on a dev machine. Very unlikely that your boss and team members will like this solution given the extra install step.
So there are two basic things you can do:
Let the build system sort this out. As it did, it solved the problem correctly and your solution will work. If version 5 is compatible enough with version 3 then the code in A-helper.dll will even execute correctly. If the boss doesn't like it then you'll of course have to scratch this and do:
Change the reference in the A-helper project to A version 5.0.0.0. Now there no longer is any incompatibility, the one-and-only A.dll is good for all the code. Given your requirement, this is the only solution your boss will like.

All system references missing Visual Studio 2013 NuGet Async

I have a solution/team project set up in visual studio 2013 and for some time have had a working NuGet Microsoft.Bcl Async Package installed for NET Framework 4.0. Today when opening the project all of the default .NET system library references cannot be found, They just have a warning symbol next to them. I have 49 warnings when building the project all saying 'The referenced component 'System.X' could not be found. Or 'The referenced component 'Microsoft.X' could not be found. Yet references to other projects in the solution remain intact.
If it is of any significance I have been using the built in version control system to keep backups of my code and access it from my other pc with the same configuration.
Looking at the other questions on stackoverflow with similar issues people seem to point towards NuGet as potentially causing the problem but without any solution that seems to work for me. I have tried the obvious solution of removing and re-adding the reference using both the file browser and the Framework tab but neither has worked so far.
I cannot currently compile the project as I get this warning, undoubtedly caused by the missing references in the first place.
Error 31 The "EnsureBindingRedirects" task could not be loaded from the assembly C:\Users...\Visual Studio 2013\Projects\AlgorithmToolsTFVC\AlgorithmToolsSuite\AlgorithmTools\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.Tasks.dll. Could not load file or assembly 'file:///C:\Users...\Visual Studio 2013\Projects\AlgorithmToolsTFVC\AlgorithmToolsSuite\AlgorithmTools\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.Tasks.dll' or one of its dependencies. The system cannot find the file specified. Confirm that the declaration is correct, that the assembly and all its dependencies are available, and that the task contains a public class that implements Microsoft.Build.Framework.ITask. AlgorithmTools
A possible solution: If you are seeing yellow triangles over most of your System references, edit your .csproj file (back it up just in case), scroll to the bottom of the file, and delete these lines...
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('$(SolutionDir)\.nuget\NuGet.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\.nuget\NuGet.targets'))" />
</Target>
Like many others, I've been using a centralized .packages folder outside of source control. This is done by having the following lines in your NuGet.Config file:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<config>
<add key="repositoryPath" value="..\..\..\.packages" />
</config>
<solution>
<add key="disableSourceControlIntegration" value="true" />
</solution>
</configuration>
One of the steps in achieving this, is to check your project file does not use the old NuGet.targets file anymore (the only file in your .nuget solution folder should be NuGet.Config).
When NuGet thinks it should check the NuGet.targets file, and it's not there, it will fail checks to basic references too (like System.Core, WindowsBase and PresentationCore).
Update: See this related topic/answer on how to completely do away with .nuget folders in your solution! It can be set at user-profile level in your AppData.
I was able to solve this issue by first running an update on all NuGet packages in the solution and then removing and re adding references to the libraries included or overridden by the package.
Just had the same problem.
The reason for me was that all the files inside the Nuget package, suddenly become 0 byte size. I mean DLLs, nupkg file etc.
I reinstalled the package and it worked for me.
I had exactly the same problem with my project on team foundation server. I had the error saying "EnsureBindingRedirects" task could not be loaded from the assembly C:\Users...\Visual Studio..." and many warnings saying "The referenced component 'Microsoft.X"
The solution was very easy. All I had to do was copy my entire project folder into another location and it worked.
Had a similar problem. After wasting 2.5 hours trying to find a solution, I fixed it simply by opening the project in VS 2013, enabling NuGet package restore and rebuilding. Fixed immediately and now it works in VS 2015 just fine.
Just had the same issue and solved it by executing the following command in package manager console:
Update-Package -Reinstall
If you want to do this for a specific project you can use:
Update-Package -ProjectName 'ProjectNameGoesHere' -Reinstall

Categories