In an unexpected turn of events, this post is about the pitfalls I’ve encountered whilst publishing ConTabs to NuGet. My decision to make ConTabs a .NET Standard library has meant this was more complicated than I had anticipated. In this post, I’ll start by explaining the old .NET Framework approach and go on to show the new .NET Standard / Core way of doing things. Finally, I’ll talk about some unexpected guests that turned up when I tried to consume my new NuGet package.
NuGet packages are simply zip files containing binaries and/or “content files” (assets, source code, etc.) along with a specification and some metadata files. Don’t believe me? Try changing the extension from “.nupkg” to “.zip” and then open it. (Once you’ve convinced yourself they’re just zips, go download NuGet Package Explorer for a much nicer way to explore packages.)
In a purely .NET Framework work, the way to create these magical zip files was to use nuget.exe. You’d steer your console to your project root and then run nuget spec to generate a skeleton “.nuspec file”. Next, you’d then edit that specification and then run nuget pack, which bundles everything up into a “.nupkg”. Finally, you’d toddle over to the upload page on NuGet.org and submit your package to the gallery. Easy, right?
.NET Standard / Core
When I tried the above for ConTabs, I was able to do the first bit, but got a weird error for nuget pack:
Unable to cast object of type 'System.String'
to type 'NuGet.Frameworks.NuGet.Frameworks1069249.NuGetFramework'.
This has to be one of the least helpful error messages in history. Luckily, a quick search revealed that this is caused by the fact that nuget.exe doesn’t support .NET Standard or .NET Core projects.
So, to create a “.nupkg” file from a .NET Standard or Core project, take the following steps instead:
- Add the package specification inside the .csproj file.
- Run msbuild /t:pack in the project root, from a developer console
You should now have a “.nupkg” file – ready to upload to nuget.org in the same way as for .NET Framework projects. More detailed guidance is available in the NuGet docs.
UPDATE: There’s a workaround – see my newer post.
Naturally, once I’d published my package to the NuGet gallery, I wanted to try it out. So I created a fresh .NET Framework console application in Visual Studio, launched the package manager, and installed ConTabs. What happened next blew my mind a little bit – a total of 47 packages were installed (gist of output). In other words, my single .NET Standard library had brought 46 dependencies with it!
(Interestingly, I don’t get any of this extra baggage when I install ConTabs onto a .NET Core project.)
What was going on? Surely the point of targeting .NET Standard was to reduce dependencies by relying on a common platform? I was pulling my hair out, so I did what I normally do when I’m bamboozled – I turned to Stackoverflow.
User Martin Ullrich came to my aid with a great answer outlining the history that’s lead to this situation. For the purposes of this blog post, allow me to share a highly pertinent snippet:
If you want nothing more than your own DLL being added to a new .NET Framework project, you have to target .NET Standard 2.0 for your library wait for a .NET Framework version that natively supports both the API and assembly versions – which is going to be 4.7.2.
Essentially, it sounds like .NET Framework isn’t yet fully aligned with .NET Standard. The way that support for the .NET Standard “contract” has been historical delivered is with a “meta-package”, which has dependencies on all the required support libraries. These were the libraries that I was seeing when I was installing ConTabs onto a .NET Framework project.
So it looks like I’ll be waiting until .NET Framework version 4.7.2 for ConTabs to work seamlessly across all flavours of .NET. Since 4.7.1 was only released in October of this year and given releases seems to come around almost annually, we may be waiting a while for this to come about.
This isn’t the blog post I’d been hoping to write. I had planned on doing one post on my decision to target .NET Standard (in fact, I still might) and another on publishing to NuGet. Instead, I’ve found myself writing about the intersection of these: the difficulties of publishing .NET Standard libraries to NuGet.
The issue with the tooling is easy enough to cope with (once you know how), but the number of dependencies required to add a .NET Standard library to a .NET Framework project still leaves a bad taste in my mouth. I’ll be very pleased when .NET Framework version 4.7.2 arrives so that we can truly realise the nirvana of fully portable libraries.
On a more positive note, my little old ConTabs package has already had 23 downloads and only 2 of these were me! For a package that’s had no “marketing” and lacks any sort of documentation, that seems pretty good.
If you want to contribute to ConTabs, head over to the repo on GitHub. If you’d like to give it a go, install it with your package manager of choice:
Install-Package ConTabs.tdwright -Version 0.1.0
If you’ve any thoughts on my dependency dilemma, please leave a comment!