Creating a NuGet package

Creating a NuGet package can be done using two different tools: NuGet Package Explorer simplifies manual creation, while the command line tool NuGet.exe is useful when automating package creation as part of build scripts and the like. The following article focuses on the latter. Examples are based on NuGet 1.7.

Reason

NuGet has excellent version and dependency handling capabilities, which can simplify code reuse and module management across solutions.

Code

NuGet packages are defined by so called package manifests. These are simple documents in XML format which contain a package ID, version and author information etc., much like csproj-files do for Visual Studio C# projects. Package manifests have a “.nuspec” file extension.

The markup is fairly self explanatory:

<?xml version="1.0"?>
<package>
  <metadata>
    <id>Reason.Code.Example.NuGetPackage</id>
    <version>1.0.0</version>
    <authors>Uli Weltersbach</authors>
    <owners>Reason→Code→Example</owners>
    <requireLicenseAcceptance>true</requireLicenseAcceptance>
    <licenseUrl>https://reasoncodeexample.com/license</licenseUrl>
    <description>
      NuGet package example.
    </description>
    <copyright>Copyright 2012</copyright>
    <tags>Reason→Code→Example, NuGet example</tags>
    <language>en-US</language>
    <!-- Framework dependency -->
    <frameworkAssemblies>
      <frameworkAssembly assemblyName="System.Xml.Linq" targetFramework="net40" />
    </frameworkAssemblies>
    <!-- NuGet package dependency -->
    <dependencies>
      <dependency id="Reason.Code.Example.OtherNuGetPackage" version="2.0.1" />
    </dependencies>
  </metadata>
  <!-- Example of explicit file inclusion -->
  <files>
    <file src="[SomeProjectRoot]\bin\release\*.dll" target="lib\net40" />
    <file src="[SomeProjectRoot]\**\*.cs" target="content\source code" exclude="AssemblyInfo.cs;IrrelevantSource.cs" />
  </files>
</package>

Required framework assemblies

The “frameworkAssemblies”-node can contain anything that’s been installed in the global assembly cache – the files are not added to the NuGet package itself when it’s created, but added as references once the package is installed in a project.

NuGet dependencies

The example package depends on “Reason.Code.Example.OtherNuGetPackage” as specified in the “dependencies”-node. NuGet will automatically download and install all dependencies as required.
When defining dependencies, compatible versions or version ranges can be specified by following the notation described in versioning.

Package contents

The contents of a NuGet package, beside its metadata, are either defined using an implicit folder structure relative to the location of the package manifest, or explicitly by using the “files”-node.
Using the implicit (convention based) folder structure requires the following:

To create a package in this way, you can layout a directory structure that follows the NuGet conventions.

  • tools – The tools folder of a package is for powershell scripts and programs accessible from the Package Manager Console. After the folder is copied to the target project, it is added to the `$env:Path (PATH) environment variable.
  • lib – Assemblies (.dll files) in the lib folder are added as assembly references when the package is installed.
  • content – Files in the content folder are copied to the root of your application when the package is installed.

Think of the Content folder as the root of your target application. For example, if I want to a package to add an image in the /images directory of the target application, make sure to place the image in the Content/images folder of the package.

Working with the “files”-node is similar to using file based tasks in MSBuild and NAnt, i.e.  various filtering mechanisms can be used to include or exclude files. Each “file”-node contains a “src” and “target” attribute specifying which file or set of files to include, and where to place them within the NuGet package.
In the example manifest shown above, all DLL files in the “release” build target binary folder are added to the “\lib\net40” folder, and all C# source files, except “AssemblyInfo.cs” and “IrrelevantSource.cs”, are added to the “\content\source code” folder.
Note that the use of the “files”-node overrides the convention based folder inclusion: if the “files”-node exists in the package manifest, NuGet ignores the contents of the convention based folders.

Targeting specific .NET Framework versions

By following NuGets framework version folder structure, it’s possible to include assemblies targeting multiple .NET framework versions in a single package. The following is an example of how to nest and name folders and files for .NET 3.5 and 4.0:

  • \lib
    • \net35
      • \Reason.Code.Example.dll
    • \net40
      • \Reason.Code.Example.dll

A complete description of all manifest file elements can be found in the nuspec reference.

Package creation

Once the package contents are in place, it’s a simple matter of opening a command prompt and typing “nuget pack [package manifest name]” to create it, assuming NuGet.exe has been added to the path environment variable and that the current directory contains the package manifest file. See below for an example.

Example

Consider the following file and folder structure:

  • [package root folder]
  • Example.Package.nuspec
  • lib\
    • net40\
      • Reason.Code.Example.NuGetPackage.dll
  • content\
    • source code examples\
      • SomeClass.cs
      • Tutorial.docx

The nuspec-file contains the following manifest:

<?xml version="1.0"?>
<package>
  <metadata>
    <id>Reason.Code.Example.NuGetPackage</id>
    <version>1.0.0</version>
    <authors>Uli Weltersbach</authors>
    <owners>Reason→Code→Example</owners>
    <description>NuGet package example.</description>
    <requireLicenseAcceptance>true</requireLicenseAcceptance>
    <licenseUrl>https://reasoncodeexample.com/license</licenseUrl>
    <dependencies>
      <dependency id="Reason.Code.Example.OtherNuGetPackage" version="2.0.1" />
    </dependencies>
  </metadata>
</package>

Since no “files”-node is declared, NuGet uses convention based folders. Building the package using NuGet.exe is straight forward:

Creating a NuGet package

In case NuGet has not been added to PATH and/or the package root is not the working directory, simply specify fully qualified paths (i.e. “Full\NuGet\Path\NuGet.exe” pack “Full\Package\Path\[manifest file name].nuspec”).

Once completed NuGet will have created a ready to deploy “nupkg”-file, named based on the ID and version specified in the package manifest.

2 thoughts on “Creating a NuGet package

  1. Found this article at just the right time when I had a nuspec file using the files node and becoming confused about why the files in the content folder weren’t copied over when I installed the package. This made it very clear why that wasn’t working. Thanks!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s