Recently started looking at publishing our C# libraries to nuget.org. This first post covers my experience with the actual packaging. In a later post I’ll do the signing and publishing.
In the Beginning
Subor.NNanomsg.NETStandard (our fork of NNanomsg- a C# library for nanomsg) was particularly frustrating because it involves a native library nanomsg.dll
.
Google un-earthed several promising resources:
- Stackoverflow #1 and #2
- MS docs on using nuget to create native packages
- Blog by former SignalR/ASP.NET guy
But I struggled making a package that worked; nanomsg.dll
wasn’t in the output directory.
General Tips
The .targets
file mentioned in several places seems to no longer be necessary (VS 15.7.4 and nuget.exe 4.7.0) unless your package will be consumed by c++ projects.
Managed libraries need to get packaged in /lib/TFM/
. SeeSupporting multiple .NET framework versions and about Target Framework Monikers (TFM)
Native libraries need to get packaged in /runtimes/RID/native/
. Runtime ID Catalog not only has a complete list of all Runtime IDs (RIDs), but also gives a pretty detailed explanation.
- Familiarize yourself with nuget.exe
-
nuget pack -Properties Configuration=Release
will build a release nupkg (default is debug) for the.csproj
in the current directory. The output assembly will automatically be included. - Package version can be set by adding
-Version X.Y.Z
-
- The NuGetPackageExplorer gives a nice visual look at your nupkg and its meta-data. Just make sure to File->Close otherwise nuget.exe and Visual Studio will have problems accessing your nupkg.
Nuspec
-
nuget.exe spec
will generate a template nuspec from csproj in current directory - A nuspec file with the same name as the csproj will automatically get included when using nuget.exe from the command line. For example,
NNanomsg.NETStandard.csproj
andNNanomsg.NETStandard.nuspec
. - Replacement tokens usable in nuspec
- Using a nuspec together with a csproj is clumsy
- There’s only replacement tokens for some meta-data values
- Omitting a tag from the nuspec results in the value being undefined- even if it is set in the csproj
- Enabling generation of NuGet package on build (placed in output folder) doesn’t use the nuspec:
When using nuget.exe, a <files>
section of the nuspec seems to be the only way to include /runtimes/
files. <Content>
in csproj places things in a content/
subfolder (nuget.exe ignores <ContentTargetFolders>
), <None>
doesn’t include them at all.
- You can directly pack the nuspec (e.g.
nuget pack NNanomsg.NETStandard.nuspec
)- If you see the following warning:
WARNING: NU5100: The assembly 'bin\Release\netstandard2.0\NNanomsg.NETStandard.dll' is not inside the 'lib' folder and hence it won't be added as a reference when the package is installed into a project. Move it into the 'lib' folder if it needs to be referenced.
You likely need the following in your nuspec:
<files>
<file src="bin\$configuration$\netstandard2.0\*.dll" target="lib\netstandard2.0\"/>
<file src="runtimes\**" target="runtimes/"/>
</files>
- If you get the following error:
Attempting to build package from 'NNanomsg.NETStandard.nuspec'.
Value cannot be null or an empty string.
Parameter name: value
The nuspec contains a replacement token (i.e. $xxx$
) that needs to be replaced with an actual value
NuGet as MSBuild targets
Starting NuGet 4.0, all package-related metadata can be stored in the csproj.
If your project doesn’t reference any external packages you might need to force the PackageReference format by adding to your csproj:
<PropertyGroup>
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
</PropertyGroup>
Not sure if it matters, but I use PackageReference by default ( Tools->Options->NuGet Package Manager ):
I include the native binaries with:
<ItemGroup>
<Content Include="runtimes\**" PackagePath="runtimes" Visible="false" />
</ItemGroup>
And then right-click the project->Pack to generate the nupkg. Or in a VS Developer Command Prompt:
msbuild /t:pack
Consuming nupkg
In Visual Studio, Tools->Options->NuGet Package Manager->Package Sources to add a local directory as source for nuget packages:
Visual Studio Package Manager ( View->Other Windows->Package Manager Console ) makes it easy to reload a local nupkg. Make sure Default project is set to the correct project and run: Install-Package D:\dev\NNanomsg\NNanomsg.NETStandard\NNanomsg.NETStandard.0.5.2.nupkg
.
Installing the package doesn’t cause the native binaries to get copied, you have to build the project.
Assuming your nupkg contains 32-bit and 64-bit native libraries, runtimes/win-x86/native/nanomsg.dll
and runtimes/win-x64/native/nanomsg.dll
, respectively. If Platform target (project Properties->Build ) of the consuming project is Any CPU
neither native assembly will be copied to the output directory. You must select either x86
or x64
:
Conclusions
- Least frustrating to pick either nuspec or VS project for package definition- don’t use both
- Nuspec has diminished VS integration, but simpler command line use- just need nuget.exe
- Using VS project for package definition has best VS integration, but then stuck dealing with complexities of msbuild
Next I’ll go over signing our package and pushing it to nuget.org.
Top comments (0)