Navigating Roadblocks to .NET 5

Microsoft has been warning us of a full pivot to .NET 5 this fall, and some of us at Headspring have been trying to help other development teams get ready for the changeover. Microsoft announced the retirement of .NET Framework early in 2019, in favor of focusing on .NET Core. The coming .NET 5 represents the continuation of .NET Core (also soon-to-be-retired), so applications running full .NET Framework will feel the pain of a complex migration path.

If you’re using MySQL, getting from .NET Framework to .NET 5 may be even more complicated. I discovered this for myself while working on a technical refresh project that runs on MySQL 5.6. There were a few other applications sharing data with the database as we slowly upgraded the existing apps. Using EF6 was a solid choice years ago, but is now starting to show its age.

A streamlined migration path would go something like .NET Framework -> .NET Core (or .NET Standard) -> .NET 5, all while not having to upgrade EF 6. But because MySQL is in the picture, the upgrade gets more complex.

When upgrading to .NET Core, we found that even though EF6 works on .NET Core, the connector from Oracle for EF6 does not—only the EF Core connectors will work with .NET Core. Microsoft does not suggest migrating from EF6 to EF Core. However, it’s required when using MySQL.The process we figured out should help you handle this transition.

Working backward to map your path to .NET 5

A single, sweeping upgrade from .NET Framework to .NET 5 inherits a lot of moving parts. Attempting this could slow down your release cycle because it’s harder to fix current bugs on production while in the middle of the upgrade. I suggest a more methodical upgrade path, and we can work backwards to find the right route.

You would expect to arrive most easily at .NET 5 from .NET Core 3.1. In order to get to .NET Core 3.1, you need internal libraries to use .NET Standard, specifically version 2.0, since that’s the latest version which can support both .NET Core and .NET Framework. To have internal libraries use .NET Standard 2.0, you can use EF Core 3.1, but you cannot use EF Core 3.0.

Therefore, your migration path might look like this:

EF6 -> EF Core 3.1 -> .NET Standard 2.0 -> .NET Core 3.1 -> .NET Standard 2.1 -> EF Core 5 -> .NET 5.

The lurking roadblock: dynamic SQL in EF Core

However, there’s a roadblock on that path that could get easily overlooked. One of the major changes between EF6 and EF Core is dynamic SQL. Even though the feature set for EF Core does include “Raw SQL queries: Keyless entity types,” one drawback is that on EF Core you need to create a class for every query return, and mark that class with an attribute that it is a keyless entity.

This is probably not something you did for EF6 dynamic queries. In order to bridge this gap, you can make use of a micro-ORM, Dapper. If you are unfamiliar with Dapper, it was created for Stack Exchange for performance and usability. You can easily use Dapper alongside EF6, even in the same transaction, by using the DbContext.Database.Connection as your IDbConnection for Dapper’s queries. You can migrate your existing EF6 queries to Dapper and run those through tests before any other upgrades. This helps reduce the amount of changes between each upgrade step.

This will alter your upgrade path slightly:

EF6 -> EF6 + Dapper -> EF Core 3.1 -> .NET Standard 2.0 -> .NET Core 3.1 -> .NET Standard 2.1 -> EF Core 5 -> .NET 5.

This way, Dapper stays with you through every step.

Getting up to speed, slowly but still-in-business

.NET 5 is coming, and if you don’t want to slow down your operations scrambling to switch once it’s here, a step-by-step approach is best. Many people using MySQL could overlook the potential problems with upgrading Entity Framework to EF Core in order to support Oracle connectors—and get stuck mid-migration. Don’t let that be you! Using Dapper can help alleviate some of the pain points with this while maintaining a deployable solution to help keep production running.

Let's Talk