Dependent packages not included in NuGet package or VSIX installer for the analyzer - roslyn-code-analysis

Using a template provided with Visual Studio 2022, I have created a Roslyn code analyzer. This is results in multiple VS projects - the analyzer assembly, the code fixes assembly, test assembly, and then projects to generate either NuGet package or VSIX package with the analyzer.
My analyzer assembly depends on some packages (to give an example, Microsoft.Extensions.FileProviders.Physical, but there are others as well).
My problem is that neither the NuGet package nor the VSIX package contains the dependent assemblies or a reference to the dependent package that would cause them to be resolved by Visual Studio. Consequently, the analyzer fails in runtime with "FileLoadException" when it comes to do something related to the missing dependent package.
It almost seems like that the analyzers can only be written in a "self-contained" way, without dependencies on other packages? I find it hard to believe, because that would be extremely limiting - so I guess I must be understanding something wrong.

Related

Visual Studio 2022 can't find nuget package

What am I doing wrong here?
I have a DLL in .net Standard 2.0, and a console application, also in .net standard 2.0. The DLL is going to eventually be a custom nuget package for internal use by my dev team.
I installed System.Text.Json version 6.0.0 and I get the following runtime error:
"Could not load file or assembly 'System.Text.Json, Version=6.0.0.0".
I can see the nuget package in the location that Visual Studio 2022 is looking in.
Any thoughts on how I debug this?
I tried to explicitly install each of the dependencies, but that did not work.
***EDIT: I just realized that I no longer get that FileNotFound Exception if I explicitly copy that package's DLL into the console app's execution directory, but then I get a new FileNotFound exception for one of its dependencies. When I explicitly copy that DLL, I get another FileNotFound exception for the next dependency, and so on. I just assumed that the dependent nuget packages would get encapsulated in the dll that's using them. Copying each of the dependent DLL's is not really an acceptable solution.
After some investigation, I thought my issue might be related to:
Dependent DLLs of a NuGet package not copied to output folder
or related to:
MSBuild doesn't copy references (DLL files) if using project dependencies in solution
but that was not the case.
The output of my console app project was a DLL, even though it was clearly set to "Console Application". I just assumed that this was a new runtime method for VS2022, but that's not it. My console application Target was set to ".Net Standard 2.0", which is intended for DLL's. Once I set the Target to ".Net 6.0", everything worked as expected, and all the DLL's and packages were copied over correctly.
My DLL, which is being turned into a Nuget package, was properly set to ".net Standard 2.0".

How to wrap a NUnit Engine Extension as a NuGet package?

I am working on a nunit engine extension which will be shipped as a nuget package.
Following the advises in How to implement NUnit's NUnit.Engine.ITestEventListener i was able to write the extension.
This solution is working as long as the project which contains the extension (the .cs file as well as the .addins file) is being imported to the target project which will perform the nunit tests.
As soon as I create a nuget package (following Quickstart: Create and publish a NuGet package using Visual Studio (.NET Standard, Windows only)) from the extension project and install this package to a test project, the extension doesn't work anymore.
I assume there is a problem with providing the .addins file within the nuget package so that the nunit engine in the target project can find the extension.
I already tried to ship the .addins file within the nuget package by adding the following lines to the .csproj file of the extension project.
<ItemGroup>
<Content Include="file.addins">
<Pack>true</Pack>
</Content>
</ItemGroup>
If I add the .addins file to the target project by hand, the engine extension starts working.
How can a nunit engine extension be shipped as a nuget package without any adjustments by hand?
Im using NUnit(3.13.2).
Im quite new to nunit, nuget and writing questions on stack overflow. So if I'm missing something obvious here, I'm sorry.
This is one of those areas where I wish things were less complicated, unfortunately. Since extensions are found through a relative path from the NUnit engine to the package content, it depends on where both the engine and runner are located and where the package is located on your machine.
Here are some initial guidelines...
How to structure the package itself... your extension assembly itself should be in the tools directory. If there are other assemblies with it, which it references, it's best to also include a .addins file in the same directory, which lists that assembly on a single line. That way, the NUnit engine will save time by only examining the extension assembly.
A NuGet extension package will automatically be found by the engine if the runner has been installed as a nuget package as well. This works no matter how the packages are installed on your machine, i.e. using packages.config or in a nuget cache, provided both packages were installed the same way. (That proviso is a real gotcha and it may be that a future version of the engine needs to actually understand nuget.) See the addins file provided with the the NUnit 3 console runner as an example of why this works.
The same thing is true if both the runner and the extension are installed as chocolatey packages, because they are both in the chocolatey cache. If you do provide one (which I recomend) it has to be a "native" package - one that includes the actual binaries. A chocolatey package that merely invokes the nuget package will not work. See the source for any of the NUnit-provided extensions for an example of how this this is done.
If the executing copy of the engine (usually in the same directory as the runner) is anywhere else, there is no automatic way for the extension to be found. This includes the case where you are building a runner yourself and want the extension to be available while you are developing. In that case, you need to fully understand how the engine finds extensions (see the docs) and manually create an addins file (next to any that was distributed with the engine) containing the proper relative path.
This is especially complicated if you are developing an extension for general release. Then you have to deal with various runners installed in different ways by different people. OTOH, if you are doing this for internal use in your company, you may only need to deal with one of them. If you add more specifics about your goal to the question, I'll edit this with some more specific suggestions.

Reducing dependencies for a .NET Standard class library?

I have converted some of my class libraries to .NET Standard with Visual Studio 2017.
This was easy, add a .NET Standard class library project in place of the original project and add all the files in there. The .csproj file even looks like a nuspec file now with package information and such. Inside the project options there was a checkbox for "Generate NuGet package on build", which I checked. Easy peasy.
However, .NET Framework consumers of my class library now gets a ton of dependencies, I counted at least 20 other nuget packages that were added, most of which was completely unecessary for my library. In other words, was "easy peasy too easy?"
Is this just a byproduct of me using .NET Standard as the only build output and I should add back a .NET Framework library as well?
Packages such as the following will be added to a project that consumes my library, even though they are completely unnecessary:
System.Security.Cryptography.*
System.Xml.*
System.IO.*
etc. there's plenty of packages being added. My library does "glorified" array analysis and doesn't require much at all.
The Visual Studio project is configured to target .NET Standard 1.0 and the only reference visible is the "NETStandardLibrary" so it's not like I added all of those myself.
I've inspected the package and it doesn't seem to list all of those either.
Can I add only the packages I need and still target .NET Standard 1.0?
My class library is open source here: https://github.com/lassevk/DiffLib
The nuget package is here: http://www.nuget.org/packages/difflib/2017.4.24.2347
This is quite a complex situation at the moment:
Can I add only the packages I need and still target .NET Standard 1.0?
Yes you can do it, but this is no longer recommended. In essence, .NET Standard is a specification that is made up of the packages referencing it. The supported way is to reference NETStandard.Library since it guarantees to bring you all needed compilation references and logic that you need in order to build correctly.
Beginning with the upcoming netstandard2.0, NETStandard.Library will be a flat package without dependencies and the individual packages will be removed from the dependency tree if your project or any other project references them. Also, NETStandard.Library will not be published as a dependency - so if you build a netstandard2.0 library, the resulting NuGet package will have no dependencies. (NETStandard.Library.NETFramework is required to be installed when using it in .net framework projects - NuGet is supposed to do this automatically).
That being said, if you really want to do it, you can set
<DisableImplicitFrameworkReferences>true</DisableImplicitFrameworkReferences>
in the csproj file and then add items like <PackageReference Include="System.[Something]" Version="4.3.0" /> for everything you need.

Get current version of package outside of Visual Studio

We are migrating over to using packages and NuGet for managing our dependencies on 3rd party components. This works well when referencing packages from within Visual Studio or building on the build server via msbuild.
However there are a number of files that we would like to access in our build scripts and installers. Previously these would be in source control with a well known path, now as the version of the package that we are consuming changes so the path to the package and hence the files is changing.
Is there a simple way I can get the path to a given package? The best solution I currently have is to search for all packages.config files and extract the package version from them.
Examples of the files that we need to access are
The NUnit console executable from the NUnit.Runners package for running unit tests.
License files from various packages that we redistribute with our installer.
Using the packages.config file is a pretty good solution. NuGet itself uses two approaches:
Reading the package information from the packages.config and using that to resolve to the packages path.
Enumerating all the directories in the packages directory.
You could use NuGet.Core to do either of the above if you do not want to write the code yourself. The classes that can be used are the DefaultPackagePathResolver, the PackageReferenceFile and LocalPackageRepository or SharedPackageRepository.
One problem with the second approach is that sometimes NuGet may occasionally leave behind NuGet packages that are not necessarily referenced by a project. In that case looking at the package directories may give you the incorrect information.
The only other approach I can think of might be to read the project files looking for the assembly references. Although that would not work for a solution level package such as NUnit.Runners.

Using nuget to update project files outside of Package Manager Console

Nuget.exe only supports managing packages at a file system/configuration level. The powershell commands command the magic that update the .proj files.
With that said, i need the ability to update a csproj file with the latest version of a NuGet package outside of visual studio (automated).
Basically, how do I use Install-Package (or any of the other methods) inside of an external powershell script of my own?
UPDATE:
I would like to ability to add project references outside of VS for the following reason.
My company has a lot of shared libraries that depend on each other in some cases. I am using TFS Nugetter to build and publish nuget packages from TFS. I want to ensure that the developers can't queue a build (package) unless the project can build and run on all the newer versions. This ensures that all the newer versions of the libraries work with all the newer versions of its dependencies. If the build fails, then you need to update your nuget reference in VS and fix the compiler errors/unit tests.
I have been looking at the NuGet source and I think I found an easy way to reuse NuGet source to modify proj files outside of VS (kinda).
System.Type t = System.Type.GetTypeFromProgID("VisualStudio.DTE.10.0", true);
var dte = (DTE)System.Activator.CreateInstance(t, true);
dte.Solution.Open(
#"C:\Users\paul.knopf\Documents\Visual Studio 2010\Projects\SLNMemory\SLNMemory.sln");
Basically, open an in-memory version of visual studio, run the nuget commands, then save.
In a build step, after GetWorkspace, I would like to run this in-memory vs to update all nuget references to the latest version.
What do you think? It would definitely be slow, but we would be on the same code base and have all the functionality we need.
Automating Visual Studio as you describe is certainly a possibility.
Another way I looked at was using SharpDevelop to install NuGet packages outside of Visual Studio. The NuGet PowerShell cmdlets were modified to accept a solution and you could automate installation, including the use of PowerShell scripts in a NuGet package, from the command line. The code has not been updated so it targets an old version of NuGet but could be updated. Again this is similar to your solution and fairly heavyweight solution.