Do you know how to handle complex .NET migrations?
Last updated by Brady Stroud [SSW] 7 months ago.See historyThere's not 1 single thing that makes a .NET project complex to migrate to the latest .NET Framework. Generally though it's a combination of the following:
- High complexity
- Lots of .NET Framework dependencies
- Outdated NuGet packages with no modern alternatives
- etc.
If your project doesn't meet any of the above criteria, you should consider using the .NET Upgrade Assistant. You can read more about the tool at Do you know how to modernize your .NET applications? If the .NET Upgrade Assistant works for your project, you could save a significant amount of time. However, the level of success may vary across different projects.
While complex .NET migration has many steps and can be time-consuming, it offers significant benefits, including incremental migrations, improved risk management, and streamlined progress tracking.
The migration begins with an Evolutionary approach and then smoothly transitions to the Strangler Fig pattern, optimizing the advantages of both approaches. The Evolutionary approach ensures better compatibility with .NET 8 for the existing code, while the Strangler Fig pattern complete the full migration.
This strategy results in a codebase that functions within the old .NET Framework while progressively moving towards .NET 8. The majority of changes bring benefits to both platforms, allowing seamless deployment of these improvements to production. You can get more information about different migration approaches at Do you know the different ways to modernize your application?
Below you will find some tips and tricks to help you with your more complex migrations.
Preparation
Upgrade the projects to use the sdk style csproj format
You can use the try-convert dotnet tool to convert your projects to the new sdk style csproj format. This will make it easier to upgrade the projects to the latest .NET Framework.
Install the tool using
dotnet tool install -g try-convert
Upgrade your web projects using
try-convert --keep-current-tfms --force-web-conversion
and your other projects using
try-convert --keep-current-tfms
Change all your projects to be able to target multiple Target framework monikers (TFM)
In all your project files change the TargetFramework
to TargetFrameworks
. You want to do this early on to enable a smoother flow later to not need unload and reload projects or have to close and reopen Visual Studio.
What this will allow you to do is add your target framework and compile the code. This will allow you to see what code is not compatible with the new framework and fix those issues while still developing/deploying your project in the current target framework.
<TargetFrameworks>net472;net8.0</TargetFrameworks>
Upgrading
At this point, ensure your project can target both the .NET Framework and the new target .NET. Some of the projects might not support both platforms right away and you can follow these steps to fix the issues and have a better understanding of how much work it might lies ahead.
- Add the target framework to your project
- Compile to see what breaks
-
Fix what is easy to fix
- Remember to commit after each fix to help your reviewers 😉
-
Anything that is not easy to fix, create a PBI with details of the issue
- This allows another developer on your team to work on that PBI independently
-
If you have a project that is able to compile at this point you can leave the new TFM in your project and continue to the next project
- If not, you can remove the new TFM and continue to the next project
- Repeat these steps once the PBIs have been completed related to this project
Outlined below are rules designed to assist in the project upgrade process during migration. Please note that the applicability of certain rules may vary based on individual project requirements.
- Do you know how to migrate from System.Web to modern alternatives?
- Do you know how to migrate from EDMX to EF Core?
Web application
There are several ways to migrate projects from ASP.NET to ASP.NET Core. We strongly recommend using the Strangler Fig pattern to incrementally migrate your project with YARP.
Create a side-by-side incremental project with .NET Upgrade Assistant
After you've installed the .NET Upgrade Assistant extension, Right-click on the project in the Solution Explorer window, and select Upgrade.
A tab is opened which provides, based on your project type, different styles of upgrade:
- In-place project upgrade
This option upgrades your project without making a copy. - Side-by-side project upgrade
Copies your project and upgrades the copy, leaving your original project alone. -
Side-by-side incremental
A good choice for complicated web apps. Upgrading from ASP.NET to ASP.NET Core requires quite a bit of work and at times manual refactoring. This mode puts a .NET project next to your existing .NET Framework project. If an endpoint is implemented in the .NET 8 project, any requests to that endpoint will be handled there and all other requests will be forwarded and handled by the .NET Framework project.This option lets you upgrade your ASP.NET app or class library project piece by piece.
On more complex projects you might find that Upgrade Assistant only provides you with the side-by-side incremental option. That is also the option that is covered here.
Once your app has been upgraded, a status screen is displayed which shows all of the artifacts related to your project that were associated with the upgrade. Each upgrade artifact can be expanded to read more information about the status. The following list describes the status icons:
- Filled green checkmark: The artifact was upgraded and completed successfully.
- Unfilled green checkmark: The tool didn't find anything about the artifact to upgrade.
- Yellow warning sign: The artifact was upgraded, but there's important information you should consider.
- Red X: The artifact was to be upgraded, but the upgrade failed.
After the Upgrade Assistant completes the upgrade you will find a new project in the solution running .NET 8. Upgrade Assistant pre-configured the project and installed any necessary packages it required to run side-by-side using the Yarp proxy.
Configure Yarp
As you can see in the above diagram, we want our UI to go through the .NET 8 project where the Yarp Proxy will either serve and fulfill the request or pass it through to the legacy project.
When you look at the Program.cs
in the newly created .NET 8 project, you will see that there is a configuration for the catch-all forwarder. You will need to update the configuration here with the address of your legacy project.
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseSystemWebAdapters();
app.MapDefaultControllerRoute();
// This is responsible that requests are forwarded
// You need to change the configuration for ProxyTo to
// your legacy project's address
app.MapForwarder("/{**catch-all}", app.Configuration["ProxyTo"])
.Add(static builder => ((RouteEndpointBuilder)builder).Order = int.MaxValue);
app.Run();
Figure: Program.cs code showing the forward clause to the legacy project
Upgrading components using Upgrade Assistant
Once you have created the side-by-side project, select the project that needs migration and right click
| Upgrade
on it.
Upgrade Assistant will show you a Summary view and detect that the project is linked to your Yarp proxy. You can also see the migration progress of your endpoints from .NET Framework to .NET as a pie chart.
From here you can explore your endpoints through the Endpoint explorer
, which will also indicate what endpoints have already been migrated and which ones are still outstanding.
The chain icon indicates that this endpoint has been migrated and is linked between the controller in the old project and the controller in the Yarp proxy project.
Use the Upgrade
functionality to apply automatic code transformations and speed up the migration process.
In the best-case scenario, the controller has been fully ported across and does not require any manual work.
In most scenarios, you will need to review the controller and update any custom code that the Upgrade Assistant could not automatically transform.
Create PBIs to identify the upcoming tasks
When a web project is heavily reliant on .NET Framework dependencies, the first step in gauging the effort required for a complete migration is to thoroughly examine these dependencies. This involves a detailed investigation, followed by the creation of PBIs for each dependency. These PBIs serve to accurately scope out the total effort that will be needed for the migration process.
Listed below are rules crafted to aid in the project migration process. Please ensure to incorporate only those rules that are applicable to your specific project.
- Do you know how to migrate Global.asax to ASP.NET Core?
- Do you know how to migrate OWIN to ASP.NET Core?
- Do you know how to migrate Web.config to ASP.NET Core?
.NET Upgrade Assistant
By now, you should have wrapped up the entire migration including the web applications. It's the perfect moment to use the .NET Upgrade Assistant. It'll guide you in cleaning up the codebase. The ultimate goal is to eliminate all the old .NET Framework components and keep only the code and the most up-to-date NuGet packages for .NET 8.