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.
NuGet has excellent version and dependency handling capabilities, which can simplify code reuse and module management across solutions.
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.
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.
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:
A complete description of all manifest file elements can be found in the nuspec reference.
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.
Consider the following file and folder structure:
- [package root folder]
- source code examples\
- source code examples\
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:
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.