Sponsor: Do you build complex software systems? See how NServiceBus makes it easier to design, build, and manage software systems that use message queues to achieve loose coupling. Get started for free.
Have a large .NET Framework codebase that you want to migrate to .NET8 or beyond? Here’s some tips of my .NET Framework migration and things to consider.
YouTube
Check out my YouTube channel, where I post all kinds of content accompanying my posts, including this video showing everything in this post.
Introduction to the Migration Journey
My journey of migrating a large codebase from .NET Framework to .NET 9 and beyond was not just a technical challenge; it was about long-term strategy and planning. The need for improved performance, scalability, and modern development tools is what drove the goal of migration.
Before diving into the migration process, a deep understanding of the codebase structure is important. The original solution, built on .NET Framework, relied heavily on specific libraries that may not directly translate to .NET 9. This necessitates a detailed audit of the current dependencies, modules, and integrations.
Historical Context: From .NET Framework to .NET Core
To appreciate the migration journey, it’s helpful to understand the historical context surrounding .NET Framework and .NET Core. Initially, .NET Framework was the go-to platform for Windows-based applications, but with the advent of .NET Core, Microsoft introduced a more flexible, cross-platform framework. The evolution of .NET is what is named starting at .NET5 and beyond.
.NET Framework > .NET Core > .NET
The introduction of .NET Standard further facilitated this evolution, acting as a bridge between the two frameworks. By ensuring that libraries were compliant with .NET Standard, developers could create code that was interoperable across both frameworks, easing the migration path.
Navigating the Concept of .NET Standard
Understanding the .NET Standard is needed to navigate the migration. It serves as a specification of APIs that all .NET implementations must adhere to. By targeting .NET Standard, libraries can be utilized across different .NET platforms, including .NET Framework and .NET Core.
In practice, this means that as you upgrade your codebase, ensuring that all dependencies comply with .NET Standard allows for a smoother transition. The goal is to minimize breaking changes, enabling the codebase to run seamlessly on both .NET Framework 4.8 and .NET Core 2.1 during the migration phase.
Handling Breaking Changes with Shims
One of the most significant challenges during migration is dealing with breaking changes arising from upgrading frameworks or libraries in which the API differs.
A practical solution to this problem is the implementation of shims. Shims act as an intermediary layer that translates calls from the old API to the new one, allowing existing code to function without modification. For instance, when upgrading from Nancy 1.x to 2.0, the breaking changes in route definitions necessitated the creation of a shim to maintain backward compatibility.
By employing shims, you can ensure that the migration process is less disruptive, allowing for gradual updates without the need for an immediate overhaul of the entire codebase. This approach not only preserves functionality but also provides a safety net during the transition, enabling you to address issues incrementally.
For more on Shims, check out my video How do you remove 3rd party library? Create a SHIM!
Tools for Package Compatibility
When migrating a codebase, understanding package compatibility is paramount. There are tools available that can assist in identifying which packages are compatible with .NET Standard and .NET Core. One such tool is the Porting Assistant from AWS, which helps assess the compatibility of existing libraries and suggests alternatives. Another useful tool is the .NET Upgrade Assistant, which provides insights into how to upgrade your projects effectively.
These tools not only highlight compatibility issues but also streamline the migration process by allowing developers to focus on significant changes rather than getting bogged down by minor discrepancies. Using these utilities can save considerable time and prevent potential pitfalls during the migration journey.
Options for Unsupported Libraries
Encountering unsupported libraries during migration can be a significant roadblock. However, there are several strategies to address this challenge. The first option is to seek out community-driven forks of the library that have been updated to support .NET Standard. If the library is open source, you can also consider forking it and applying the necessary updates yourself.
If neither option is feasible, exploring alternative libraries that provide similar functionality is a viable path. This may involve refactoring parts of your application to accommodate the new library’s API. In cases where a direct replacement is not possible, creating an adapter layer can help bridge the gap, allowing your existing code to interact with the new library seamlessly.
Testing Runtime Differences
As you transition to .NET Core, you’ll need ot test for runtime differences that may arise, especially concerning serialization. Differences in how types are handled between .NET Framework and .NET Core can lead to unexpected behaviors. For instance, if you’re using Newtonsoft.Json for serialization, you may encounter issues when deserializing data due to discrepancies in type information if it’s included in the serialized output.
To mitigate these risks, conduct thorough testing of all functionalities that rely on serialization. This ensures that data is correctly serialized and deserialized across different framework versions, preserving the integrity of your application.
Upgrading Through the Versions
Once the codebase is stable on .NET Core 2.1, the next step is to upgrade through subsequent versions to .NET 9.
After you migrate to .NET5, you might think about jumping right to the latest version. Each upgrade may introduce its own set of breaking changes, however .NET5 and beyond has been very stable in not introducing many breaking changes in my experience.
Reflections on the Migration Process
The migration process from .NET Framework to the latest .NET was long and not a big bang. It took planning and effort to migrate libraries and our code to work under .NET as it is today.
Initially, the codebase ran .NET Framework 4.8 on Windows, and today, it runs on the latest .NET under Linux containers. Quite the ride.
Join CodeOpinon!
Developer-level members of my Patreon or YouTube channel get access to a private Discord server to chat with other developers about Software Architecture and Design and access to source code for any working demo application I post on my blog or YouTube. Check out my Patreon or YouTube Membership for more info.