How To Create NuGet Packages

Today’s header image was created by Daniel McCullough at Unsplash
What Is a nuspec File?
Firstly a little about NuGet packages. You’ll have heard of these, I’m sure
you’ve been using them throughout your .NET Core journey so far – all of the System namespaces are NuGet packages
They are the .NET equivalent of NPM packages, in that .NET developers can encapsulate entire libraries into a single package file which can be added to a project to provide access to the methods and classes that the libraries expose.
No doubt you’ll have all heard of NewtonSoft.Json, which is arguably the most famous of NuGet packages.
But how do we encapsulate everything into a NuGet package? And why bother, if we can get the source from GitHub (or similar)?
I’ll answer with another question: Say you’re creating the greatest app in the world, do you really want to have to pull down each library from GitHub, build them, and pull the DLLs into your project? Surely
I’m deadly serious, and don’t call me… you get the joke
that would cause all sorts of headaches – not least of which would be keeping all of the DLLs in sync with their source repos. So why not have the original developers of those libraries do the hard work for you?
Releasing code into a single package, which can be added to a solution and built alongside your code, you take all of the headaches away
not all of them, but the majority anyway
Plus the libraries that you pull down will be built for the architecture that your solution targets – because Visual Studio is ace like that.
Anyway, less about NuGet packages for now. More about nuspec files.
nuspec Files
A nuspec file is an XML file which describes what the contents of a NuGet package should be. It is described in the Microsoft documentation as:
an XML manifest that contains package metadata. This manifest is used both to build the package and to provide information to consumers. The manifest is always included in a package
source: https://docs.microsoft.com/en-us/nuget/reference/nuspec
It is used by the nuget and dotnet pack command line applications to package up a code base into a NuGet package file. NuGet packages can also be generated within Visual Studio, too
there are a bunch of different downloads for NuGet tooling here
My choices are pretty limited, however. This is because I run Ubuntu and Mac OS X on my development machines at home. Specifically why I do this is beside the point, but it’s important to know what tooling is available for which operating systems.
- If you’re running Windows, then you can use anything.
- If you’re running a Linux distribution, then you can use either dotnet pack or nuget
assuming that you install Mono first
- If you’re running Mac OS X, then you can use dotnet pack
whilst it’s possible to run nuget on Mac OS X, I’ve not attempted it
Creating And Consuming A nuspec File
Since a nuspec file is an XML formatted plain text file you can, technically, use any text editor to create one. I prefer to use Visual Studio Code to create and edit them as it’s light weight, has autocomplete, and is very fast. But feel free to use what ever you’d like.
In order to create a nuspec file (assuming you’ve opened your code directory in Visual Studio Code), click on the new file button:

Then give it a useful name. I tend to go with “<the name of the project>.nuspec”, but feel free to follow whatever format you wish:
Then it’s a case of looking through the documentation and creating a file with the relevant tags. Simple, right?
… What are the relevant tags? Let me talk you through the nuspec file for my OnionAcrh project.
The nuspec File
The first thing you’ll need to do is make yourself familiar with the layout of my OnionArch project layout in the image above
or you can take a look at the code in the GitHub repo for it
The hierarchy of the project looks like this (from top to bottom):
- Onion.Web
- Onion.Service
- Onion.Repo
- Onion.Data
The entry point for the application is Onion.Web which has references to each of the other layers. Onion.Service has references to Repo and Data, and Repo has a reference to Data. A graphical representation of the project layout would look like this:
As such, the nuspec file will have to retain that directory layout.
Now that we have an idea of the layout, lets take a look at the nusepc file
because I can tell how excited you are to see it
<?xml version="1.0" encoding="utf-8"?> | |
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd"> | |
<metadata> | |
<id>OnionArch.Mvc</id> | |
<title>OnionArch.Mvc</title> | |
<version>0.0.3</version> | |
<iconUrl>https://raw.githubusercontent.com/GaProgMan/OnionArch/master/onionArch-nuget-logo.png</iconUrl> | |
<description> | |
ASP.NET Core MVC using the onion architecture and feature folders | |
</description> | |
<summary> | |
Creates a new ASP NET Core MVC application using the onion architecture and feature folders | |
</summary> | |
<requireLicenseAcceptance>false</requireLicenseAcceptance> | |
<authors>Jamie Taylor</authors> | |
<copyright>Copyright © Jamie Taylor 2018</copyright> | |
<licenseUrl>https://raw.githubusercontent.com/GaProgMan/OnionArch/master/LICENSE</licenseUrl> | |
<projectUrl>https://github.com/GaProgMan/OnionArch</projectUrl> | |
<tags>Template, AspNet, Mvc, onion architecture, feature folders</tags> | |
</metadata> | |
<files> | |
<file src="template.config/*" target="src/.template.config" /> | |
<file src="Onion.*/**" exclude="Onion.*/obj/**" target="src" /> | |
<file src="OnionArch.sln" target="src" /> | |
<file src="README.md" target="src" /> | |
<file src=".idea/**" exclude="*" /> | |
<file src=".git/**" exclude="*"/> | |
<file src="./**" exclude="*.png" /> | |
<file src="./**" exclude="*.svg" /> | |
</files> | |
</package> |
There’s an awful lot going on here, so let’s break it down into logical chunks.
Metadata
The metadata section contains… well, metadata about the NuGet package that we’ll create.
<id>OnionArch.Mvc</id> | |
<title>OnionArch.Mvc</title> | |
<version>0.0.3</version> | |
<iconUrl>https://raw.githubusercontent.com/GaProgMan/OnionArch/master/onionArch-nuget-logo.png</iconUrl> | |
<description> | |
ASP.NET Core MVC using the onion architecture and feature folders | |
</description> | |
<summary> | |
Creates a new ASP NET Core MVC application using the onion architecture and feature folders | |
</summary> | |
<requireLicenseAcceptance>false</requireLicenseAcceptance> | |
<authors>Jamie Taylor</authors> | |
<copyright>Copyright © Jamie Taylor 2018</copyright> | |
<licenseUrl>https://raw.githubusercontent.com/GaProgMan/OnionArch/master/LICENSE</licenseUrl> | |
<projectUrl>https://github.com/GaProgMan/OnionArch</projectUrl> | |
<tags>Template, AspNet, Mvc, onion architecture, feature folders</tags> | |
</metadata> |
There’s nothing particularly exciting here, but it’s useful to fill this information in (especially the id, version, description, and authors fields as they are required). Otherwise when you upload the package to NuGet, you’ll have to fill the corresponding fields in anyway
as Scott Hanselman said, “I only have so many key strokes in my fingers”
(i.e. “programmers are lazy”)
Potentially the most interesting parts are the tags and url… er, tags:
<iconUrl>https://raw.githubusercontent.com/GaProgMan/OnionArch/master/onionArch-nuget-logo.png</iconUrl> | |
<description> | |
ASP.NET Core MVC using the onion architecture and feature folders | |
</description> | |
<summary> | |
Creates a new ASP NET Core MVC application using the onion architecture and feature folders | |
</summary> | |
<requireLicenseAcceptance>false</requireLicenseAcceptance> | |
<authors>Jamie Taylor</authors> | |
<copyright>Copyright © Jamie Taylor 2018</copyright> | |
<licenseUrl>https://raw.githubusercontent.com/GaProgMan/OnionArch/master/LICENSE</licenseUrl> | |
<projectUrl>https://github.com/GaProgMan/OnionArch</projectUrl> | |
<tags>Template, AspNet, Mvc, onion architecture, feature folders</tags> |
The url tags (iconUrl, licenseUrl, projectUrl) are used to link to external files on the NuGet listing page:

if you want to see it for yourself, you can click here
I couldn’t figure out how to auto populate the Documentation area, via a nuspec file. But we’ll come to filling that in, in a few moments.
Files
This is where the important stuff goes. Without filling in some of the metadata
id, version, description, and authors are required fields
you could still upload the NuGet file – you’d have to fill the relevant fields in manually, though. But without the files section, the rendered NuGet package would be useless.
The first thing to remember here is that we only want to include source code in the nuget package. The reason for this is that the contents of the NuGet files are meant to be built alongside the source of projects which consume them.
So let’s take a look at the files section of the nuspec file:
<files> | |
<file src="template.config/*" target="src/.template.config" /> | |
<file src="Onion.*/**" exclude="Onion.*/obj/**" target="src" /> | |
<file src="OnionArch.sln" target="src" /> | |
<file src="README.md" target="src" /> | |
<file src=".idea/**" exclude="*" /> | |
<file src=".git/**" exclude="*"/> | |
<file src="./**" exclude="*.png" /> | |
<file src="./**" exclude="*.svg" /> | |
</files> |
Remember that I asked you to make sure that you had the layout of the OnionArch project in your mind? Here’s why.
Including Files
The first four lines are used to add files to the NuGet package.:
<files> | |
<file src="template.config/*" target="src/.template.config" /> | |
<file src="Onion.*/**" exclude="Onion.*/obj/**" target="src" /> | |
<file src="OnionArch.sln" target="src" /> | |
<file src="README.md" target="src" /> | |
<file src=".idea/**" exclude="*" /> | |
<file src=".git/**" exclude="*"/> | |
<file src="./**" exclude="*.png" /> | |
<file src="./**" exclude="*.svg" /> | |
</files> |
I’ve highlighted them, here
Each line is a directive telling nuget or dotnet pack to grab any file which matches the pattern we supply in the src attribute and store it in a path (within the rendered NuGet package) which we supply in the target path.
For example, the following line:
<file src="Onion.*/**" exclude="Onion.*/obj/**" target="src" /> |
tells nuget or dotnet pack to look for any files within a path which matches on the string “Onion.*” and add them to a directory within the NuGet file called “src”
we’ll cover the exclude attribute in a moment
In the above image, I’ve opened the rendered NuGet package
which is just a zip file, by the way
and navigated to the /src/Onion.Web directory (on the right) to show you that it contains the same files that the Onion.Web directory on disk does (on the left). That is, with the exception of the bin and obj directories.
Excluding Files
The next four lines of the nuspec tell nuget or dotnet pack which files to exclude:
<files> | |
<file src="template.config/*" target="src/.template.config" /> | |
<file src="Onion.*/**" exclude="Onion.*/obj/**" target="src" /> | |
<file src="OnionArch.sln" target="src" /> | |
<file src="README.md" target="src" /> | |
<file src=".idea/**" exclude="*" /> | |
<file src=".git/**" exclude="*"/> | |
<file src="./**" exclude="*.png" /> | |
<file src="./**" exclude="*.svg" /> | |
</files> |
It’s a similar idea to the include directives, except that it works slightly differently.
Essentially the “src” attribute works the same way, but the “exclude” tag includes a pattern for files which we want to exclude from that directory. Take this line, for instance:
<file src=".git/**" exclude="*"/> |
What this does is ensure that your .git directory
which contains, among other things, the entire history of your repo
is excluded from the NuGet package.
In the above image, I’ve opened the NuGet package (in the foreground) and shown the source directory (in the background) to show that my rule for excluding all files from the “.git” directory is working.
That’s really all there is to nuspec files.
Excluded, The Refrain
You’ll have noticed that I didn’t cover everything that following line of the nuspec file does, earlier:
<file src="Onion.*/**" exclude="Onion.*/obj/**" target="src" /> |
That was because I thought it best to talk about excluding files first. Hopefully now that I’ve gone over what the “exclude” attribute does, you should be able to tell what it does.
Don’t fret if you don’t quite get what it’s doing. I’ll explain it now by breaking it down into chunks, one attribute at a time:
-
src="Onion.*/**"
The pattern here says that we should look at all directories in the root which start with “Onion” – which is what the “Onion.*” part does
for those who don’t know, the * character can be thought of as the wildcard character
It then says that we should recursively look at all of the sub-directories of the Onion.* directories.
This pattern ensures that we get all of the files and sub-directories in the following directories:
- Onion.Web
- Onion.Service
- Onion.Repo
- Onion.Data
It does this for each of the above directories in turn – kind of like a foreach.
-
exclude="Onion.*/obj/**"
The pattern here says that we should ignore any files and sub-directories that we find in any obj sub-directories found in the current Onion.* directory.
This means that we’ll never end up with any of the obj files in our rendered NuGet package.
remember, our NuGet package needs to only contain the resources needed to build our project
-
target="src"
This pattern says that we should take all of the files and sub-directories we found by the “src” pattern, but not any that we found in the “exclude” pattern and store them in a directory called “src” within the rendered NuGet package.
How Do I Render a NuGet Package From a nuspec file?
I’ve alluded to this several times so far: What you need to do is use either the nuget or dotnet pack commands – head back up to the top of this post to see where you can get these commands from
psst… dotnet pack is built into the .NET Core SDK
nuget
Using the nuget command is easy. Assuming that you’re terminal is in the same directory of the nuspec file, simply run the following command:
nuget pack OnionArch.nuspec |
This package everything in your source code up, based on the contents of the nuspec file, and produce a file called “OnionArch.Mvc.0.0.3.nupkg”
I’m assuming that you’re running these commands against the OnionArch repo. The file name will be different, based on your repo
dotnet pack
You can also use the .NET Core SDK to package everything up. The following command (when run from the root of the above repo) will do that:
dotnet pack ./Onion.Web/Onion.Web.csproj --configuration Release --no-build --no-restore --output nupkgs /p:NuspecFile=OnionArch.nuspec |
The same thing will happen, except that the .NET Core SDK will do all of the hard work for you.
Where I Have Used Them
All this bleating on about nuspec files is all well and good, but where are the real life examples? Well, we just built one.
ClackMiddlware and OwaspHeaders.Core
These two projects are ASP.NET Core Middleware and are packaged and deployed to NuGet automatically, whenever I commit to their master branches. At the time of writing, OnionArch.Mvc is packaged and uploaded to NuGet manually – I plan to make this automatic, but it’s not at the top of my priorities list at the moment.
What are they, you ask?
- ClacksMiddlware adds the X-GNU-Pratchett HTTP header to all responses
- OwaspHeaders.Core adds the OWASP recommended HTTP headers to all responses
as you’re about to see, OnionArch.Mvc includes both of these middleware packages via command line switches
OnionArch.Mvc
If you go and take a look at this GitHub repo and this NuGet package, you’ll find the nuspec file we just created. How cool is that?
Oh, I forgot to say. That project is for a ASP.NET Core MVC template that I’ve been working on for a while
you might remember that I mentioned it back in October of 2017
You should totally check it out if you’re at all interested in the templating engine, the onion architecture or domain driven design. It’s incredibly easy to install, too. Since it’s on Nuget, you can do
dotnet new --install OnionArch.Mvc |
at the command line
as per these instructions
and the dotnet SDK will take care of the rest: it’ll get the latest version from NuGet and install it for you.
You should see something like the following output:
Installing OnionArch.Mvc 0.0.4. | |
... | |
Templates Short Name Language Tags | |
-------------------------------------------------------------------------------------------------------- | |
Console Application console [C#], F#, VB Common/Console | |
Class library classlib [C#], F#, VB Common/Library | |
Unit Test Project mstest [C#], F#, VB Test/MSTest | |
xUnit Test Project xunit [C#], F#, VB Test/xUnit | |
Razor Page page [C#] Web/ASP.NET | |
MVC ViewImports viewimports [C#] Web/ASP.NET | |
MVC ViewStart viewstart [C#] Web/ASP.NET | |
ASP.NET Core Empty web [C#], F# Web/Empty | |
ASP.NET Core Web App (Model-View-Controller) mvc [C#], F# Web/MVC | |
Onion Architecture MVC onionArch [C#] Web/MVC | |
ASP.NET Core Web App razor [C#] Web/MVC/Razor Pages | |
ASP.NET Core with Angular angular [C#] Web/MVC/SPA | |
ASP.NET Core with React.js react [C#] Web/MVC/SPA | |
ASP.NET Core with React.js and Redux reactredux [C#] Web/MVC/SPA | |
ASP.NET Core Web API webapi [C#], F# Web/WebAPI | |
global.json file globaljson Config | |
NuGet Config nugetconfig Config | |
Web Config webconfig Config | |
Solution File sln Solution |
And to see how to use it, issue the following command:
dotnet new onionArch --help |
Which should return something like the following:
Onion Architecture MVC (C#) | |
Author: Jamie Taylor | |
Options: | |
-egp|--enable-gnu-pratchett Whether to include and activate middleware which will include the X-GNU-Pratchett header in all requests | |
bool - Optional | |
Default: false / (*) true | |
-esh|--enable-secure-headers Whether to include and activate middleware which will include a range of OWASP suggested security headers | |
bool - Optional | |
Default: false / (*) true |