I find NuGet to be pretty awesome. Even though it’s several years old, it still has that new car smell to me. We recently started using the NuGet Package Restore feature, which has helped improve our CI builds. But like leather bucketseats, the feature I’ve wanted to have for a few years is to create my own NuGet package.
Why Create Your Own NuGet Package
When is this useful? Do you have a library of utility functions that you want to share with others, or maybe one that you have used in multiple projects? We have a library of utility functions that most of our other projects use. Every time we make a change to this library, we have to manually copy the new DLL across all projects. Yuck. Manual process.
NuGet to the rescue! We can slap this library into a NuGet package, and then fork the new version easily through NuGet.
You will need three small pieces in order to create your first NuGet package:
- The NuGet.exe command line utility.
- The files you want to package (i.e. a class library).
- A specification (.nuspec) file. We’ll get to that in a minute.
Let’s Get Started
Starting with a simple example, let’s create a new Visual Studio solution.
- Create a new C# Class Library (File –> New Project –> Visual C# –> Class Library) called MyMathLibrary.
- In order to watch NuGet work it’s magic, let’s go ahead and create a class in here called MyMath, and give it a single static method, Sum.
- Build the solution. (you can use the default Debug solution configuration).
- We’re going to keep it simple and do all of our NuGet stuff in a separate folder. Create C:\Local-NuGet-Feed.
- Create a folder in here called output (we’ll get to this later).
- Add the NuGet.exe command line utility to the C:\Local-NuGet-Feed folder.
- Open the folder where the project you just created lives. Navigate to the output folder, bin/Debug, and grab the .dll file (MyMathLibrary.dll). Copy (or move) this file into C:\Local-NuGet-Feed folder.
- Create a blank file, and name it MyMathLibrary.nuspec.
The Specification File (.nuspec)
Let’s fill in our .nuspec file with some XML (thanks to Rick Shott for the original example):
<?xml version="1.0"?> <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> <metadata > <id>MyMathLibrary</id> <version>188.8.131.52</version> <authors>athenahealth</authors> <requireLicenseAcceptance>false</requireLicenseAcceptance> <description>A library of global-use math functions.</description> <language>en-US</language> <projectUrl>http://www.athenahealth.com/</projectUrl> <licenseUrl>http://www.athenahealth.com/license</licenseUrl> <tags>Awesomeness</tags> </metadata> <files> <file src="MyMathLibray.dll" target="lib" /> </files> </package>
Most of the metadata is self-explanatory (id, authors, description).
- The target attribute specified in the <file> tag is the folder where the file lives (either a relative or absolute path).
- You can use wildcards for the filename in the src attribute of the <file> tag. For example, if you specified My*.dll, the package would include all .dll files that start with My.
- There is one thing worth mentioning about the <version> tag. THIS value is what dictates when consumers see a new version of the package in NuGet. In other words, you can change the content of your files in the package, you can change the version number in the assemblies, but consumers will not see a new version until you change this value.
Creating the Package
Alrighty. Now we’ve got our .nuspec file, let’s create a package. For this, we’re going to use the NuGet.exe command line utility. Run the pack command like this:
nuget pack MyMathLibrary.nuspec -basepath lib\ -o output\
Bingo! You should now have a single .nupkg file in your output folder. You will also notice that NuGet generates the name of the .nupkg file by concatenating the values that you specify in the <id> and <version> tags in the .nuspec file.
Consuming the Package
After all, what good is our new call if we can’t smell the tires (am I the only one who likes the smell of new tires?) Ok, I digress.
All that we need to do to see our internal packages in NuGet Package Manager is add a new package source. It’s really that simple.
(In Visual Studio 2012, this is under Tools –> Options –> Library Package Manager –> Package Manager Settings). If you want to try out a cool new trick, just press Ctrl + Q in Visual Studio and type “package manager settings“; then Enter. Neato!
Choose “Package Sources”. Click the “+”, and give it an arbitrary name (i.e. Local Package Feed), and enter your local path to the .nupkg output files as the source, C:\Local-NuGet-Feed\output.
Now, open up Nuget Package Manager (or Ctrl+Q, “nuget package manger”, if you like). You will see your new package source listed in Online (right under nuget.org). Sweet.
Updating the Package
Let’s watch NuGet do it’s magic, shall we? Create a new project in Visual Studio (this time a Console Application), and call it NuGetTester. Use NuGet Package Manager (Ctrl+Q coming in handy yet?), and add the MyMathLibrary package.
Expand References, and then double-click on MyMathLibrary to open the library reference in the Object Browser. You can see that there is one class, Math, with one static method, Sum.
Return to MyMathLibrary, and now let’s add a second method, Product. Build the project and copy the .dll into our NuGet feed folder. REMEMBER that we need to change the version in the .nuspec file. Open MyMathLibrary.nuspec increment the version number to 184.108.40.206. Run the pack command again.
Return to NuGetTester, and open NuGet Package Manager. If we look at our Local Feed, we see that we can now install the update to MyMathLibrary, and we also see that it’s on version 220.127.116.11. If you examine the reference again in Object Browser, you see our new Product method in MyMath class. Score.
Hosting the Package Feed
A locally-hosted feed may not be terribly useful, so I’m sure most of you want to host your internal packages on a server. As long as the folder contains the .nupkg files, that folder can live wherever you want it to.
The simplest solution that I would recommend is to create a share folder on a server (i.e. a build server is a great idea). This is a great way to get up and running quickly.
Another neat little trick is to try running post-build commands to automatically move your .dll files automatically to the NuGet feed folder, then automatically kick off a nuget pack command. Now throw this on a build server, trigger it after your CI builds, and it’s even cooler.