Create nuget package that references referenced .dlls without using .nuspec - visual-studio

Problem: Top level project references MyLibrary nuget which references several vendor.dll files. Vendor.dll files should be able to be referenced by top level project when MyLibrary nuget package is added to top level project but they are not.
When I run the top level project I receive this error:
FileNotFoundException: Could not load file or assembly 'Vendor.A, Culture=neutral, PublicKeyToken=b88d1754d700e49a'. The system cannot find the file specified.
Vendor .dll files are not copied to bin folder.
I hope to find a resolution to this problem that does not require me to create a .nuspec file.
Structure of generated MyLibrary nuget package (observed with Nuget package explorer):
lib
net5.0-windows
Vendor.a.dll
Vendor.b.dll
net5.0-windows7.0
MyLibrary.dll
I do not understand where net5.0-windows7.0 comes from. It does not exist in TFM list referenced below. Also, if net5.0-windows7.0 is for some reason necessary, why does MyLibrary.dll exist there but not the .dlls it depends on?
Looking at the package from within Visual Studio 2019 it appears as follows (vendor dlls do not appear):
Packages
MyLibrary
Compile Time Assemblies
MyLibrary.dll
MyLibrary.csproj:
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<TargetFramework>net5.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
<PropertyGroup>
<AssemblyVersion>1.0.0.1</AssemblyVersion>
<FileVersion>1.0.0.1</FileVersion>
<Version>1.0.0.3</Version>
</PropertyGroup>
<ItemGroup>
<Content Include="$(OutputPath)\Vendor.*.dll">
<Pack>true</Pack>
<PackagePath>lib\$(TargetFramework)</PackagePath>
</Content>
</ItemGroup>
<ItemGroup>
<Reference Include="Vendor.a">
<HintPath>VendorLib\Vendor.a.dll</HintPath>
</Reference>
<Reference Include="Vendor.b">
<HintPath>VendorLib\Vendor.b.dll</HintPath>
</Reference>
</ItemGroup>
TopLevel.csproj
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net5.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MyLibrary" Version="1.0.0.3" />
</ItemGroup>
Target Framework Monikers
Similar question
Similar question requiring nuspec
Similar question requiring nuspec
Possibly related issue

I also found an issue about this strange behavior and still did not know where the net5.0-windows7.0 from. Since the issue is still open and the Team does not know it is normal or a strange issue, as my opinion, net5.0-windows7.0 is the special version for wpf project's frameowork of nuget, so you should pack your dlls into such folder of nupkg.
Although this is not the best function, but is a workaround now. You can keep tracking the issue to get the explanation from the Product Team.
Or try my suggestions:
function one
1) change the targetframwork of your nuget project to
<TargetFramework>net5.0-windows7.0</TargetFramework>
As the Team said, net5.0-windows is the same as net5.0-windows7.0. However, they treat them differently in terms of packaging into nuget.
function two
2) still use <TargetFramework>net5.0-windows</TargetFramework>.
change this to:
<ItemGroup>
<Content Include="$(OutputPath)\Vendor.*.dll">
<Pack>true</Pack>
<PackagePath>lib\$(TargetFramework)7.0</PackagePath>
</Content>
</ItemGroup>
Besides, when you finish packing nuget project, please delete nuget caches first or delete all files under C:\Users\xxx\.nuget\packages, then install the new release version of the nuget package into the main project.
vendor is my custom nuget project name.

Related

Package third party dll in context of multi target framework project, .Net Framework & .Net Core

I'm using next configuration within csproj :
<ItemGroup Condition="$(TargetFramework.StartsWith('net4'))">
<Reference Include="amqmdnet">
<HintPath>..\bin\amqmdnet.dll</HintPath>
</Reference>
<Content Include="..\bin\amqmdnet.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<Pack>true</Pack>
<PackagePath>lib\$(TargetFramework)</PackagePath>
</Content>
</ItemGroup>
<ItemGroup Condition="$(TargetFramework.StartsWith('netstandard2')) or $(TargetFramework.StartsWith('netcoreapp3'))">
<Reference Include="amqmdnetstd">
<HintPath>..\bin\amqmdnetstd.dll</HintPath>
</Reference>
<Content Include="..\bin\amqmdnetstd.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<Pack>true</Pack>
<PackagePath>lib\$(TargetFramework)</PackagePath>
</Content>
</ItemGroup>
each part of it working fine when the project is set with a concrete framework, for example :
<TargetFramework>netcoreapp3.1</TargetFramework>
but when the project is multi framework noting happened, dlls are not included
<TargetFrameworks>netcoreapp3.1;net451</TargetFrameworks>
I'm getting this message in multi framework scenario, this is the only context:
How I proceeded
For some reason nuget spec doesn't fill metadata; I test it with nuget version 5.5.1.6542.
I build the project with VS, how it is.
Change extension of {project folder}\bin\Release\xxx.nupkg to .zip
Extract xxx.nuspec file from xxx.zip. It will contain also dependencies metadata.
Edit xxx.nuspec with NuGet Package Explorer
Build nuget xxx.nuspec
.nuspec documentation
Answer
See this link. NuGet doc
I will post it and here:
<PropertyGroup>
<TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);GetMyPackageFiles</TargetsForTfmSpecificBuildOutput>
</PropertyGroup>
<Target Name="GetMyPackageFiles">
<ItemGroup Condition="$(TargetFramework.StartsWith('net4'))">
<BuildOutputInPackage Include="amqmdnet.dll">
<FinalOutputPath>..\bin\amqmdnet.dll</FinalOutputPath>
</BuildOutputInPackage>
</ItemGroup>
<ItemGroup Condition="$(TargetFramework.StartsWith('netstandard2')) or $(TargetFramework.StartsWith('netcoreapp3'))">
<BuildOutputInPackage Include="amqmdnetstd.dll">
<FinalOutputPath>..\bin\amqmdnetstd.dll</FinalOutputPath>
</BuildOutputInPackage>
</ItemGroup>
</Target>
Package third party dll in context of multi target framework project,
.Net Framework & .Net Core
I tried your sample and face the same issue in my side. When I use TargetFrameworks to set such dll into multi target framework projects and face the same situation.
And the <pack>true</pack> does not work due to your condition. But when I looked into output folder in such project, <CopyToOutputDirectory>Always</CopyToOutputDirectory> works. And according to the conditions, copy the two types of dll to the corresponding target framework folder.
However, pack does not work,still quite be strange.
So l report this issue to our DC Forum. See this link. You can vote this issue and add any comments if I did not describe the issue in detailed. And anyone who is interested in this issue will vote for you so that it will get more attention from the staff.
Suggestion
As a suggestion, you can use nuspec file with nuget.exe cli to pack your project which I have tested successfully.
1) download nuget.exe from this link and config its path into System Environment Variable PATH.
2) call Developer Command Prompt for VS or CMD and then cd your project path(which xxx.csproj exists)
Then call nuget spec and get xxx.nuspec file
3) open xxx.nuspec file and modify like these:
<?xml version="1.0" encoding="utf-8"?>
<package >
<metadata>
......
</metadata>
<files>
<file src="bin\Debug\net451\amqmdnet.dll" target="lib\net451" />
<file src="bin\Debug\net451\PRCB.IBM.MQ.dll" target="lib\net451"/>
<file src="bin\Debug\netcoreapp3.1\amqmdnetstd.dll" target="lib\netcoreapp3.1" />
<file src="bin\Debug\netcoreapp3.1\PRCB.IBM.MQ.dll" target="lib\netcoreapp3.1" />
</files>
</package>
4) Finally, type nuget pack xxx.nuspec and you will get the xxx.nupkg file.

How should I include Package References in a VSIX project

My solution creates a Visual Studio Package from multiple projects, using multiple NuGet packages.
All of the Nuget packages are specified in the project files using PackageReference (rather than the older packages.config file). I am using Visual Studio 2019.
I have had a problem, that the DLLs referenced by NuGet Packages are not included in the VSIX installation.
There is a solution to this problem, described in this article by Daniel Cazzulino, by adding the following code to the project file:
<PropertyGroup>
<GetVsixSourceItemsDependsOn>$(GetVsixSourceItemsDependsOn);IncludeNuGetResolvedAssets</GetVsixSourceItemsDependsOn>
</PropertyGroup>
<Target Name="IncludeNuGetResolvedAssets" DependsOnTargets="ResolveNuGetPackageAssets">
<ItemGroup>
<VSIXCopyLocalReferenceSourceItem Include="#(ReferenceCopyLocalPaths)" />
</ItemGroup>
</Target>
This does work, but it blows up the size of the installation from about 20MB to about 40MB.
The installation now includes a lot of PDB files, which I don't really need.
More significantly, it brings in about 46MB of Visual Studio DLLs which are not necessary, because they are part of Visual Studio.
Is there a better way to ensure that the referenced NuGet packages are included in the VSIX, without inflating the installation with these other files?
You can use a simple script like this:
<Target Name="IncludeNuGetPackageReferences" AfterTargets="GetVsixSourceItems">
<ItemGroup>
<VSIXSourceItem Include="#(ReferenceCopyLocalPaths)" Condition="'%(ReferenceCopyLocalPaths.NuGetPackageId)' == 'Newtonsoft.Json'" />
<VSIXSourceItem Include="#(ReferenceCopyLocalPaths)" Condition="'%(ReferenceCopyLocalPaths.NuGetPackageId)' == 'xxx'" />
... </ItemGroup>
</Target>
You can specify what assemblies should be included into .vsix . And it won't copy the unnecessary VS assemblies after tests in my machine. Hint from smourier, thanks to him.
Hope it helps:)

Create a Nuget package without its dependencies to be added as references

I need to create a Nuget package out of my library .net framework project.
The problem is that my project depends on many other dlls which I do not want my Nuget users to see. So I want people to install my package and see only my project dll in the references list, while all its dependencies will be added to bin folder only.
Actually, this is what happens when I reference this dll in any project- I can see it in my references list, and all its dependencies are simply copied to bin folder right after building. Can this behaviour be achieved with this project as Nuget ?
Create a Nuget package without its dependencies to be added as references
Since you do not want your Nuget users to see the other dlls, so you can not set those dlls file as dependencies, which will be added to the references list by default.
To resolve this issue, we need add those dlls file in the other folder in the .nuspec file and add a function to copy this dlls file to the bin folder when we add this nuget package to the project. You can follow below steps:
Add a xx.targets file in your project folder(The one you used to create nuget package ), make sure the name of the target file is the same name as the package id(TestDemo is my package ID, so the name of .targets is TestDemo.targets).
Add below code in the targets file:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)*.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
Note: The path of "$(MSBuildThisFileDirectory)" should be relative path, if you are not familiar with it, you can use the absolute path.
In the nuspec file, add required file to the Build directory along with the targets file.
<files>
<file src="<ThoseDllsPath>\*.dll" target="Build\" />
<file src="TestDemo.targets" target="Build\" />
<file src="bin\Debug\TestDemo.dll" target="lib\462" />
</files>
Pack this package, then add it on other project to test, it work fine.
Hope this helps.
I tried the solution of Leo Liu-MSFT. It worked in a .NET Framework Project, but not in a .NET Core 3.0
If you're using packages.config to manage your library's NuGet dependencies and building the nupkg with nuget.exe pack, then I believe you'll need to generate your own nuspec file and simply not add your build-time dependencies as a dependency to your package.
If you're using PackageReference, then you can use PrivateAssets
<ItemGroup>
<!-- ... -->
<PackageReference Include="Contoso.Utility.UsefulStuff" Version="3.6.0">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<!-- ... -->
</ItemGroup>

NuGet only imports my .targets file into the top project

I have multiple projects in my solution, they all have the same NuGet package installed. I installed this NuGet package via the 'Manage Nuget Packages for Solution' option in my menu.
Now this particular NuGet Package has a .targets file in my build folder that imports some files into the build.
When I rebuild my solution these files are only copied for the top-level project. The other projects don't get the files copied into their build folder. This is causing me headaches because all the projects need these files in their build folder.
When I look into my .csproject files I see the following difference:
Project 1
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\packages\NuGetTester.1.0.1\build\NuGetTester.targets" Condition="Exists('..\packages\NuGetTester.1.0.1\build\NuGetTester.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use 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('..\packages\NuGetTester.1.0.1\build\NuGetTester.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\NuGetTester.1.0.1\build\NuGetTester.targets'))" />
</Target>
</Project>
Project 2
The 2nd project does not have these lines.
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
When I include these lines in the 2nd project everything seem to work.
Can someone explain why this only happens for the first project? Can I somehow force that every project in the solution that installs this NuGet will also include these lines? I can't force my users to include this manually.
Edit, this is the .targets file.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Content Include="$(MSBuildThisFileDirectory)\Versions\*.sql">
<Link>App_Data\Versions\%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>
Thanks
Can someone explain why this only happens for the first project? Can I somehow force that every project in the solution that installs this NuGet will also include these lines?
Without install nuget package log, I could not give the reason that why this only happens for the first project. But you should make sure you have installed the nuget package to all projects when you installed the NuGet package via the 'Manage Nuget Packages for Solution' option:
If all check boxes are checked, you still have this issue, you should install individually that package to the problematic project, then check the install log.
Just in case, there is a workaround for this issue. You can create a MSBuild project file named "Directory.Build.props" in the same folder as your solution with you content in it.
It will be primitive imported into all projects in the directory hierarchy.
Check this document for more details.
Hope this helps.
It appears, to my knowledge, that the order of the projects was not the problem.
The problem only appears when I have no files in my target (net46) folder in the build folder.
Once I placed a random file into the .NET targetted folder the .targets file was imported into the project. Or if I removed all the .NET target folders from the build it works as usual.
So just to make a summary.
Build folder with no .NET framework target folders -> It works
Build folder with an empty .NET framework target folder -> Does not work
Build folder with a .NET framework target folder filled with one or many files -> It works

Build NuGet Package automatically including referenced dependencies

I want to run a local/internal NuGet repository. I think I've figured out how to "reuse" existing NuGet packages by including them in a dummy project using NuGet and scanning the package file to grab my locally-cached .nupkg files, but...
How do you create a nuget package (.nupkg) from a project, automatically including all dll dependencies and not just those grabbed via NuGet?
Specifically:
Create a solution
Add a new Project
Add references to various .dll files/other projects <-- this is the missing part
Add NuGet packages via package manager / cmdline / whatever
something automatically creates the .nupkg
From what I've found, you're supposed to do things like
manually edit your .csproj file to add <BuildPackage>true</BuildPackage> to include dependencies
manually create a .nuspec file and manually list your dependencies (similar ?)
manually run nuget pack on your .nuspec file
But everything is manual, which is stupid. Even the semi-automatic solutions are still awkward or half-manual:
Create .nuspec templates - doesn't seem to include dependencies, just metadata
nuget pack via build-event (step #5), which you need to add manually to every project, and it has its own quirks:
"$(SolutionDir).nuget\NuGet.exe" pack "$(ProjectPath)" -Properties Configuration=Release
move /Y *.nupkg "$(TargetDir)"
I'll settle for something that automatically creates a .nuspec manifest from project references. Then theoretically that + the nuget build-event can be rolled up into a build-project/nuget package, which is what I really want to see.
Your point #3 (Add references to various .dll files/other projects <-- this is the missing part) really contains two different issues: (1) add references to various dll files, and (2) add references to other projects in the same solution.
Number (2) here has gotten some added support as of NuGet 2.5. You can add an option to include references to other projects in the same solution when creating a NuGet package for a project:
nuget pack projectfile.csproj -IncludeReferencedProjects
If projectfile.csproj references any other projects in your solution that also is exposed as NuGet packages, these projects' NuGet packages will be added as dependencies.
If it references projects in your solution that doesn't expose themselves as NuGet packages, their dlls will be included in this NuGet package.
As for (1), if you find yourself often adding dlls to your projects that aren't available as NuGet packages, you could just create your own (internal) NuGet packages with these files. If you then add these dlls as a NuGet package instead of the files directly, this NuGet package will be a dependency in your project's NuGet package.
I found a well-written article on this topic. I have the same issue with certain packages that have a hierarchy of dependencies and up until now I've been uploading each as a separate NuGet package (what. a. waste. of. time)
I've just tested the solution found here: https://dev.to/wabbbit/include-both-nuget-package-references-and-project-reference-dll-using-dotnet-pack-2d8p
And after examining the NuGet package using NuGet Package Explorer, the DLLs produced by referenced projects are indeed present. I'm going to test by actually submitting this package to NuGet and testing it.
Here's my source in case it is helpful to you: https://github.com/jchristn/NuGetPackTest
And the test NuGet package: https://www.nuget.org/packages/NuGetPackTest/1.0.0
The solution appears to work well. I don't know what it's going to look like when there are layers of references, I'm sure it could get really hairy and really fast.
.csproj from NuGetPackTest library which references project TestLibrary (portions removed for brevity)
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netcoreapp3.0;netcoreapp3.1;net461</TargetFrameworks>
...
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<!-- added this line -->
<TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);CopyProjectReferencesToPackage</TargetsForTfmSpecificBuildOutput>
</PropertyGroup>
<ItemGroup>
<!-- modified this ProjectReference to include the children ReferenceOutputAssembly and IncludeAssets -->
<ProjectReference Include="..\TestLibrary\TestLibrary.csproj">
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
<IncludeAssets>TestLibrary.dll</IncludeAssets>
</ProjectReference>
</ItemGroup>
<!-- added this section -->
<Target DependsOnTargets="ResolveReferences" Name="CopyProjectReferencesToPackage">
<ItemGroup>
<BuildOutputInPackage Include="#(ReferenceCopyLocalPaths->WithMetadataValue('ReferenceSourceTarget', 'ProjectReference'))"/>
</ItemGroup>
</Target>
</Project>
For other Googlers, you can use this if you are using the NuGet.targets file to run NuGet Pack:
<Target Name="PrePackage" BeforeTargets="BuildPackage">
<PropertyGroup>
<BuildCommand>$(BuildCommand) -IncludeReferencedProjects</BuildCommand>
</PropertyGroup>
</Target>
Check this out!
The solution which I found is an extension for Visual Studio:
https://visualstudiogallery.msdn.microsoft.com/fbe9b9b8-34ae-47b5-a751-cb71a16f7e96/view/Reviews
You simply add new project called NuGet Package:
Then you are adding interesting you projects to references and BOOOM !!
All dependencies and file directories are automatically added.
If you want to modify NuSpec data you click right at project and go to Properties,
then modify what you want.
Generated NuSpec and nupkg will be in folder obj of your new project.
I hope it helps ;).
I solved this for my case by adding the whole TargetDir to the nuget package.
Just add this to the .csproj :
<Target Name="IncludeAllFilesInTargetDir" AfterTargets="Build">
<ItemGroup>
<None Include="$(TargetDir)\**">
<Pack>true</Pack>
<PackagePath>tools</PackagePath>
</None>
</ItemGroup>
</Target>

Resources