You know what I ‘m talking about. You want to put that method that sends an email, or that Key/Key Pair dictionary thing the you stole from Jon Skeet’s blog somewhere for all of your colleagues to use and bask in your reusable API glory. The question is, where do you put it? On a server share? Checked in to source control? On a mapped drive that everyone has? I suppose, but how are you going to version it? How are you going to let the people referencing upgrade? How are you going to handle breaking changes? Dependency Management? Well, here is my opinion: Nuget to the rescue. If you are sharing any code in your organization, hosting an internal Nuget feed is a great way to do that. Get this set up early and have your CI build continue to publish packages and you can add and share code as quickly as your build server can build it (and run the tests of course).
I have used the integrated Nuget server in TeamCity before, and I have to admit, it’s pretty awesome (minus managing packages, as of this date that still sucks since you can’t issue Nuget.exe commands to it). For the purposes of this post, however, for those that aren’t running TeamCity or want a process that isn’t married to a third party, we will talk about setting one up from scratch.
Before we get in to putting the package somewhere, lets go over creating the package in the first place. So, you have your assembly:
The first thing you need to do is create a nuspec file. You can generate this by “nuget spec” in the same folder as your csproj (I just put a copy of Nuget.exe in the same folder to make it easy):
All that does is generate a nuspec file for you, but if you ask me, it’s pretty weak in terms of actually doing anything for you specific to this project. Maybe its more useful if as part of your build process you are generating a new nuspec file every time and using this text as wildcards to what you would replace. Honestly, for now, you can just copy this and and start from there:
<?xml version="1.0"?> <package > <metadata> <id>$id$</id> <version>$version$</version> <title>$title$</title> <authors>$author$</authors> <owners>$author$</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>$description$</description> <releaseNotes>Summary of changes made in this release of the package.</releaseNotes> <copyright>Copyright 2013</copyright> <tags>Tag1 Tag2</tags> </metadata> </package>
Those $variable$ replacement tokens come from your AssemblyInfo.cs, so make sure that it populated, or just hard code the values instead (we will pass the version into the pack command):
Also, IT IS IMPORTANT THE THE NUSPEC FILE IS THE SAME NAME AS THE CSPROJ. That will come in to play when we package this sucker. It is a convention thing, and it bit me pretty good when I tried to do this for the first time.
Time to pack it up. There are MSBuild targets for this as well, but since we have that Nuget.exe right there, we can call “nuget pack” (if you don’t have that, you can pass it a csproj after the word ‘pack’). In this case we are going to use a few of the optional command line arguments to 1. build the package before packaging 2. Produce debug symbols 3. Build in release mode 4. Specify a version. You can specify an OutputDirectory, but it will use the current directory if you don’t specify.
So, “nuget pack –Build –Symbols -Properties Configuration=Release –Version 18.104.22.168”
You will have some warnings that you haven’t filled everything out properly, and you can take care of that if you’d like.
Viola! We have a package! (and symbols, which is great for an internal Nuget feed since you most likely own the code and will want to debug)
Now, where to put it?
Let’s start with setting up an internal server. There are 2 ways to do this:
1. a network share (simple, but may have some performance and security complications)
2. a remote feed through an IIS website (probably best, but has a little bit more of a startup effort to implement)
#1 – A Network Share
Create a share somewhere and put your packages in it.
In Visual Studio – Go to Tools > Options > Package Manager > Package Sources. Add a name and a UNC share location:
Now you can consume it in your project that needs it. First things first, make sure you have this checked:
Then you can right click on your project, and Manage Nuget Packages:
When you install, you will get a reference to Holeshot.Utility, a packages.config, and a .nuget folder (if you have Restore Nuget Packages on, which I think you will). Open the NuGet.targets and make sure RestorePackages is true and DownloadNuGetExe is true. Make sure that the Nuget.exe is NOT checked in to source control, as it will download a new copy every time if it needs to.
There you have it, the next time a new Holeshot.Utility is put in the network share, your Holeshot.ProjectThatNeedsUtility will notify you that there has been an update to your reference, and you have the option to take the new version. Herein lies one of the biggest advantages of this process. It puts the product owners back in charge. Don’t want to take the upgrade now because the Minor version changed and that indicates a possible breaking change? Then don’t take it. When you are ready, take it, correct any compilation errors (if any), run your tests, and you are in business with a potentially effortless upgrade.
#2 – A remote feed in IIS
If you have a build server, TFS server, or some other computer that is publicly accessible, that will do the trick. It’s not like it needs to be a beefy machine.
First, create an Empty ASP.NET Web Application, and install Nuget.Server from the Manage Nuget Packages console. Notice how it resolves all of its own dependencies (Elmah, Ninject, about 25 others, etc.). You can have that too in your packages using this process and specifying dependencies in your nuspec file, but that is another post.
Now you will have this. Notice the packages folder, that is where your packages need to go now.
Go to the web.config and specify an API key:
Publish and browse to the web site:
Now we can either push to the feed, or just copy the packages to the folder specified above:
There you have it. I did all of this while documenting in a matter of 2 hours. Well worth the effort if you ask me.