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
.targetsfile 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/. See Supporting 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=Releasewill build a release nupkg (default is debug) for the.csprojin 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 specwill 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.csprojandNNanomsg.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 acontent/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: valueThe nuspec contains a replacement token (i.e.
$xxx$) that needs to be replaced with an actual value
- If you see the following warning:
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.dllandruntimes/win-x64/native/nanomsg.dll, respectively. If Platform target (project Properties->Build) of the consuming project isAny CPUneither native assembly will be copied to the output directory. You must select eitherx86orx64:

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.