For anyone who has been cutting-edge with .Net for a while will know that the nuget.exe runs under mono. And that you can use nuget.exe to package
*.nuspec files into
Anyone who has been doing dotnet cross-platform will also know that you can use
dotnet pack on both Windows and Linux to package your project into a NuGet package containing the
dll. It even does references and multi-targeting correctly out of the box.
But did you know that you can also use dotnet pack to package any arbitrary
nuspec file as well?
First, let’s look at a simple
nuspec file that only has package references (an aggregate package).
<?xml version="1.0" encoding="utf-8"?> <package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd"> <metadata> <id>MyNewApp</id> <version>1.0.0</version> <authors>csMACnz</authors> <description>An aggregate package example</description> <tags>utils example</tags> <dependencies> <dependency id="Newtonsoft.Json" version="11.0.2" /> <dependency id="Beefeater" version="0.5.0" /> </dependencies> </metadata> <files> <!-- empty files tag avoids copying all files --> </files> </package>
We could use
nuget.exe pack but that wouldn’t work on Linux. Instead, we create a csproj file designed to do the pack for us in a standard
dotnet pack kind of way.
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>netstandard2.0</TargetFramework> <NuspecFile>newapp.nuspec</NuspecFile> <NuspecProperties></NuspecProperties> <NuspecBasePath></NuspecBasePath> </PropertyGroup> </Project>
The magic is these three properties (only one required, really):
<NuspecFile>- Required to tell dotnet to use the hand-crafted
<NuspecProperties>- (Optional) ability to generate and send
<NuspecBasePath>- (Optional) relative base path to use for pack files (defaults to project folder)
For more details on all the things you can put into a
nuspec file, check out the docs: https://docs.microsoft.com/en-us/nuget/reference/nuspec
But we don’t stop there. If you run this you will see that we are still building our empty project. We can do a couple of things here.
<NoBuild>true</NoBuild>- Adding this will stop the build step being run during pack
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>- We can instead tell
dotnet buildto run the pack as well.
One of these two scenarios may suit you better. It depends.
Using the above settings, you can basically produce any kind of NuGet package you want.
For one last piece of tidy-up, you can disable the compile and remove the dll from the build output entirely:
<SkipCompilerExecution>true</SkipCompilerExecution>- (Optional) disable compile entirely
<CopyBuildOutputToOutputDirectory>false</CopyBuildOutputToOutputDirectory>- stop the dll output to the output folder.
Unfortunately, at this stage I am still yet to find a reasonable way to remove the need for
<TargetFramework>, but something I am still experimenting with. There is a chance that if you are really customising your MSBuild commands, you would end up leveraging the
dotnet restore, and that requires a TargetFramework anyway, so not a big deal.