Create Nuget package for different platforms, architectures and .net versions - c#

I have a C# 7.3 project Foo which I want to publish as a Nuget package. I want my package be available for different architectures (x86 & x64), different platforms (Windows & Linux) and different .Net versions (4.8 framework & 5.0).
Foo C# code itself does not contain any architecture-specific code, it consists only of pure C# 7.3. But this project uses my custom platform-specific .dll and .so on Linux (say ExternalLib.dll / ExternalLib.dll.so). I have one of them for each Windows x64, Windows x86 and etc.
I know that in the NuGet package you place runtime-specific components in /runtimes folder structure like /runtimes/win10-x64/native/ExternalLib.dll. As documentation says, these will be used only for runtime and I need to specify compile-time references.
I built my Foo project in Any CPU configuration for each net4.7 and net5.0 and placed each Foo.dll in /lib folder. So my final folder structure for the module is
Project.nuspec
/lib
/net4.7/Foo.dll
/net5.0/Foo.dll
/runtimes
/win10-x64/native/ExternalLib.dll
/win10-x86/native/ExternalLib.dll
/linux-x64/native/ExternalLib.dll.so
Project.nuspec:
<?xml version="1.0" encoding="utf-8"?>
<package>
<metadata>
/* */
<dependencies>
<group targetFramework=".NETFramework4.8" />
<group targetFramework="net5.0" />
</dependencies>
</metadata>
</package>
I build a package using the nuspec pack Project.nuspec command. There are no errors from it but when I add this package to any .net project and try to use any functionality from it, VS can not find anything from my library.
What am I doing wrong?

I finally did it. After a research, this is my approach:
If you write a C# library, use only .NetStandard, so both .Net and .NetFramework applications can use your library. I used .NetStandard2.0 which can be used from both .Net5.0 and .NetFramework4.8. See this for all compatible versions.
Clear NuGet cache
Provide xml documentation (optional)
Final .nuspec file:
<?xml version="1.0" encoding="utf-8"?>
<package >
<metadata>
...
<dependencies>
<group targetFramework="netstandard2.0" />
</dependencies>
</metadata>
<files>
<!--Path to documentaion and AnyCPU builded dll-->
<file src="Doc\Api.xml" target="lib\netstandard2.0"/>
<file src="bin\x86\Release\netstandard2.0\Foo.dll" target="lib\netstandard2.0"/>
<!--Path to x86 builded ExternalLib and Foo-->
<file src="build\x86-Release\ExternalLib.dll" target="runtimes\win-x86\native" />
<file src="bin\x86\Release\netstandard2.0\Foo.dll" target="runtimes\win-x86\native" />
<!--Path to x64 builded ExternalLib and Foo-->
<file src="build\x64-Release\ExternalLib.dll" target="runtimes\win-x64\native" />
<file src="bin\x64\Release\netstandard2.0\Foo.dll" target="runtimes\win-x64\native" />
<!--Path to x64 builded ExternalLib(for linux) and Foo(same as windows)-->
<file src="build\x64-Release\ExternalLib.so" target="runtimes\linux-x64\native\ExternalLib.dll.so" />
<file src="bin\x64\Release\netstandard2.0\Foo.dll" target="runtimes\linux-x64\native" />
</files>
</package>

Related

How do i remove dll(s) from Nuget package?

Im using Visual Studio 2022 and created a Nuget Package using this article
https://arsenshnurkov.github.io/gentoo-mono-handbook/building-nupkg.htm
I run nuget pack and i see the nupg file and upload it to our Azure Artifacts. Below is the spec file
<package >
<metadata>
<id>myProject.csproj</id>
<version>1.0.0</version>
<authors>user</authors>
<owners>user</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Test package 1</description>
<releaseNotes>Summary of changes.</releaseNotes>
<copyright>Copyright 2023</copyright>
<tags>Tag test</tags>
</metadata>
</package>
I noticed when i install this pack into a test application it includes some dlls that are not required for the end project to run.
After some research there are suggestions to change the .csproj to exclude it from Nuget when packing following this article https://www.jocheojeda.com/2019/07/22/how-to-exclude-package-dependencies-in-a-nuget-package/
but he writes the exact question i have in mind but no example of how to do this. In the article he quotes
the answer depend on how now you create your NuGet package, in this case, I’m going to focus my answer on excluding the dependency in a package created by the info in the csproj file (there is a different approach if you use the nuspec file).
I dont want to amend the csproj file but just the nuspec file. How could i leave out files that i dont want to have bundled with my package by amending the nuspec file?
In order to include/exclude files from nuget packaging, you can add the section to nuspec config file as described here.
Following your example, the files would exclude log files from your package. Using wildcards, you can exclude any other file/dll:
<package>
<metadata>
<id>myProject.csproj</id>
<version>1.0.0</version>
<authors>user</authors>
<owners>user</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Test package 1</description>
<releaseNotes>Summary of changes.</releaseNotes>
<copyright>Copyright 2023</copyright>
<tags>Tag test</tags>
</metadata>
<files>
<file src="*.*" exclude="*.log" />
</files>
</package>

c# nuget package doesn't show up in references in VS

I want to create a C# app that does things with the powershell. I found many solutions on the internet how to do that like this. The most answeres to this use the Powershell class from 'Microsoft.WSMan.Runtime'. Now when I search this package in nuget and install it, it doesnt show up in the references list in visual studio and also the using statement or the 'quick fix' on a PowerShell object doesnt find it.
Did I install something wrong or do I need something else too?
Edit for more infos:
.net Version 4.6.1
Tried 'Microsoft.WSMan.Runtime'v 7.0.0 and 7.0.3
'Microsoft.WSMan.Runtime' is downloaded and avaible at './packages/Microsoft.WSMan.Runtime.7.0.0'
'packages.config' does contain the entry for 'Microsoft.WSMan.Runtime'.
I found the assembly within the package targets .net core 3.1 instead of .net framework 4.6.1. So you can't see the reference in solution explorer.
It's by design of the package author, you can download the package manually, rename the name from xx.nupkg to xx.zip to check the content of the package.
The structure of the package:
And the content of the Microsoft.WSMan.Runtime.nuspec file:
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
...
<dependencies>
<group targetFramework=".NETCoreApp3.1" />
</dependencies>
<contentFiles>
<files include="**/*" buildAction="None" copyToOutput="true" flatten="false" />
</contentFiles>
</metadata>
</package>

How to copy Nuget Package Dependencies

We are currently refactoring an old win forms app which uses a framework as referenced project across the whole application. I am fairly new to nuget and .net so I hope you don't mind my newbiew question.
We created a nuget package from the csproj (Syncing.nupgk). That package references other packages like Newtonsoft or Consul. When I build the project, my syncing.dll gets copied to the bin folder of the win forms project, but other dlls (newtonsoft.dll, consul.dll) are copied outside in a packages folder with a structure lib\net45 etc.
How I can tell visual studio that I also need the newtonsoft.dll in the bin folder of the project as it is a dependencie of my syncing.dll
thx!
I usually use nuspec file for this purpose. In your case, you would have Syncing.csproj.nuspec which looks something like this:
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
<id>Syncing</id>
<authors></authors>
<owners></owners>
<requireLicenseAcceptance>true</requireLicenseAcceptance>
<licenseUrl></licenseUrl>
<projectUrl></projectUrl>
<iconUrl></iconUrl>
<description></description>
<language></language>
<tags></tags>
<dependencies>
<group targetFramework=".NETStandard2.0">
<dependency id="Newtonsoft.Json" version="12.0.2" exclude="Build,Analyzers" />
...
</group>
</dependencies>
</metadata>
</package>
You can look at these two links for more info:
- https://learn.microsoft.com/en-us/nuget/reference/nuspec
- This is how I'm using .nuspec file to publish the instrumentation library on https://github.com/borkke/opentracing-csharp-mongo/blob/master/src/OpenTracing.Contrib.Mongo/OpenTracing.Contrib.Mongo.csproj.nuspecnuget

How to share source code via NuGet packages for use in .NET Core projects

I want to make small pieces of source code (e.g. helper classes) available for use in .NET Core projects (.csproj).
At this point I packaged the source code with NuGet in many different ways according to different blog posts and the official nuget docs. I used a nuspec file to control where my source files will end up in the nuget package, e.g.:
<files>
<file src="*.cs" target="content/LruCache" />
<file src="*.cs" target="contentFiles/cs/any/LruCache" />
</files>
I did not include any msbuild targets file or install script.
Whenever I install the NuGet package into a .NET Core project (https://learn.microsoft.com/en-us/dotnet/core/tools/csproj) I simply don't get anything there. No source files will be included into my project. I tried different settings for the <PackageReference/> node in the .csproj (PrivateAssets, etc.) without success.
Is it meant to be possible at all? If so, how should it be done?
Background:
The reason for doing this is some kind of diamond problem where we have projects B and C both using helper class A and a third project D using B and C.
In this situation I don't want to deal with assembly version conflicts when different (incompatible) versions of A have been used in B and C.
Is it meant to be possible at all? If so, how should it be done?
The answer is yes. Since you test project type is .net core. You should use contentFiles instead of content. content is used for packages.config. Check the Using the contentFiles element for content files and blog NuGet ContentFiles Demystified for more details.
So your .nuspec file should be:
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>MyTestCore</id>
<version>5.0.0</version>
<authors>TestContentFile</authors>
<owners>TestContentFile</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Package Description</description>
<contentFiles>
<files include="any/any/Test.cs" buildAction="content" flatten="true" copyToOutput="true"/>
</contentFiles>
</metadata>
<files>
<file src="contentFiles/any/any/Test.cs" target="contentFiles/any/any/LruCache" />
</files>
</package>
The nuget package should look like:
Note: When you create a new package, do not forgot to remove the nuget cache for this package in the C:\Users\<UserName>\.nuget\packages folder, otherwise, it always install the old package.
With this method, the source files will be included into your project.
Hope this helps.

Copy C++ dlls to build output of any C# project that reference them by extension

I have a C# library that references some C++\CLI project that contains a few C++ libraries compiled as dlls.
So all in all, on runtime of any app that uses my library, I need of course the C# and CLI dlls, but also all the C++ ones, which are not copied by default even though they are referenced by the CLI project.
Using Pre-build events to copy them manually works.
But not only do I need to add them per application project, but I also want to publish my library as NuGet and cannot control the properties of the referenced projects then.
Any workaround? Event one that is specific to NuGet packages.
I like Hans Passants comments. His answer reduces the amount of copied data and allow the seamless use of AnyCPU.
My solution is something which is used by a WPF project. The project type supporting old project files, that are not quite supported by nuget as .NET Core or .NET Standard projects. But no c++cli in .NET Standard. We only have x64 assemblies and my consumers are only internal, so do not need to care about win32.
The new nuget syntax allows a great deal in fine control for those dlls, but actually I'm not done with my learning curve and nuget.
So this is what i use for a strict wrapping dll. That people can debug into my dll, I put the debug dll, pdbs into the package, they only are consumed within our company. I do write the target file for the packages that those assemblies get referenced if the user changes the configuration to debug.
native dll <-- c++cli wrapper <-- c# convenience load
' nuspec
<?xml version="1.0"?>
<package xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<metadata xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<description></description>
<id>yourId</id>
<version>$version$</version>
<authors></authors>
<!-- Only done because at the beginning I copied the native dll into the lib/net461 folder which gets automatically referenced -->
<references>
<reference file="yourCSharpProject.dll" />
<reference file="yourInteropProject.dll" /> <!-- if needed -->
</references>
</metadata>
<files>
<!-- the target file will copy my native dlls into the target file -->
<file src="target\**" target="build"/>
<!-- copy all debug and release of ... Native.dlls, pdbs, xml -->
<!-- usage hint ** preserves the folder structure, debug and release -->
<file src="bin\x64\**\YourNative.*" target="lib\native\" />
<!-- copy all debug and release of ... Interop.lls, pdbs, xml -->
<file src="bin\x64\Release\.*" target="lib\net461\" />
</files>
</package>
' target\yourpackageName.target
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="CopyBinaries" BeforeTargets="BeforeBuild">
<CreateItem Include="$(MSBuildThisFileDirectory)../lib/native/$(Configuration)/*" >
<Output TaskParameter="Include" ItemName="SomeImportantName" />
</CreateItem>
<Copy SourceFiles="#(SomeImportantName)"
DestinationFolder="$(Outputpath)"
SkipUnchangedFiles="true" />
</Target>
</Project>

Categories

Resources