How do I override a nuget package circular reference - c#

I have 2 solutions.
Main
Which builds an assembly: Main.DomainTypes.dll (this will get packaged as a nuget package)
External
Which builds an assembly: External.EventTypes.dll (this is also packaged as nuget package)
External.EventTypes.dll references Main.DomainTypes.dll via it's nuget package.
Now, some code has been added to Main, that references External.EventTypes (which therefore also references Main.DomainTypes).
When I run Main, it throws a FileNotFound exception, because it is trying to load the version of DomainTypes referenced by External.EventTypes, instead of the version it has just built.
I'm guessing that Main tries to load the highest version number referenced, which is the version in the nuget, not the version it has just built, except the version on disk IS the one just built, not the one referenced.
E.g., the nuget version of Main.DomainTypes referenced by External.EventTypes is 1.0.123, but the version of Main.DomainTypes just built doesn't yet have a package number, so defaults to 1.0.0
How can I get Main to load the local version, and not the nuget version?
I realise I could remove the circular reference by (re)defining the DomainTypes in external, but I'd rather not.

Related

could not load file or assembly exception NET 5/6 of NuGet package for NET Standard

I'm at the end of my rope trying to figure out why my working DLL cannot load a NuGet package that it could always load before (like for a whole year). My system has 70 NET 6 projects and half a dozen of them use the same NuGet package to read XML files. Recently (a few months ago) I upgraded everything to NET 6, and even after that upgrade, everything worked fine.
But now, one of my C# class libraries generates an exception in a constructor because it can't find the NuGet package that sits right beside it in the filesystem app folder where everything is loaded from. The error message was:
.ctor Could not load file or assembly xxx blah blah. The system could not find the file specified.
For what it is worth, here is a trace of the build options in the batch file that I have been using for months.
Deleting hscore\hscore\bin Deleting hscore\hscore\obj Deleting
hscore\hscore\packages "C:\Program Files\Microsoft Visual
Studio\2022\Community\MSBuild\Current\Bin\msbuild.exe" -nologo -m
-V:minimal -t:clean;restore;publish /p:Platform=AnyCPU /p:PlatformTarget=AnyCPU /p:Configuration=Debug
/p:TargetFramework=net6.0-windows7.0 /p:RuntimeIdentifier=win-x64
/p:SelfContained=false /p:PublishProtcol=FileSystem
/p:DeleteExistingFiles=true /p:PublishDir=c:\dev\holding\core.plt
-nowarn:MSB3305 c:\dev\products\hscore\hscore\hscore.csproj
Determining projects to restore... Restored
c:\dev\products\hscore\hscore\hscore.csproj (in 874 ms).
hscore -> c:\dev\products\hscore\hscore\bin\Debug\net6.0-windows7.0\win-x64\hscore.dll
hscore -> c:\dev\holding\core.plt\
I have done the following to debug it, without success:
deleted the bin/obj folders of the failing class library
checked the target framework of all projects (= net6.0-windows7.0)
checked the runtime identifier of all projects (= win-x64)
checked the build configuration (Debug, AnyCPU)
removed and re-added the NuGet package (with a specific version)
the Nuget package depends on NET Standard, compatible with NET 6
and I use the same version in other NET 6 programs that are working fine
restored and rebuilt the DLL
published it to the destination folder where it is run from
checked that the expected Nuget package is there (it was)
and yet it still fails to find the Nuget package
I tried to trace DLL loads of the process with the SysInternals Process Monitor, but I am not good enough to do that (if it is even possible). I can filter events to see the parent app process load, but the failing DLL is called by the parent process and I don't know how to see the search paths it is using to find the Nuget package.
I want to believe that the problem is a version mismatch between NET 5 and NET 6 and the version of the Nuget package sitting in the folder, because I once had a problem like that. For example, if I had a NET Framework version of the Nuget package, it would not be "found" by a NET 5 DLL that wanted to load it. (I am NOT saying that is my problem, because I have no NET Framework projects anymore.)
The most recent thing I have been working on is the build system and options. I can build the whole system with batch files or with parallel builds (when the system is working). I use the same msbuild options in both cases, and the batch method has been reliable and shows no build errors, no publish errors, all the correct build options, and no warnings or errors whatsoever.
The Nuget package pulls in 10 or 20 dependencies, but that is all automatic, and the package works with other console programs and apps that are working fine. So, I don't think there is anything wrong with Nuget package. All the working apps use the same Nuget package from the same runtime folder. I don't know why this one DLL is having a problem. AND I have not changed anything in the failing DLL class library for months (and it has been working fine).
Does anyone have suggestions on what else I might try to debug the problem and get the system working again? Thank you.
UPDATE - New version and build, but still a runtime failure.
Just to be sure, I upgraded the Nuget package that could not be found to the latest version and replaced all references in my 70 projects to the new version. Then I rebuilt the system (no warnings, no errors). But that did not make a difference. Now the new version cannot be found.
All unit tests of the code in question work flawlessly in VStudio, presumably because VS loads the Nuget package properly. I am mystified and would appreciate thoughts on how to proceed. Thank you.
UPDATE 2 - installed 'dotnet-trace' and traced DLL loads
I found a page that described how to dotnet tool install --global dotnet-trace and then captured a trace of my app trying to find the elusive Nuget package that is sitting right beside the requesting DLL. Although I could my app loading various app DLLs (and tons of system DLLs) with found pathnames, the trace showed nothing useful about the Nuget package.
The trace entries show the system searching in stages FindInLoadContext, then ApplicationAssemblies, then AppDomainAssemblyResolveEvent. After that, the system throws an exception because it can't find the Nuget package.
I would have thought the system FindInLoadContext would find it in the same folder as the executing and requesting assemblies, but it seems not so.
Ideas? I'm lost. And everything used to work fine.
UPDATE 3 - A small console app calls the DLL and it finds the Nuget package
The problem scenario in this question is: WindowsFormsApp -> loads MyCore.dll and calls new MyCore.MyObject(), which in the constructor tries to read some XML files using MyUtils.dll, which tries to reference the mystery Nuget package for reading XML files. MyUtils.dll cannot find the package, no matter what I do.
I wrote a small console program to load MyUtils.dll and called the exact same MyUtils.ReadMyXmlFiles API to read the files. The console app (actually, the system assembly loader) correctly found the Nuget package and read the XML files properly. This all occurred in the same folder that contains the Forms app and the Nuget package.
The only difference now is that the WindowsForms app calls an intermediate DLL that calls a constructor that references MyUtils.dll.
Could the intermediate DLL + constructor call be changing the Assembly Load Context (FindInLoadContext search rules) for the Nuget package load operation? Very strange.
The overall problem was that my Windows Forms app failed during boot (in the Form_Load event) because a Nuget package could not be found to read some XML configuration files.
Four assemblies were involved in the problem. Assembly1 (the app) called Assembly2 (.. new Assembly2Object()), whose constructor called an Assembly3 method (utilities.ReadXMLFile) which called Assembly4 (NugetPackage.XMLReader).
You can see that only Assembly4 references the Nugetpackage which could not be found. Normally, there should be no reason for Assemblies 1 or 2 to know about the existence of the NugetXmlReader used by Assembly3. But, the exceptions and assembly load traces of dotnet-trace and procmon clearly showed that Assembly3 (utilities.ReadXmlFile) could not find the NugetPackage at runtime, even though the right package was in the folder beside the executing assemblies (1->3).
The "solution" for my case was to add a Nuget package dependency to
Assembly1 (the WinFormsApp). As soon as I did that, Assembly3 (utilities.ReadXmlFile) could find Assembly4 (Nugetpackage).
My working theory is that during a WinForms boot sequence (including the Form_Shown event), the AssemblyLoadContext from Assembly1 is used to look up all assemblies in any call chain (like Assembly2 calling Assembly3 calling NugetPackage4).
Because the load context of Assembly1 has no reference to NugetPackage, and because the .deps.json file for Assembly1 is present (the doc says it is used to form the load context), Assembly3 - using the assembly load context for Assembly1 - could not find the NugetPackage.
When I added a dependency to Assembly4 (Nugetpackage) to Assembly1, then the assembly load context from Assembly1 was used by the System AssemblyLoader FindInLoadContext phase to search for (and find) the NugetPackage4 wanted by (the referencing assembly) Assembly3.
I used to think that each assembly in a calling chain would have its own assembly load context used by AssemblyLoad/FindInLoadContext. But I think that no longer. At least for my case of a Windows Forms app booting up, the assembly load context from the top-level app is being used to look up Nuget packages far down the calling chain.
It's worth repeating that my little test console apps always found the Nuget package without adding the package as a dependency to the top-level console program. I wrote console programs to test the calling chain from the bottom up: Test1) console calls Nuget directly - found; Test2) console (w/o Nuget dependency) calls Assembly3 - Nuget found; (Test3) console (w/o Nuget dependency) calls Assembly2 - Nuget found.
Then I wrote a skeleton WindowsFormsTestApp to call Assembly2 (just like the console program did) - Nuget NOT found. When I added a Nuget dependency to the WindowsFormsTestApp - Nuget was found by Assembly3.
The final step was to add a Nuget package dependency to the WinFormsApp that started this whole mess. Presto! Assembly3 found the Nuget package immediately.
My (unproven) belief is that somewhere along the line of upgrades from NET 5 - NET 6 (several SDK versions of each one), the assembly load context rules changed somehow. I could be wrong, but I lean toward this belief because my code from App->Assembly2->Assembly3->Nuget did not change during several months of successful operation. And just a couple of weeks ago after another NET 6 SDK upgrade, things broke.
Hopefully, this record might help someone someday. It seems completely unintuitive to me to add a Nuget package dependency to the top-level Forms app to help Assembly3 find a Nuget package sitting in the same folder as all the other assemblies.
After all this, I am coming around to the idea that the top-level app must/should include dependencies on anything the app ever calls, including packages used by dependent assemblies. (Although I am still puzzled as to why the code worked for months before without the Nuget package dependency.)

Conflicts with Nuget Package References

I have observed a strange behaviour of NuGet packages where the same version of NuGet packages (under different projects of a solution) refers different versions of dependent dlls.
Please see the images below:
Microsoft.Extensions.Caching.Abstractions Version 3.1.3
Same assembly , different version
Same assembly , different version
This is my nuget folder for Microsoft.Extensions.Caching.Abstractions:
Nuget folder for Microsoft.Extensions.Caching.Abstractions
But the logs shows that version 3.1.18 has been loaded, which is never used in any of the package references used in the solution. Am I missing something here?
`AppDomain: AssemblyLoad: Microsoft.Extensions.Caching.Abstractions, Version=3.1.18.0,
Culture=neutral, PublicKeyToken=adb9793829ddae60`
I have tried changing the Verbosity (Tools--> Options--> Projects and Solutions--> Build and Run) to "Diagnostics" and the build output showed the following conflict:
`Encountered conflict between 'Platform:Microsoft.Extensions.Caching.Abstractions.dll' and 'CopyLocal:C:\Users\91998\.nuget\packages\microsoft.extensions.caching.abstractions\3.1.3\lib\netcoreapp3.1\Microsoft.Extensions.Caching.Abstractions.dll'. Choosing 'CopyLocal:C:\Users\91998\.nuget\packages\microsoft.extensions.caching.abstractions\3.1.3\lib\netcoreapp3.1\Microsoft.Extensions.Caching.Abstractions.dll' because AssemblyVersion '3.1.3.0' is greater than '3.1.0.0'`
Please guide how to correct this so that there won’t be any conflicts between versions of the same assembly within the solution and the same assembly reference will be used in all the projects.

How to add additional dll to Roslyn analyzer NuGet package?

In short: I referenced additional dll in my code-analyzer. All good with unit-tests & while I debugged analyzer by F5. But when this analyzer was installed as NuGet package to real project, it can't find that additional dll & crashes.
#Optional reading - detailed version of question:
I've wrote my code-analyzer (say MyAnalyzer). It finds some types forbidden to use in client code. And its codeFix replaces these types by allowed replacement-types from my custom dll (say myCustom.dll). I've added this dll as dependency to MyAnalyzer.CodeFixes project & to MyAnalyzer.Test unit tests project of analyzer solution.
And it works fine when started by F5 (at special opened VisualStudio instance) & successfully passes all unit tests.
But when I:
built NuGet package of analyzer (by building MyAnalyzer.Package - a special project from VS template to produce analyzer NuGet packege)
then coppied it to NuGet local feed (local path registered at NuGet manager as packages source)
& then install this NuGet package from that local feed to real project by NuGet manager,
diagnostics rise fine, but when I try use codefix, which should replace some type by one from that myCustom.dll, my analyzer can't find myCustom.dll & throws an exception:
System.IO.FileNotFoundException : Could not load file or assembly 'myCustom, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
I probably add reference to my dll at wrong way (not working with analyzers)? Or may be (its only my assumption) any dependency of NuGet package should be NuGet package too?
#Additional info (may be it matters):
Build output looks Ok: folder with build output contains that my referenced dll.
I copied it as is to NuGet local feed folder.
But cache folder of installed package, which appears after installing package, doesn't contain that myCustom.dll. It contains (except for a few small files) only:
C:\Users\user1\.nuget\packages\myanalyzer\0.0.1\MyAnalyzer.0.0.1.nupkg
& 2 dlls:
C:\Users\user1\.nuget\packages\myanalyzer\0.0.1\analyzers\dotnet\cs\MyAnalyzer.dll
C:\Users\user1\.nuget\packages\myanalyzer\0.0.1\analyzers\dotnet\cs\MyAnalyzer.CodeFixes.dll
And when I try to manually put my dll there - to package cahe folder, analyzer still throws exception.
And when I try to manually put my dll there - to package cahe folder,
analyzer still throws exception.
That is not a right way. The issue describes that you have some wrong old version of the nuget under the global cache. Since you do not change the new release version to another, the old wrong nuget package is the same as the new release one, nuget package manager always install the version under the global cache first and if it does not find the same version of the nuget package by nuget package manager UI, it will then download the specific, different version from the nuget package feed into global cache C:\Users\xxx\.nuget\packages\, and then install it into your project.
You should try the following steps to make a careful check:
1) check your new packed nuget package myanalyzer under the local feed. And you can use 7zip tool to unpack myanalyzer.0.0.1.nupkg.
Check whether the myCustom.dll is under the folder myanalyzer.0.0.1\analyzers\dotnet\cs\.
Also, I found the error is
Could not load file or assembly 'MyCustomDll, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies.
I am curious why the dll is not right. And the error is that you have used MyCustomDll.dll rather than MyCustom.dll. You should check your Analyzers file and make sure that use the right named file.
Then, repack the new nuget project, ensure the new release nuget package is right.
2) delete the cache folder under C:\Users\xxx\.nuget\packages\myanalyzer.
If you use packages.config nuget management format, and you should also delete the folder under your solution folder <solution_folder>\packages\myanalyzer.0.0.1.
3) after that, reinstall the right version under package manager UI.
Update
Sorry for that I ignored the pack steps of your analyzer nuget project.
Actually, if the dlls are referenced by your current nuget project, the pack button has no duty to pack these dlls into the nupkg file automatically.
You have to pack it manually, no matter how you did, you have to modify the csproj file.
Solution
Use your target or another is to add these under myanalyzer.package.csproj file:
<ItemGroup>
<None Include ="$(TargetDir)mycustom.dll" pack="true" PackagePath="analyzers/dotnet/cs"></None>
</ItemGroup>
Then, repack the project, clean the nuget caches, then install the new one.
I wonder, why all dlls are present twice at installed NuGet package:
as separate files at packages\myanalyzer\0.0.1\analyzers\dotnet\cs &
as part of archive in .nupkg file. Or all content of installed package
folder, except .nupkg file, is just unpacked .nupkg?
The nupkg is the file is the original version of your nuget package. It is generated by your pack nuget project. And the folder which contains the nupkg is a local nuget feed.
The folder is like nuget.org source. And this folder which contains it is the nuget package source(nuget download nuget files from this path and then download the nupkg and unpack it under C:\Users\xxx\.nuget\packages)
Besides, the C:\Users\xxx\.nuget\packages is the global nuget cache folder.
So it restores the download nuget packages from the local feed, and if you installed the old same version of the myanalyzer nuget package before, it will always install the old same version like 1.0.0 from the cache folder no matter you have packed a new release same 1.0.0 version. Because the version is the same, so VS IDE will judge that there is already has a same nuget package under the cache folder, it always install the old one rather than the new one.
So that is why I recommended that you should delete all cache files under that folder. Avoid VS installing older cache packages all the time. Or you should set a new version for the updated nuget package like 2.0.0.
This is the explanation and the difference between these two Folders.
One is the original local nuget package feed. Another is the storage path and unpacking path of the package downloaded from the local nuget package feed, and it will record the previously downloaded packages. You need to pay attention to this.

Dependency problems after update nuget packages of a VISX project

I'm creating a VISX project. It runs normally, but after I update all it's nuget packages, it start to show errors when I try to run it in the Visual Studio Experimental Instance.
I tried to revert the packages, but it seems that some packages versions are no longer available for download.
The main reason is that the VISX can't load the Microsoft.VisualStudio.Threading assembly after the dependecies are updated.
I tried adding the assembly to the package's Assets too. The VISX can load it now, but can't find the following method in the AsyncPackage class, like it would be loading the wrong assembly version.
JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
There's also the same error (assembly not found) for the Newtonsoft.Json dependency.
Can someone help me with this?
I zipped everything and upload in my onedrive: https://1drv.ms/u/s!AmhLdtS8gKjrl71Vmnp85m4ZPUILgw
I included all packages, since there's a chance that who download the project could not execute it because the packages could not be downloaded from nuget.org.
To simulate the error, just update the dependencies.
Update 1
As suggested, I was able to redo the entire project using "package reference" to target dependencies.
The visx builds and work, but the problem with the dependency for Newtonsoft.Json still occurs.
Also, I tried adding another dependency from a nuget package that I created, and the same error occurs too.
I wrote a piece of code that uses JsonConvert just to make use of the dependency.
When I execute the "TestCommand" from VS Experimental instance, them the error popups.
Link for the second project in my onedrive:
https://1drv.ms/u/s!AmhLdtS8gKjrl71ZCd1WIYNDTZaSCw

.NET Core - MSB3277: Found conflicts between different versions

I am having difficulty getting rid of the build warning:
warning MSB3277: Found conflicts between different versions of the same dependent assembly that could not be resolved
specifically in .NET core projects.
In a full .NET framework project I would add some binding redirects so I googled around that issue and found this answer suggesting adding the following to the .csproj file:
<PropertyGroup>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
</PropertyGroup>
I have done this but to no avail - I still get the build warnings. Anything else I can do?
I had a look at your project and the problem seems to be a conflict with the versions that Rssdp was built against and the assembly version that the referenced System.Net.Http version (4.3.0) provides as compile-time reference.
This can be fixed by updating System.Net.Http to 4.3.2.
<PackageReference Include="System.Net.Http" Version="4.3.2"/>
Run Update-Package via Package Manager Console, this will fix MSB3277, what it does it reinstall all the packages with highest version possible.
More info on official docs https://learn.microsoft.com/en-us/nuget/consume-packages/reinstalling-and-updating-packages
I had the same issue. Got several warnings on one of the projects. I updated all packages from the solution level and warnings went away.
I used the Visual Studios for Mac to update the package.
Right click the solution, then Update Nuget Packages.
Does any of you dependencies use <PrivateAssets>?
If project A has a private reference, and both the private reference and another reference requires some package X, but the private one requires a higher version of package X, then the assembly for project A will also require the higher version of package X.
However you end up with a situation where any other project, e.g. project B, that references project A will only see the lower version of package X as a dependency - hence select the lower version of the assembly of package X to be copied to the output directory. The good news is that this DLL-HELL is detected at build time, where it sees that assembly projectA.dll requires a different projectX.dll than the one already designated as primary, and thus it logs some very unhelpful output about packageX being required by itself, which makes no sense... and gives up the build.

Categories

Resources