DNN Blogs

Written for the Community, by the Community

NuGet is the bane of my existence

Written By Peter Donker
2019-07-23

I have said on many an occasion. And I'll readily admit that in part this is just an old coder's frustration with a new technology. One of the many "get off my lawn" moments I've gone through. But like it or not, NuGet is here to stay and in our Microsoft-oriented world it is the standard way to resolve references. Before we had NuGet we'd do this "manually". So before I go any deeper into this, let's first explore what the breadth of the problem is and how we used to do this in the old days. You know, when telephones were still attached to a wall.

Background

Way back when, DNN was a sample project for asp.net called IBuySpy. If you wanted to develop a module to extend it, you'd load in the entire IBuySpy solution and add your code. This would ensure that (a) all your references were correct and (b) you could debug by drilling through the entire solution. This way of development is still done in some systems but there are huge drawbacks to this. One such reason is that the more code you have "open" the slower VS and compiling becomes. For the current DNN platform you'd load in so much code that your development speed would drop to naught. So no one does this (or not anyone I know in any case).

In the early days of DotNetNuke we used so-called WAP ("Web Application Project") projects. The idea was you'd develop your module in its own project and then reference the relevant dlls from the bin folder of the larger solution. This is how you'd do DNN modules and this is where many of us jumped on board back in the early 2000's. And this has worked quite well for us ever since.

As time went on I noticed one important difference between how we'd do module references and how all tutorials on the web explained how it should be done. If you develop to distribute you'd typically want to compile against an older version of DNN while ensuring yourself it will run on the latest as well. This is easily done by keeping a folder of referenced dlls with your project and not rely on the dlls that are in the bin folder of the DNN installation you're using to develop on. Ensure that "Copy Local" is set to false for the various DNN dlls and you're good to go. It requires a few tweaks and understanding of how VS deals with references, but it works well for the development of modules that need to work on a wide range of DNN versions.

NuGet

So along comes NuGet in 2010. Now, if we wish to use Newtonsoft for instance, we'd use NuGet in our project to create the reference. The advantage that we're promised is that we're no longer keeping a directory of reference dlls and we don't need to fish those out of DNN any more. The references are neatly listed in an XML file and VS takes care that the projects use the right dll. But, as is so often the case, those who create these new technologies are not in our shoes and have designed them for very different scenarios.

Where it gets complicated

DNN currently gets distributed with around 45 dlls. Generally you do not want to touch these dlls. They interdepend. And as you're not aware of how exactly, changing any one of them risks breaking the entire application. So as a rule of thumb: if you have any dependency on a dll that ships with DNN you do _not_ include this in your module's install zip. Period. No ifs or buts. I know DNN can work out if an assembly has a newer version or it can be overwritten etc. etc. But just, no. If you're using Newtonsoft or SharpZipLib you don't want these dlls to be distributed with your module and instead your module relies on the ones that came with DNN.

What this entails is that you should be aware which dlls were shipped with the distribution you're compiling against! If you're compiling against DNN 7 then you must use Newtonsoft 7.0.1 (or earlier) as a reference. This will ensure your module won't be broken on DNN 7 and since DNN took care of rewiring newtonsoft when it was upgraded to 10.0.3 in DNN version 9.2.0, your module will work unaltered on that version, too.

What this all means is that if you wish to use NuGet, you need to first look up which version of Newtonsoft was used for DNN 7. And this goes for every dependency that you take that is already included in the distribution. A recent MVC style module I have worked on includes references to 11 dlls that are not built by DNN but are part of the distribution (think Microsoft.ApplicationBlocks.Data, System.Web.Http, System.Web.Mvc). I will now need to check the version for each of these for the DNN version I wish to compile for. Can you begin to see my frustration with this "improvement"? And to top it all off, many of these dlls are hiding in other packages from Microsoft with a completely different name and version number (System.Net.Http.Formatting.dll is found in the Microsoft.AspNet.WebApi.Client package for instance).

The twist

But, I hear you say, you can bundle things in NuGet so you could create a package that combines things. This indeed would solve the issue above. But from personal chats with "NuGet experts" I hear the Microsoft philosophy is away from bundles. I can only guess why, but again I'm left with the impression that the good folks behind this have no idea how coding looks like to me.

I have tried to make a case internally for a "everything but the kitchen sink" DNN NuGet package. I.e. one that includes all dlls and dependencies we need. In theory this would be the best solution as anything you develop for DNN would be covered by such a package. But there are a couple of snags. For one VS insists it will add all assemblies in the package as references for a project if you add the bundle. So using such a NuGet package would explode the number of dll references in your project. It's not the end of the world, but it makes things a bit unwieldy. The second disadvantage is that for some dlls we have no right to distribute them this way. So there are legal barriers to this, too.

And that's not all

Just like other package management systems, NuGet can retrieve packages from multiple sources, or "feeds". By default it takes its feed from nuget.org. But you can add feeds to your own NuGet server, a share, or any other provider. This means that your project can reference packages that someone else, who downloads your solution, cannot access unless he/she changes their configuration. This is what happened to me when around 2018 when I tried to build the DNN source code. There were bunches of errors in NuGet stating it could not find packages. And unless you are familiar with how NuGet works, you are left wondering if and how you'll get this working. After outside help, I got the url to the DNN Corp NuGet feed and those errors disappeared. But again I was left feeling this is a pretty awful experience as a developer.

This has recently improved with local nuget config files that allow you to specify the feed locations. This will resolve this issue.

Where we stand today

I'm still on the fence on how useful NuGet is for DNN developers. The current set of packages is still incomplete and doesn't go back in time. The DotNetNuke.Core and DotNetNuke.Web.Mvc packages, for instance, are only there from DNN 9.2.0 and newer. And as long as it doesn't cover our needs I am not surprised to find that when I ask around in my developer circle of friends, most will say they don't use NuGet for this reason. They are still using the trusted folder of referenced dlls.

Do you have a solution?

I think we should have clearly delineated bundles for the most common use cases of DNN module development (Mvc, Spa). And that these bundles should go back as far as we can reasonably create them (e.g. DNN 8.0). This does not need to be a lot of work. In fact, I have already automated this process. All it needs is the "templates" for the packages to be created. These packages should be clearly labeled so everyone knows these are the official/best DNN development packages. Since we are stuck not being able to retract or improve the old packages I propose a new banner and/or logo.

Total: 4 Comment(s)
As part of the 9.3.2 release we improved the packages, to add references that are needed for development that were not there automatically. All module types can be built with NuGet references only and for enterprise development this is critical as it allows for easily builds in environments such as Azure DevOps. It is a mindset shift, but we have had support for this since 2009 when I had Joe push the first iteration of the packages. Additionally we can help to guide integration best practices by preventing usage of assemblies that should not be consumed etc. I dont have an issue back porting the recent changes it just takes time.
Wednesday, July 24, 2019 ·
I stand behind your point of view Peter. I use NuGet, but by no means an expert and the "magic" it sometimes does drives me mad and I sometimes therefore revert to pointing to the dlls directly. With DNN, I'm open to any suggestion to make it easy to compile and distribute.
Thursday, July 25, 2019 ·
EPT
EPT
For me, a folder in the solution with the referenced DLL's still works most efficiëntly and less error prone. It also garantees that others with a copy of the solution can build directly without any hassle.
Friday, July 26, 2019 ·
Nuget missed to have a lock file, save as npm, While the solution for javascript has been yarn, there was also a similar solution for .Net: Paket. It gives you back the control and doesn't feel like magic anymore. I can strongly recommend to give it a try! https://fsprojects.github.io/Paket/
Wednesday, August 28, 2019 ·

Would you like to help us?

Awesome! Simply post in the forums using the link below and we'll get you started.

Get Involved