A Caveat with NuGet Source Code Packages

git, github, code 0 comments suggest edit

The other day I needed a simple JSON parser for a thing I worked on. Sure, I’m familiar with JSON.NET, but I wanted something I could just compile into my project. The reason why is not important for this discussion (but it has to do with world domination, butterflies, and minotaurs).

I found the SimpleJson package which is also on GitHub.

SimpleJson takes advantage of a neat little feature of NuGet that allows you to include source code in a package and have that code transformed into the appropriate namespace for the package target. Oftentimes, this is used to install sample code or the like into a project. But SimpleJson uses it to distribute the entire library.

At first glance, this is a pretty sweet way to distribute a small single source file utility library. It gets compiled into my code. No binding redirects to worry about. No worries about different versions of the same library pulled in by dependencies. In my particular case, it was just what I needed.

But I started to think about the implications of such an approach on a wider scale. What if everybody did this?

The Update Problem

If such a library were used by multiple packages, it actually could limit the consumer’s ability to update the code.

For example, suppose I have a project that installs the SimpleJson package and also the SimpleOtherStuff package, where SimpleOtherStuff has a dependency on SimpleJson 1.0.0 and higher. The following diagram outlines the NuGet package dependency graph. It’s very simple.

nuget-dependency-graph

Now suppose we learn that SimpleJson 1.0.0 has a very bad security issue and we need to upgrade to the just released SimpleJson 1.1.

So we do just that. Everything should be hunky dory as we’re now using SimpleJson 1.0.0 everywhere. Or are we?

nuget-dependency-graph-2

If all the references to SimpleJson were assembly references, we’d be fine. But recall, it’s a source code package. Even though we upgraded it in our application, SimpleOtherStuff 1.0.0 has SimpleJson 1.0.0 compiled into it.

There’s no way to upgrade SimpleOtherStuff’s reference other than to wait for the package author to do it or to manually recompile it ourselves (assuming the source is available).

You Are in Control

A guiding principle in the design of NuGet is we try and keep you, the consumer of the packages, in control of things. Want to uninstall a package even though other packages reference it? We’ll prevent it by default but then offer you a –Force flag so you can tell NuGet, “No really, I know what I’m doing here and am ready to face the consequences.”

We don’t do this perfectly in every case. Pre-release packages come to mind. But it’s a principle we try to follow.

Source code packages are interesting in that they give you more control in one area (you have the source), but take it away in another (upgrades are no longer complete).

Note that I’m not picking on SimpleJson. As I said before, I really needed this. In fact, I contributed back with several Pull Requests. I’m just pointing out a caveat to consider when using such packages.

Making it Better

So yeah, be careful. There are caveats. But couldn’t we make this better? Well I have an idea. Ok, it’s not my idea but an idea that some of my coworkers and I have bounced around for a while.

Imagine if you could attach a Git repository to your NuGet package. When you install the package, you could add a flag to install it as a Git Submodule rather than the normal assembly approach. Maybe it’d look like this.

Install-Package SimpleJson –AsSource

What this would do is initialize a submodule, and grab the source from GitHub. Perhaps it goes further and adds the files as linked files into your target project based on a bit of configuration in the source tree.

There’s a lot of possibilities here to flesh out. The Upgrade-Package command simply run a Git update submodule command on these submodules and do a normal update for all the other packages.

Since Microsoft recently made it clear that Git is the future of DVCS as far as Microsoft is concerned, maybe now is the time to think about tighter integration with NuGet. What do you think?

At the very least, perhaps NuGet needs a better extensibility model so we could build this support in outside of NuGet. That’s the more prudent approach of course, but I’m not feeling so prudent today.

Found a typo or error? Suggest an edit! If accepted, your contribution is listed automatically here.

Comments

avatar

12 responses

  1. Avatar for Joe Wood
    Joe Wood February 10th, 2013

    Yeah, sub-module approach is a great idea.  But would it also replace the namespace ? What about the issues with sub module dependency collisions (when two usable packages, use the same submodule but at different revisions?).

    These are similar to the problems that the Boost people are looking at with the ryppl project, modularizing Boost in GitHub.  They ended up using cmake and 0install, with ryppl binding it all together.  It would be great if a good Nuget/GitHub solution could also solve the C++ package management problem in a more cleaner way.

  2. Avatar for Daniel15
    Daniel15 February 10th, 2013

    Distributing source code with NuGet is an interesting idea that I hadn't considered in the past. 

    As for JSON, I wonder if you could extract the JSON parsing code from System.Web.Helpers... I've used it in the past and it seems to work well

  3. Avatar for Michael Lang
    Michael Lang February 10th, 2013

    What about using sourcecode packages for MVC controllers, models, and views?

    Do you see any problems with creating a bootstrap Mvc application built from code purely made of NuGet packages.
    http://candordeveloper.com/...

  4. Avatar for Michael Lang
    Michael Lang February 10th, 2013

    Any thoughts on source code packages for MVC controllers, models, and views?

    I am in the process of creating a bootstrap type MVC template built on NuGet packages for all the included source, or at least as much of the code as makes sense.
    http://candordeveloper.com/...

  5. Avatar for Michael Lang
    Michael Lang February 10th, 2013

    sorry for the double post.  I thought I lost the first one I typed after I logged in.  Delete the first one not posted by my twitter id, plus this meta comment.

  6. Avatar for giacomo (@gsscoder)
    giacomo (@gsscoder) February 10th, 2013

    Hi @haacked,
    your idea of git submodule with nuget is very interesting.
    I faced a similar dilemma but from author perspective.
    Anyway I think that as you said when the problem is 'small', after all the actual solution can be acceptable.
    But for larger projects, I'm 100% agree with you!

  7. Avatar for Maarten Balliauw
    Maarten Balliauw February 11th, 2013

    That's the way Composer (www.getcomposer.org) does it in the PHP world. I've been thinking about this same thing last week and it would be interesting to have a mix of assembly packages and source packages.

  8. Avatar for Matt Davey
    Matt Davey February 11th, 2013

    Reminds me of the old svn externals days! This is a great idea in principle but I can see a couple of gotchas. If NuGet changes the namespace to match the project, isn't there always going to be an outstanding commit in the local repo? I think package authors would be forced to make a read-only repo url available (admittedly you get this for free on github). Secondly, I know Microsoft are backing git heavily, but I would be sad to see NuGet shun Mercurial.

  9. Avatar for Anthony Your
    Anthony Your February 12th, 2013

    It reminds me of the new DLL hell...it's called jQuery versions.

  10. Avatar for Wm
    Wm February 12th, 2013

    just my 2 cent...

    a) keep it simple is important, avoid external dependencies (outside the BCL) in code deployed on this way
    b) classes deployed in this way should be declared as internal => no conflicts if used in multiiple assembies

    for more complicated scenarios (with dependencies) i think ILMerge can be a alternative...

  11. Avatar for Shayne van Asperen
    Shayne van Asperen August 18th, 2015

    The solution to this is to make sure that all the types in a source-only package are internal and to mark the package as a developer dependency. See my github project where I've created a whole collection of source-only packages built from a single c-sharp project: https://github.com/shayneva...

  12. Avatar for Stuart
    Stuart February 12th, 2017

    Haha, was just about to email you this article! :-D