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

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.

Related

build project without runtimes folder but included nuget packages in nopcommerce 4.40(.net 5 and VS 2019)

I'm developing plugin for nopcommerce,
I'm using VS 2019 and nopcommerce 4.40.4(.net 5)
I should use a nuget package in my plugin,
If I set CopyLocalLockFileAssemblies to true, when I build my project, it created runtimes folder, which is about 65 MB,
If I set CopyLocalLockFileAssemblies to false, it does not create runtimes folder, but, the dll of nuget package which I should use, not included in the build folder,
would you please help me about this?
Note: set copy local to no, make no difference when I change for Nop.Services which I use in the project
this is my csproj and my the package is > SmsIrRestful.NetCore :
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<OutputPath>..\..\Presentation\Nop.Web\Plugins\AttributeStockSMS</OutputPath>
<OutDir>$(OutputPath)</OutDir>
<!--Set this parameter to true to get the dlls copied from the NuGet cache to the output of your project.
You need to set this parameter to true if your plugin has a nuget package
to ensure that the dlls copied from the NuGet cache to the output of your project-->
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
<ItemGroup>
<ClearPluginAssemblies Include="$(MSBuildProjectDirectory)\..\..\Build\ClearPluginAssemblies.proj" />
</ItemGroup>
<ItemGroup>
<None Remove="plugin.json" />
</ItemGroup>
<ItemGroup>
<Content Include="plugin.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="SmsIrRestful.NetCore" Version="1.1.5" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Libraries\Nop.Services\Nop.Services.csproj">
<Private>false</Private>
</ProjectReference>
</ItemGroup>
<Target Name="NopTarget" AfterTargets="Build">
<!-- Delete unnecessary libraries from plugins path -->
<MSBuild Projects="#(ClearPluginAssemblies)" Properties="PluginPath=$(MSBuildProjectDirectory)\$(OutDir)" Targets="NopClear" />
</Target>
</Project>
Instead of using NuGet reference, include the dll file of that NuGet package. For example, You are going to use TaxJar library then follow these steps.
Added NuGet reference.
Right click on NuGet package and go to properties.
Copy path value from property values as below.
Go to that path in file explorer.
Find dll file(s) from there, copy-paste into your plugin folder and add refence.
Repeat same procedures for dependent packages also (if any).
Mark as Copy Local to Yes from properties.

Create nuget package that references referenced .dlls without using .nuspec

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.

ASP.NET Core (NET Framework) Teamcity build fails, VS builds properly

I have an ASP.NET Core project that builds properly with VS but fails with TeamCity.
It is a project that compiles to a library, but TeamCity tries to build it as an executable, and complains about the lack of 'main':
CSC error CS5001: Program does not contain a static 'Main' method suitable for an entry point
The content of the .csproj file are as follow:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<OutputType>Library</OutputType>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>net462</TargetFramework>
<RuntimeIdentifier>win7-x86</RuntimeIdentifier>
<OutputTypeEx>library</OutputTypeEx>
<StartupObject />
<AssemblyName>Test</AssemblyName>
<RootNamespace>Test</RootNamespace>
</PropertyGroup>
<ItemGroup>
<Folder Include="wwwroot\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore" Version="1.1.2" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.3" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
</ItemGroup>
</Project>
Visual studio has no problem building the dll file.
To reproduce:
Create an ASP.NET Core (.NET Framework) project
Change the output type to library
Remove the program.cs / startup.cs files
Compile with Visual Studio to confirm a library is being built
Build with Team City and an error will appear
To avoid that error, Please look into this SO post or this
You should be using the dotnet core plugin or you can easily
configure dotnet build command(if dotnet is present in your build
servers).
Or you can refer the MusicStore build.cmd file for reference. This basically downloads and installs the dotnet and all the dependencies and then builds the project.
Hope it helps!
I found a workaround; in the project file, VS puts this:
<OutputTypeEx>library</OutputTypeEx>
I need to add one line:
<OutputType>Library</OutputType>
<OutputTypeEx>library</OutputTypeEx>
So it looks like the build with TeamCity is not handling the OutputTypeEx propery but it handles the OutputType one.
I still see this as a bug, but at least there is a workaround.

Include XML file from package when using "Publish Web"

I have a Web API project that depends on a NuGet package. This package contains an XML file that is referenced by my application at runtime.
When I build the solution and run it in debug mode from Visual studio the file gets copied to \bin, and the application runs without problem.
When I publish the application the file doesn't get copied to the final output, and I can see that it's never been copied to the \obj folder.
I've though of adding the file reference directly to the package in the \packages folder, but this will break whenever the package version is updated.
How can I specify that the file should be copied when deploying?
I figured it out based on this blogpost.
I added the following to the end of the .csproj file:
<PropertyGroup>
<CopyAllFilesToSingleFolderForPackageDependsOn>
CustomCollectFiles;
$(CopyAllFilesToSingleFolderForPackageDependsOn);
</CopyAllFilesToSingleFolderForPackageDependsOn>
</PropertyGroup>
<Target Name="CustomCollectFiles">
<Message Text="=== CustomCollectFiles ===" Importance="high" />
<ItemGroup>
<_CustomFiles Include="..\Packages\**\*PackageName.*.xml*" />
<FilesForPackagingFromProject Include="%(_CustomFiles.Identity)">
<DestinationRelativePath>bin\%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
Petter Brodins answer almost work for me. And since I am new to Stackoverflow commenting i can not add a comment. In order for it to work I changed the Include to "..\Packages*\lib*.xml". But this was a life saver since i wrote a lot of documentation and couldn't get it to my swagger implementation.

How to deal with relative NuGet packages paths to facilitate easy pckages dir relocation with NuGet.Config?

We moved NuGet's packages folder to some other place and created a NuGet.Config file at the slns level:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<config>
<add key="repositoryPath" value="../.nugetPackages" />
</config>
</configuration>
We also have this in few of our csproj files:
<Import Project="..\..\..\Proj\packages\Microsoft.Azure.DocumentDB.1.7.1\build\Microsoft.Azure.DocumentDB.targets" Condition="Exists('..\..\..\Proj\packages\Microsoft.Azure.DocumentDB.1.7.1\build\Microsoft.Azure.DocumentDB.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('..\..\..\Proj\packages\Microsoft.Azure.DocumentDB.1.7.1\build\Microsoft.Azure.DocumentDB.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\Proj\packages\Microsoft.Azure.DocumentDB.1.7.1\build\Microsoft.Azure.DocumentDB.targets'))" />
</Target>
And this too:
<Import Project="..\..\packages\PostSharp.4.2.17\tools\PostSharp.targets" Condition="Exists('..\..\packages\PostSharp.4.2.17\tools\PostSharp.targets')" />
<Target Name="EnsurePostSharpImported" BeforeTargets="BeforeBuild" Condition="'$(PostSharp30Imported)' == ''">
<Error Condition="!Exists('..\..\packages\PostSharp.4.2.17\tools\PostSharp.targets')" Text="This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://www.postsharp.net/links/nuget-restore." />
<Error Condition="Exists('..\..\packages\PostSharp.4.2.17\tools\PostSharp.targets')" Text="The build restored NuGet packages. Build the project again to include these packages in the build. For more information, see http://www.postsharp.net/links/nuget-restore." />
</Target>
My question is how to deal with such relative package paths in the csproj files to keep things generic (so we could easily move the package folder anytime anywhere)?
Is there maybe some variable we can use like $NuGetPackagesDir or something like that?
(We use Vs2015, NuGet 5.3 and TeamCity build server [I don't remember current version..])
You cannot really have a generic path and still use the NuGet tooling within Visual Studio since when you update a package the hint path will be updated by NuGet back to a relative path if you are using a packages.config file.
Whilst you could specify a global packages folder the hint paths will be relative to that path depending on where you put the solution.
The hint path problem goes away when you use a project.json file or have a new .NET Core style project that uses PackageReference elements in the .csproj file. If you are using a packages.config file then your .csproj file will have hint paths pointing to assemblies within the packages folder.

Resources