Written By Peter Donker
2025-10-22
As DNN continues to evolve, we’re increasingly relying on modern .NET libraries distributed through NuGet. This has opened the door to powerful new features and integrations — but it’s also brought with it an old and familiar problem: DLL hell. In this post, we’ll walk through why our traditional upgrade process no longer fits today’s reality, and how we’re moving toward a more robust, installer-driven approach to keep your sites stable and easier to upgrade.
The Classic DNN Upgrade Process
Historically, upgrading DNN has been simple — maybe too simple. You’d download a _Upgrade.zip package, extract it over your existing installation, restart your site, and let DNN’s built-in upgrade logic take over. During that process, all DLLs from the upgrade package would overwrite whatever was already in your bin folder. This worked fine back when DNN and its dependencies lived entirely within the .NET Framework ecosystem. But the landscape has changed.
The Problem: Modern Dependencies Meet Old Habits
With more and more features being delivered via NuGet, DNN now includes a growing number of .NET Core–based libraries, such as Microsoft.Bcl.AsyncInterfaces.dll. These libraries are often shared dependencies — used both by DNN itself and by third-party modules distributed by the community or vendors. When a module developer installs a NuGet package, it can bring along one of these shared DLLs, potentially at a newer version than the one bundled with DNN.
Here’s where things start to go wrong: During module installation, DNN smartly checks each assembly version. If a newer version exists, DNN copies it into the bin folder and updates the web.config with the appropriate binding redirect. Later, during a platform upgrade, the _Upgrade.zip process blindly overwrites DLLs — even those newer ones — with the versions included in the core package. The result? The binding redirect now points to a version that no longer exists.
Let's look at a concrete example:
- DNN ships with the .net 8 version of Microsoft.Extensions.DependencyInjection.dll
- You install a module that has shipped with a .net 9 version of Microsoft.Extensions.DependencyInjection.dll. The module installer now copies over this dll and updates the binding redirect to point to version 9.
- You install a module that has shipped with a .net 8 version of Microsoft.Extensions.DependencyInjection.dll. The module installer detects a newer version has already been installed and does not copy over this dll.
- You try to upgrade DNN by copying the contents of the _Upgrade package over your installation. Let's assume this newer version of DNN still ships with the .net 8 version of Microsoft.Extensions.DependencyInjection.dll. So now in the bin folder you have the .net 8 version.
Now your site fails to start with a big fat yellow error screen! And fixing this isn’t easy. It often requires manual inspection of the bin folder and web.config, tracking down which assemblies were replaced incorrectly. I know because it's happened to me.
As DNN continues to modernize — adding features that depend on multiple .NET libraries like Serilog, for example — this problem compounds. A single upgrade could involve 15–20 DLLs, dramatically increasing the risk of conflicts and broken sites.
The Solution: A Smarter, Safer Installer
Fortunately, we already have the foundation for a better solution. Starting in DNN 10.1, Brian Dukes submitted an internal installer designed to handle upgrades in a more intelligent, modular way (many thanks to him for this addition). The underlying idea is to make all assemblies from DNN go through the same process as a module's assemblies would. It works by placing the _Upgrade zip file in App_Data/Upgrade. The Upgrade zip file is extracted and a "mini installer" is created to do this for every dll in the bin folder of the distribution. This process means that "old" don't get copied in and newer ones do and the assembly redirects get set correctly.
Until now there has been no clear UI for this to kick off. I’ve been working on the UI for this installer, and I believe it’s shaping up to be the future of how DNN upgrades are performed. You can upload the DNN zip file to your site and kick off the upgrade process from there. As an added bonus this will also work with the Install package as the installer makes sure to filter out the files it shouldn't copy.
The Next Step: Enforcing the New Upgrade Path
To make this process reliable for everyone, we need to take one more important step: Stop distributing _Upgrade.zip packages. As mentioned above the installer can also work with the _Install package. No longer making this available will mean everyone will need to go through the UI to upgrade. Users familiar with the old process will immediately notice the change — and when they look for an explanation, we’ll point them to the new, safer, UI-driven upgrade process. This ensures consistency, eliminates a major source of upgrade-related errors, and future-proofs DNN as we continue to integrate modern .NET technologies.
Wrapping Up
As DNN evolves, so must our tooling and habits. The traditional file-copy upgrade process served us well for many years, but it’s no longer compatible with the complexity of today’s .NET ecosystem. By moving to an installer-based approach — and retiring the _Upgrade.zip packages — we’re taking an important step toward a more stable, predictable, and developer-friendly future for DNN.
Links: