Creating a nuget package (revisited)

I’ve covered some of this post previous in my post Creating Local Packages with NuGet, but I wanted to drill down a little more into this here.

Part of the reason for a revisit is that I wanted to look at creating the relevant .nuspec for a couple of projects I’ve put on github and I wanted to cover the .nuspec files in a little more depth.

Before we start

Before we start you’ll probably want to grab the latest nuget.exe from Available NuGet Distribution Versions. The current recommended version is v4.9.4 and this should be placed in your project folder (or ofcourse wherever you prefer in the path).

Generating a nuspec file

We can now run

nuget spec

in my case, this produced the following

<?xml version="1.0"?>
<package >
  <metadata>
    <id>Package</id>
    <version>1.0.0</version>
    <authors>PutridParrot</authors>
    <owners>PutridParrot</owners>
    <licenseUrl>http://LICENSE_URL_HERE_OR_DELETE_THIS_LINE</licenseUrl>
    <projectUrl>http://PROJECT_URL_HERE_OR_DELETE_THIS_LINE</projectUrl>
    <iconUrl>http://ICON_URL_HERE_OR_DELETE_THIS_LINE</iconUrl>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>Package description</description>
    <releaseNotes>Summary of changes made in this release of the package.</releaseNotes>
    <copyright>Copyright 2019</copyright>
    <tags>Tag1 Tag2</tags>
    <dependencies>
      <dependency id="SampleDependency" version="1.0" />
    </dependencies>
  </metadata>
</package>

As you can see, it’s supplied the basics along with an example of a dependency. The dependencies are the package our project is dependent upon. The id can be found via the nuget website or from the nuget packages section within Visual Studio. The versions can also be found in the same way.

If we wish to add files to our nuspec we add a files section after the metadata end tag. For example

  </metadata>

   <files>
      <file src="" target="" />
   </files>

</package>

The src is the relative location of the files to add (maybe we’re adding a README.txt for example). The target is where the file should be copied to. Using content as the start of the target will added file to the content folder.

Naming conventions

The next thing I want to touch on is naming conventions, which I think becomes important if you’re intending the deploy on the NuGet site (as opposed to local to your organization or the likes).

The Names of Assemblies and DLLs discusses some possible conventions. Obviously the <Company>.<Component>.dll is a very sensible convention to adopt as we will need to ensure our assemblies are as uniquely named as possible to stay away from name clashes with others.

Obviously using such naming conventions will tend to push towards namespace etc. naming conventions also, so have a read of Names of Namespaces also.

Generating our NuGet package from a project

Before we look at the nuspec file itself, let’s cover the simple way of generating our NuGet package, as this might be all you need if the component/code you want to package is fairly self-contained.

Before we create the package, let’s create a bare bones .nuspec file because otherwise, the nuget tool will generate one along these lines

<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
  <metadata>
    <id>PutridParrot.Collections</id>
    <version>1.0.0.0</version>
    <title>PutridParrot.Collections</title>
    <authors>PutridParrot</authors>
    <owners>PutridParrot</owners>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>Description</description>
    <copyright>Copyright © PutridParrot 2017</copyright>
    <dependencies />
  </metadata>
</package>

Note: the project I ran this against was PutridParrot.Collections.csproj

So lets take this and change it a little – create a .nuspec named after your project, i.e. mines PutridParrot.Collections.nuspec and paste the below, into it (change names etc. as you need).

<?xml version="1.0"?>
<package >
  <metadata>
    <id>Your Project Name</id>
    <version>1.0.0.0</version>
    <title>Your project title</title>
    <authors>Your Name</authors>
    <owners>Your Name</owners>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>Your Description</description>
    <releaseNotes>First Release</releaseNotes>
    <copyright>Copyright 2017</copyright>
    <tags>collections</tags>
  </metadata>
</package>

Note: The tags are used by the NuGet repos, so it’s best to come up with several (with a space between each) tags for your project.

Now we’ve got a nuspec file this will be embedded into the package by nuget.

From the command line, (easiest from the folder containing the project you want to package) run

nuget pack <project-name>.csproj

Note: as the package is zipped, just append .zip to it to open using File Explorer in Windows, so you can see how it’s laid out. Don’t forget to remove the .zip when relocating to local host of remote host.

Autogenerating parts of the nuspec from AssemblyInfo

We can actually tokenize some of our nuspec and have nuget use our project’s AssemblyInfo.cs file, see Replacement tokens.

This means, for example version might be written like this

<version>$version$</version>

and will have this value automatically replaced and the nupkg will be named with that same version.

Multiple files or how to use nuget pack with the csproj

Running nuget pack against a project is useful but what if you want to handle multiple projects and/or non-project files? Then we would be better off editing the nuspec file to pull in the files we want.

Here’s an example of the previous nuspec which now includes more than one version of the project’s DLL.

<?xml version="1.0"?>
<package >
  <metadata>
    <id>Your Project Name</id>
    <version>1.0.0.0</version>
    <title>Your project title</title>
    <authors>Your Name</authors>
    <owners>Your Name</owners>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>Your Description</description>
    <releaseNotes>First Release</releaseNotes>
    <copyright>Copyright 2017</copyright>
    <tags>collections</tags>
  </metadata>
  <files>
    <file src="bin\Release\PutridParrot.Collections.dll" target="lib\net40" />
    <file src="bin\Release\PutridParrot.Collections.dll" target="lib\netstandard1.6" />
  </files>  
</package>

Now run

nuget pack PutridParrot.Collections.nuspec

Notice we’re running nuget pack against our nuspec file instead and this will bring in two DLL’s and make them available to lib\net40 and lib\netstandard1.6 thus targetting two different .NET frameworks.

The following gives a list of valid Supported frameworks that we can assign.