NuGet in the Enterprise, in 2021 and Beyond
by Eric Seng, on Jul 10, 2021 4:46:00 AM
Open-source packages on NuGet.org are a part of nearly every single modern .NET application... and most certainly, some the ones you and your team develop.
NuGet is easy to get started with, but gets complex quick. There's dependency resolution, multi-targeting, assembly redirection, debugging -- just to name a few.
But complexity should be the least of your worries with NuGet. What if someone on your team uses a package...
- with vulnerabilities, like WinSCPHelper 1.0.13 that "allows remote attackers to execute arbitrary programs when the URL handler encounters a crafted URL that loads session settings.”
- licensed under GPL-3, which requires that the entire code-base is open sourced, under the thread of lawsuits and copyright damages
Dealing with the fallout from security and licensing disasters will make those runtime-crashes from NuGet misconfiguration look like a walk in the park.
Fortunately, not everyone on your team needs to be an expert in all things NuGet. In fact, you don't even need to be a NuGet expert -- just some basic knowledge on how to manage NuGet in the Enterprise, as well as the tools and processes to use to make it work.
This article will walk you through NuGet in the Enterprise, in 2021 and beyond:
- What exactly is "NuGet" Anyways?
- How Do NuGet Packages Work
- The Life of NuGet
- Challenges With Third-Party Packages (Downloaded from NuGet.org)
- Challenges With First Party Packages (Your own packages)
- Taking NuGet to Enterprise
What exactly is "NuGet"?
Ask a group of developers “What is NuGet?”, and you'll get some conflicting answers.
They will probably be right, to some extent. "NuGet" is not just one thing, it's:
- a package format that describes files like MyPackage.nupkg
- a Public Package Feed
- it’s a Visual Studio plugin that lets you download packages from IDE
- a command-line tool that lets you automate or use the CLI
- a server API that describes how a tool downloads packages from a feed
- the website NuGet.org.
But the one central technology that all of these revolve around is the NuGet Package itself (i.e., a .nupkg file)
NuGet packages contain reusable code that other developers make available to you for use in your .NET projects. These packages reduce the time it takes to build, increases code quality, and are often free. Some examples of NuGet Packages are:
- Swashbuckle.AspNetCore: Automatically generate a JSON object that describes your entire API including endpoints, models, and the possible results.
- AutoMapper: Transforms one type of object to another. For example, transforming a persistent model to a DTO model.
- NETCore.Encrypt: Industry-standard encryption (SAH1, SAH256, SHA384, SHA512)
NuGet packages are great because they’re reusable, cut down of production costs, and means developers don’t have to reinvent the wheel when encountering a problem that’s been solved once before.
Most developers on your team already knows this, but may not have thought about it this way. Instead, they might just find the packages they need, and fold them into their code.
How Do NuGet Packages Work
NuGet packages are incredibly powerful tools. Packages can easily be plugged-in and used without having to copy/paste the code constantly. This means that developers can work faster and don’t have to struggle to reinvent the wheel. It’s also much easier to maintain/change one package that’s used by 100 applications than to change all that code in each individual application.
NuGet packages are files that contain any number of software libraries or other files. More specifically, a NuGet package is a single ZIP file with the .nupkg extension that contains compiled code (DLLs), and related files. The ZIP file also contains a manifest file (.nuspec) that includes metadata like the package's name, version number, and dependencies.
Packages and their Dependencies
Packages rarely function as a stand-alone unit. Instead, they often require one or more prerequisite packages before they can be used; these are known as "dependencies".
A dependency must be downloaded for the intended package to work, and this is where things can get a little complex.
For example, if you want to use Swashbuckle.AspNetCore 6.2.1, you first need to download four other packages:
- Microsoft.Extensions.ApiDescription.Server (3.0.0 or newer),
- Swashbuckle.AspNetCore.Swagger (6.2.1 or newer)
- Swashbuckle.AspNetCore.SwaggerGen (6.2.1 or newer)
- Swashbuckle.AspNetCore.SwaggerUI (6.2.1 or newer)
However, Swashbuckle.AspNetCore.Swagger has some dependencies of its own that also need to be downloaded:
And then, Microsoft.AspNetCore.Routing has its own dependencies:
- Microsoft.AspNetCore.Http.Extensions (2.2.0 or newer)
- Microsoft.AspNetCore.Routing.Abstractions (2.2.0 or newer)
- Microsoft.Extensions.Logging.Abstractions (2.2.0 or newer)
- Microsoft.Extensions.ObjectPool (2.2.0 or newer)
- Microsoft.Extensions.Options (2.2.0 or newer)
The list just goes on and on from there. Using just a single package could mean introducing a dozen other packages, each with their own DLLs, into your code base.
Accessing & Using NuGet Packages
To explore the contents of a NuGet package, you simply need to change the extension to .zip and open it. Alternatively, you can use a tool like NuGet Package Explorer.
NuGet packages are uploaded and hosted on a public or private repository for others to access.
To use a NuGet package, you can use Visual Studio or another similar tool. In Visual Studio you can add, update, remove, or restore packages to your project.
The Life of NuGet
NuGet is a mature technology with a long history. Understand what came before NuGet and how NuGet was developed will give some perspective on why NuGet in the Enterprise is such a challenge. For developers who just want to dive into the Visual Studio Extension and start coding, security and quality control with NuGet feels like a roadblock..
To get a good idea of why NuGet is so popular and how why it’s so complex, it’s helpful to understand a little bit more about what life was like before NuGet.
Developers would find and download a library file called a DLL (Dynamic-link library) and checked into source control alongside their own code, images, and other DLLs. DLL’s could also be installed on the target server waiting to be used.
DLLs promoted modularization of code, code reuse, efficient memory usage, and reduced disk space. Using them meant the operating system and programs would load and run faster, while taking less disk space on the computer.
However, unlike NuGet packages, DLLs often don’t link to their dependencies. They depend on the existence of a separate DLL module. The application terminates and produces an error if a required DLL isn’t found. This means you must hunt down all dependencies, download them, and check them into source code before being able to utilize them. All in all – a bit of a pain.
Another major issue users ran into was that certain DLL’s would only work with certain versions of platforms. Developers could spend hours searching for a DLL only to find it only worked on 64bit Windows and not 32bit. Using an incorrect DLL would lead to the app crashing.
NuGet packages are a standardized way of handling packages and unlike DLL’s, allow the user to inspect the manifest without having to run the code. Organizations are able to control quality and dependability easier using packages than with DLL’s.
NuGet had a humble beginning and was originally intended as a community project for open-source packages in .NET. On January 7th, 2011, the very first package was shared to the NuGet registry. NuGet early adopters had issues like buggy and constantly changing tools. After those were fixed, late adopters ran into the problem of having to catch up with a severe lack of official documentation. All in all, it was a less than ideal start for NuGet.
This was because, unlike other major developer tools by Microsoft (from Visual Studio to .NET), NuGet was not created following Microsoft’s generally high-quality standards. These standards include not only high-quality code, but collateral like marketing materials, training, documentation, and so on.
Instead, NuGet started as a Microsoft-sponsored community project. After many years, it became a proper Microsoft project, and is now tightly integrated into Visual Studio and .NET. It’s also a key driver behind Microsoft’s open-source initiative.
This development path has led to a few consequences.
- Early adopters had to use buggy and constantly changing NuGet tools that had very little documentation; this led to many suboptimal and quirky development practices
- Later adopters had to learn and discover how (and why) to use it on their own, and took instruction and training from anywhere they could (from StackOverflow to conference videos); these were often community-created instruction by early adopters
- Managers and directors had little awareness of NuGet until long after it was in use, and weren’t given the choice of when and how to use NuGet, nor how to develop internal practices
Packages from Internal and External
Dev teams use both proprietary (first-party) packages alongside external (third-party) packages to build their code. NuGet’s impressive library of over 270,000 unique packages and over 3,570,000 package versions means that developers have an abundant number of packages to choose from. As I mentioned, these third-party packages cut down on the time it takes to develop but they’re far from a perfect solution.
Challenges With Third-Party Packages (Downloaded from NuGet.org)
Most organizations use NuGet.org as a place to find and download third-party packages. There are a handful of critical issues that users (both veteran and junior) should be aware of.
“Open Source is everywhere. It is in many proprietary codebases and community projects. For organizations and individuals, the question today is not whether you are or are not using open-source code, but what open-source code you are using, and how much.” -- Microsoft on NuGet Packages
NuGet packages, like all software, are copyrighted material. When someone creates a package, they own its copyright – except in the rare case of being published in the Public Domain. The author decides how others can use their NuGet package through the license agreement. Not following or understanding these agreements can lead to costly lawsuits.
There are a tremendous number of different license agreements out there, and many are difficult to find (for non-technical folks) and difficult to understand (especially for non-lawyers). And then, because many packages use a URL for their license agreement, it can change after you originally agreed to it.
Manually vetting each and every license agreement, for each and every package, is simply not feasible. But you can do it automatically!
See How to Avoid Costly lawsuits from unexpected NuGet license agreements to learn how to best use automatic license scanning with a private NuGet server like ProGet.
Studies show that over 80% of codebases had at least one vulnerability – the average was 188 vulnerabilities per codebase.
Many vulnerabilities can be seen clearly and directly on NuGet.org with details including severity. NuGet gets vulnerability information directly from the centralized GitHub Advisory Database. This database provides two main listings of vulnerabilities: CVE (Common Vulnerabilities and Exposure) and GHSA (GitHub Service Advisory.)
Reported vulnerabilities are a reality of open-source packages, but those are only half the story. When using third-party packages, there’s the risk of an unknown amount of un-reported vulnerabilities being introduced to your code. Sometimes these are non-issues, other times they’re catastrophic. It’s virtually impossible to ever know or guess when, where, and the severity of these un-reported vulnerabilities until you find them
It’s important to remember that anyone and everyone can upload a package to NuGet.org without any verification.
A recent security analysis of packages hosted NuGet.org revealed exploitable high-severity vulnerabilities in over 50 packages that had been downloaded and used. One of the packages WinSCPHelper has been downloaded more than 33,000 times and is still being actively installed. This vulnerability “allows remote attackers to execute arbitrary programs when the URL handler encounters a crafted URL that loads session settings.”
NuGet packages on NuGet.org don’t undergo any kind of quality control/verification scanning. Therefore, IT development teams must rely on community recommendations, their own testing, or brand recognition (ex. A package made by Microsoft is almost certainly high quality.)
Most packages used in software development are third-party. NuGet.org keeps count of package downloads and the number at the time of this article being published is surpassing 119,900,000,000. Third-party packages inevitably introduce risk and without research, an incredible amount of faith is put into community reviews and recommendations.
NuGet.org is a public website and that means that your teams ability to work is directly related to server and internet access. Although uncommon, service outages can happen and when they do, teams are blocked.
Challenges With First Party Packages (Your own packages)
First Party Packages
Downloading third-party packages isn’t the only option for teams. It’s possible to make your own (first-party) packages and host them on your own private NuGet server. However, there are a few problems that teams need to be aware of before diving in.
Package Authoring Challenges
There are a lot of confusing fields to input when starting to create your own first-party NuGet packages. "Is Project Name the same as Package ID?" "Should the author be me, my team, my company??"
Really only FOUR fields matter:
- Package ID: your company name
- Description: link to your company internal wiki
- Author: your company / team name
- Repository: use a source link
The most important thing to understand about packages is that they cannot be renamed - at least, not easily. The NuGet package name is stored in the package's manifest file, which is stored within the package zip file itself.
What all this means is that your team really should be following package authoring best practices.
Versioning & Quality
Versioning seems so simple – it’s just a number! But with NuGet, it’s anything but that. There are five distinct, multi-part version numbers that can be in a package, and each of these has its own formatting rules and behaviors.
Improperly versioning your NuGet packages can lead to lots of problems. Usually, it’s just headaches and wasted time from confusing and “broken” packages. But sometimes, this will lead to production problems like application crashes due to assemblies that didn’t load at runtime.
One of the major challenges is that the five version numbers are used for three different things: Manage Package Dependencies, Loading Libraries Within the Package, and Displaying Important Information.
Fortunately, there are some best practices for versioning NuGet packages that you can follow to speed up the development process, keep things organized, avoid future headaches, and ensure your NuGet packages and applications are deployed seamlessly.
CI/CD for NuGet Packages
CI/CD for NuGet packages can feel nearly impossible when your team follows application CI/CD best practices.
Labels for “pre-releases” and “builds” are available as extensions. For example: the package ErpApplicationUtils 2.0.0-beta1 signifies that it's a prerelease ("beta1") of 2.0.0.
Imagine you’re working on 2.0.0 of ErpApplicationUtils. Obviously, you want another developer to test the package before release, so you create and publish 2.0.0-beta1 to your team's private package feed. After it’s tested and approved for production, what do you do? Publish the pre-release? Rebuild the package and version it 2.0.0?
You're stuck in a CI/CD loop.
The secret to getting out of the CI/CD loop while still following best practices is using a technique called "repackaging." By adapting repackaging into your CI/CD pipeline, you can ensure that what goes to production is exactly what you have tested.
Organization (Multiple Feeds)
A feed is kind of like an app store. Certain developers, projects, departments, have certain feeds that are separate from everyone else. Should every department have its own app store? Every dev? Every project? Every team?
Multiple people have multiple projects they’re working on. One massive feed can quickly get unruly and confusing. However, 100 feeds for every small project your team is working on is also a big problem. There is a learning curve and growing pain that comes with discovering your IT organization's feed management.
Taking NuGet to the Enterprise
119,900,000,000+ Package Downloads
3,570,000+ Package Versions
270,000+ Unique Packages
As the roles and responsibilities of developers grow and evolve, they rely more and more on NuGet packages. Third-party, open-source package use has jumped over 250% over the past 5 years and have built the foundation for almost every single modern application in every industry. It’s undeniable that third-party, open-source NuGet packages are necessary in the modern enterprise for developing software. They’re reusable and cut down production costs but inevitably introduce risk.
Jumping into NuGet for the first time is a complicated intimidating thing. But after learning about the history, context, and evolution of NuGet I hope you have a deeper understanding of why NuGet is such a popular and complex technology.