3

I'm seeking advice on the best approach to upgrade a legacy .NET Framework project to a newer version. The project currently consists of over 80 projects, and a complete rewrite would be a time-consuming undertaking.

We're considering a phased approach, where we gradually migrate functionality to newer projects while maintaining the old ones for the time being. This would allow us to benefit from newer features and security improvements without disrupting the existing application.

Our primary question is whether it's feasible to reuse components from the old projects, such as models, methods, and entity contexts, within the new projects. This would save us significant development time and effort.

Would this be the most efficient approach, or is there a more ideal strategy? We're open to suggestions and best practices for tackling this type of migration.

Additional details:

  • The current project is in .NET Framework 4.5.
  • We're considering upgrading to .NET 6 or later.
  • We have a team of experienced developers with expertise in .NET Framework and newer technologies.
  • We're prioritizing a smooth transition that minimizes disruption to the existing application.

Key considerations:

  • Technical feasibility: Can we effectively reuse components from the old projects within the new ones?
  • Development effort: Will reusing existing components save us significant time and effort compared to a complete rewrite?
  • Long-term maintainability: Will the resulting codebase be maintainable and scalable in the long run?
14
  • Have you seen the .NET Migration Documentation? Commented Jul 8 at 6:31
  • 1
    I see two close votes already. I'm in the midst of precisely this sort of problem, and I do have some advice. Hold the close votes, please! Commented Jul 8 at 12:32
  • 1
    "a complete rewrite would be a time-consuming undertaking" Gradual upgrades tend to take more time, not less. However, gradual upgrades can keep the outage time (i.e. time between breaking the old code and finishing the refactored code) to a minimum by spacing out the changes. It is unclear to me whether the key goal here is to minimize the overall hours worked on the refactor (in which case a slow upgrade is the wrong decision) or if you're stuck having to have an always-buildable and continually-evolving codebase that couldn't possibly support a big bang refactor.
    – Flater
    Commented Jul 8 at 23:45
  • 1
    @Flater, while a rewrite takes less time in absolute terms, .NET 4.8 is still supported by Microsoft, so there is no panic yet. A gradual upgrade allows you to deliver new features in parallel, which is the major win here. Commented Jul 9 at 12:46
  • 1
    @GregBurghardt Same comment as above.
    – Flater
    Commented Jul 9 at 23:37

1 Answer 1

3

You will want to target .NET 8, which is the latest version. Using .NET 6 is not recommended because it is out of support (see Microsoft .NET and .NET Core Lifetime Policy).

First, assess the project dependencies to ensure they make sense. I've worked on applications where class libs depended on web projects, and separate web API projects depended on each other. You need to ensure your solution does not have circular dependencies. Visual Studio does a pretty good job of this, but circular dependencies can sneak in if there are enough levels of separation between projects. Don't be afraid to crack open a Visio diagram (or some similar tool) to visually map these dependencies if necessary. If you find indirect circular dependencies between projects, your first order of business is to break these circular dependencies. The rest of the upgrade will go much smoother and allows to selectively upgrading projects, which I believe to be one of your main goals.

The low-hanging fruit for your upgrade will be class libraries that are not directly coupled to the .NET Framework. We use .NET Standard 2.0 for class libraries in one of my projects, because they work with .NET Framework 4.6+ and .NET Core/.NET 5+ projects. Generally speaking, the lower the .NET Standard version number the more .NET runtimes that are compatible. So really, step 1 is to convert class libs to .NET Standard 2.0 and upgrade the other projects to .NET 4.8.x. The upgrade from .NET 4.5 to 4.8 should require minimal effort.

Next step is to upgrade test projects that only rely on those class libs and NuGet packages. These are usually pretty easy and safe to upgrade to the latest version of .NET. The most troubles I've had concerned upgrading NuGet packages, but this is very dependent on the NuGet packages you have installed.

Finally, upgrade projects that are tied to the .NET framework. These are things like web and web API projects, Windows services and console applications. This is where project dependencies begin to matter.

Roughly, these are the steps to take:

  1. Break indirect circular dependencies between projects.
  2. Upgrade projects to .NET 4.8 which still receives security fixes and supports .NET Standard 2.0.
  3. Upgrade class libs to .NET Standard 2.0, which works on .NET 4 and .NET Core/.NET 5+.
    • This will include hunting down newer versions of 3rd party NuGet packages which are compatible with .NET 4.8 and .NET Standard.
    • I've run into a slight snag using FluentValidation. It looks like the v8 series of FluentValidation is the last one that had good integration with .NET Framework 4 ASP.NET MVC applications. You can upgrade to the latest version of FluentValidation for those projects, but you lose client-side validations. Properly done, this is an inconvenience for the end user and should be resolved once you upgrade to .NET 8.
  4. Upgrade test projects for the .NET Standard class libs to the latest .NET version.
    • And then upgrade any CI/CD pipelines you use as well.
  5. Upgrade the remaining projects which are tightly coupled to .NET 4.
    • Again, CI/CD pipelines will likely be impacted by this.

Some other considerations:

  • With 80 projects in one solution, dependencies might be difficult to untangle. Analyze which ones are cohesive, and consider upgrading the whole group of projects at once.
  • Automated tests are you friends. If you don't have good test coverage, consider writing tests first before attempting to upgrade. They can be unit tests, integration tests, or end-to-end tests. The important thing is that you have tests.

Planning For The Future

Once you've done the big lift-and-shift into the new framework, you can retarget the .NET Standard libraries to .NET 8, however .NET Standard will continue being supported moving forward. Changing from .NET Standard to .NET 8 should only be necessary if your application needs to utilize APIs that are not available in .NET Standard.

Limitations Of This Approach

I have not needed to deal with C++ projects yet. The available .NET framework APIs and any third party libraries will be the major hurdles with upgrading C++ projects. I don't have a lot of advice here due to a lack of experience on this front.

8
  • Hello, thanks for the information. It helps me have a good idea of where to start. I forgot to mention that I have .ascx views or user controls. When migrating, would I have to convert all of those views to Razor? Commented Jul 8 at 14:44
  • @AsdrubalHernandez, check Microsoft's documentation. They might still support those kinds of views, but I don't know offhand. That is another consideration. Commented Jul 8 at 14:51
  • 1
    I plan on updating my answer. I saw two close-votes, so I was racing the community to answer before it got closed. Commented Jul 8 at 15:50
  • 1
    .NET Standard is just that: a standard of the C# language API and .NET 8 is an implementation of that standard --- .NET Standard is to HTML 5 as .NET 8 is to Google Chrome v126, as an illustration. Commented Jul 8 at 16:55
  • 1
    @AsdrubalHernandez It should not change anything at all when it comes to upgrading/migrating to .NET 8; Changes between .NET 4.x versions are trivial and not worth wasting time which would be better spent on getting to the very real problems with dependencies that Greg mentioned. In every case you always need completely new versions of every tool and dependency you're currently using. That includes the new MSBuild SDK (csproj XML structure), new build tools and compiler, NuGet, all of the .NET libraries and all NuGet packages. This is where most of the real work is found. Commented Jul 9 at 6:49

Not the answer you're looking for? Browse other questions tagged or ask your own question.