How to Migrate from .NET MVC 5 to .NET Core for Kentico Xperience
.NET Core and .NET 5 have been available for some time now and .NET 6 will be released any month now. However, the majority of existing Kentico MVC sites previous to version 13 were created in .NET MVC 5. This situation is especially true for Kentico 11 and Kentico 12 MVC versions as those previous versions weren't yet ready for and basically incompatible with .NET Core.
Why Leverage .NET 5 (and .NET 6)
ASP.NET MVC Core along with .NET 5 presents a compelling case for almost every .NET based application today. It could be perceived as a small jump in version numbers from 4.x to 5 if one is not familiar with the situation Microsoft has put us in, but .NET 5 is a major (and I do truly mean major) leap from the .NET 4.x framework that Kentico Xperience had traditionally run on. .NET 5 is a continuation of completely rebuilt and all-new framework that started with .NET Core 1.0 (released back in 2016) through .NET Core 3.1 and is now the future for all .NET development. Let me say this again, the .NET 4.7 or .NET 4.8 framework that developers were very familiar with no longer is even used in .NET 5 (and future versions).
I'm using .NET 5 and .NET 6 pretty interchangeably here because .NET 5 is current production ready target framework at time of writing this article. However, .NET 6 is set to release November 9th, 2021, which is almost around the corner. As soon as November 10th hits you would want to target .NET 6.
May key benefits of migrating to .NET 5 / .NET 6 for Kentico Xperience (and all .NET apps):
- Built for performance, and getting faster with every release
- Hot reload capability that is coming in .NET 6 (think enhanced developer productivity)
- It is the current framework that is being actively developed with regular performance, feature, and security updates
- Using the current framework will mean that future upgrades to .NET 6, 7, and onward will be much easier as far as upgrades go (think simple Nuget package update)
- Build and run cross-platform (yes, you no longer absolutely need a windows PC and Visual Studio to work with Kentico Xperience)
- Optimized project files for faster load and build times
- Cloud-ready (of course we are talking Azure PaaS here as the best practice)
- Open source on GitHub
- Support for minimal APIs
- Command Line Interface (CLI) for general use and scripting tasks
- Attract and retain developers who want to work with the latest technologies
- Additional years of LTS (long term support) when using .NET 6
Depending on the size of your application, or complexity of your Kentico installation, this may be a larger undertaking. I'm here to tell you that the benefits far out way the effort. The greater potential for performance improvements than any prior .NET Framework upgrade combined with the fact that all future versions of Kentico will only support .NET 5 / 6, and you have your answer why I feel this way.
Luckily my team and I at BizStream have worked through a few different real world client projects to make this migration a reality this year. As a result, I'd like to share the general way we have went about migrating Kentico MVC 5 to Kentico .NET Core / .NET 5.
Every project has its own unique customizations and dependencies, so your migration process may be slightly different and require additional steps, but the general process for .NET 5 / .NET 6 migrations follow these steps:
Phase 1: Kentico Xperience Upgrade
As I mentioned above, the only version of Kentico Xperience that supports .NET Core / .NET 5 / .NET 6 is Kentico Xperience 13. I've talked multiple times about Kentico upgrades before, so I am going to skip the details for this post. It is assumed that you have completed the upgrade to 13 with your Kentico admin tool, or you are starting out at Kentico 13.
I will say it again to be clear, you MUST be on Kentico Xperience 13 or higher to continue on.
Phase 2: MVC Live Site Migration from MVC 5 to .NET 5 / 6
The real meat of your migration is here. All of the steps below are related to your MVC Live site project and NOT the Kentico CMSApp project. Kentico's official documentation does have very helpful steps for how to handle the very specific Kentico Xperience parts of the migration of Xperience from MVC 5 to .NET 5, but I don't feel that it has enough "big picture" to the process (hence my motivation to write this post).
Step 1: Check Out .NET Portability Analyzer
The official Microsoft documentation says the first step in the migration is to analyze your current application to determine the amount of effort to expect when migrating to .NET 5. The .NET Portability Analyzer is a free tool that will analyze your assemblies and provide you with a report of APIs in your current application that are no longer supported. Sometimes there is a path forward for code that uses APIs that are no longer supported, but other changes require additional effort and a new approach.
Grab the Visual Studio extension to get started with the .NET Portability Analyzer.
Step 2: Inspect Project Dependencies
Evaluate dependencies between projects and determine whether to upgrade library classes to .NET Standard or .NET 5. If all projects are being upgraded to .NET 5, then all projects can target .NET 5. In the Kentico Xperience world, that option should boil down to .NET Standard 2.0. Realy in all cases where you need to leave a project in .NET Framework, and that project needs to reference an upgraded class project, you will need to target .NET Standard 2.0 instead of .NET 5. Think of the CMSApp project that represents the Kentico Admin tool (it is in .NET framework 4.x and you will most likely need to share code between those projects for thinks like custom external media storage modules). If you are not sure, you can also lookup the .NET Standard implementation support page to determine what versions of .NET and .NET Standard are compatible with each other.
Step 3: Convert Class Libraries
Class libraries (your helpers, extensions, custom scheduled tasks, reusable components, etc. etc.) are typically the easiest project types to convert. If they do not have any compatibility warnings in Step 1, it is very likely that you will be able to simply migrate all of the existing code to the new project structure. Before you start converting projects, ensure that you have the desired version of the .NET SDK installed on your local machine.
When you are ready to migrate your projects, you can start with the Try Convert tool to see if your entire solution or individual projects can be migrated automatically. If that does not succeed (and it most likely will not), or if you want to convert them manually to have more control over the process, you can take the following approach. I do recommend the manual process. Common steps are:
- Create a new Class Library project in either the same folder (with a new project name) a parallel folder (with the same project name) using either Visual Studio (Add > New Project > Class Library), or with the CLI command
dotnet new classlib -o <ProjectName>
- If using the same project name, replace the old csproj class file with the new csproj file that was just created
- Manage Nuget packages for the new project and add any missing packages that your code requires. You can also right-click on the packages.config file in Visual Studio and select “Migrate packages.config to PackageReference.”
- Delete files and folders that may no longer be needed such as the Properties folder and the packages.config file (now that your Nuget packages are now managed in the csproj file)
- Build the project and resolve any missing references or errors
Step 4: Convert ASP.NET Projects (The Hardest Part)
There have been a lot of changes to how .NET Core and .NET 5 initialize and run ASP.NET MVC projects, this step tends to be more involved than migrating class libraries.
In theory just like Step 3, you may be able to automatically convert your entire solution or the ASP.NET projects with the Try Convert tool. In my experience, it will not succeed on a complex project like a traditional Kentico Xperience project. You will most likely have to perform the conversion manually, you can follow these steps:
- Create a new ASP.NET Core Web App or an ASP.NET Core Empty project (differences of the .NET templates here). Select “.NET 5” for your Target Framework.
- Review your original project's startup code in Global.asax.cs. Any custom logic will need to be migrated to the new Startup.cs class in .NET 5.
- Add in / update the the Kentico Xperience libraries to 13 (follow Developing Kentico Xperience projects with .NET Core)
- Add in your custom Nuget packages from your previsous site and resolve any Nuget or reference errors. You will likely need to adjust your
usingstatements to account for changed namespaces in .NET 5.
- Copy or move all of your existing controllers and classes into the new project structure
- Update existing controller classes to derive from Microsoft.AspNetCore.Mvc.ControllerBase. You will want to create your own ControllerBase class that derives from ControllerBase and is decorated with the [Controller] attribute. Controllers that need to provide MVC View support can derive from Microsoft.AspNetCore.Mvc.Controller.
- This is where the official steps come in handy from Kentico documentation on migration to MVC Core. Some or all of those steps apply here.
- Migrate any custom (non Kentico) Handlers to use .NET Middleware instead
- Migrate web.config settings to appsettings.json (not every one of them!)
- Again, make sure to follow the docs from Kentico on Developing Kentico Xperience projects with .NET Core and heavily review the Kentico docs on migration to MVC Core.
Step 5: Review Dependency Injection
If you are already using Dependency Injection, you can likely continue to use the same DI framework. If you are not using DI at all, the migration to .NET 5 provides the perfect opportunity to start using the built-in Dependency Injection framework. Even if you are using a different DI framework, it may be worth considering making the switch to .NET Dependency Injection because of its excellent performance, and since it is a first-class citizen in .NET, it is very easy to adopt and use. I'm a big fan of using the built in DI framework in .NET Core.
Step 6: Migrate to System.Text.Json (optional)
Similar to DI, the migration to System.Text.Json for serialization and deserialization is an optional migration. If you are using Newtonsoft.Json currently, there won’t be complete feature parity in System.Text.Json, so it is worth reviewing the differences outlined here. But if System.Text.Json does provide all of the features you need, it is likely that you will see performance improvements by making the switch.
Also important, do not perform this step on the Kentico CMSApp project. Newtonsoft is still required there. Here are typical steps for migrating to System.Text.Json:
- Remove Nuget references to Newtonsoft.Json in your project(s)
- Build your solution and you should get build errors for everything that was using Newtonsoft
- Update using statements, typically removing Newtonsoft.Json and replacing with System.Text.Json
- Update serialization/deserialization syntax: SerializeObject() becomes JsonSerializer.Serialize() and DeserializeObject() becomes JsonSerializer.Deserialize()
Step 7: Migrate Forms to the new Form Builder (optional)
You may or may not have to do this step. But if you had older Forms (built in Kentico 12 or ealier), you will need to change to the way that Kentico Xperience 13 handles forms. The best place to start is the documentation here on Form builder development. You may have run into issues with the upgrade from 12 to 13 around this area. I know we sure did. We actually had to delete the forms out of the system to make the upgrade work. At a high level, you will most likely need to rebuild your forms in 13. There are some crazy workarounds possible, but that would be a whole different blog post to tell that story. If your forms are built in Xperience 13 using Form builder from the start you can ignore this step.
Step 8: Treat it like an Upgrade (optional)
This is an optional step as well, but you most likely will want to review / rebuild / re-test anything and everything that is on the MVC live site from a Kentico standpoint. That means, heavily inspect your event log as you browse through the site to watch for errors, rebuild your search indexes, clean / restart your web farm servers, and ensure that files are being delivered correctly when adding a new image in the Kentico media library.
Making the move from .NET Framework 4.x to the latest .NET platform can be a large effort, but it certainly has its benefits. Along with the immediate performance gains, you will once again be on the current .NET platform that will continue to improve over time. I know not everyone wants to go through a large upgrade to effort, especially since you may also need to go through a Kentico Portal Engine to Kentico MVC conversion as well, but it's 2021 people, which means .NET Core / .NET 5 / .NET 6 have been out for over 5 years now. There's no reason not to use it.