Moving from the classic .NET Framework to .NET Core (modern .NET) requires careful planning. This chapter covers migration strategies, tooling, breaking changes, and best practices for large codebases.
Modern .NET (5, 6, 7, 8+) is the successor to both .NET Core and .NET Framework. The recommended path is:
packages.config to PackageReference..NET Standard version (2.0 is widely compatible).Early .NET Core used project.json; the SDK later returned to the .csproj format. If you still have project.json:
dotnet migrate # Automated migration tool
# Or manually create a .csproj:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
</Project>
dotnet migrate command was deprecated after .NET Core 3.0. For newer projects, create a new SDK-style project and port your code manually.The API Compatibility Analyzer (Microsoft.DotNet.ApiCompat) helps identify APIs that are not available on your target platform. It runs as an MSBuild task:
<PackageReference Include="Microsoft.DotNet.ApiCompat" Version="8.0.0" />
Run dotnet build and review any compatibility warnings.
Several technologies from .NET Framework are not available in modern .NET:
SkiaSharp or ImageSharp for cross-platform image processing.AssemblyLoadContext.System.Text.Json or Protobuf.The dotnet-apiport tool (now integrated into Visual Studio) scans your assemblies and generates a detailed report of API usage and compatibility.
dotnet tool install -g dotnet-apiport
dotnet apiport analyze -f MyApp.exe -t net8.0 -o report.html
.NET Standard 2.0 is the bridge between .NET Framework and modern .NET. Libraries targeting .NET Standard 2.0 can be consumed by both ecosystems.
| .NET Standard | Supported by |
|---|---|
| 2.0 | .NET Framework 4.6.1+, .NET Core 2.0+, Unity 2018.1+ |
| 2.1 | .NET Core 3.0+, .NET 5+ (not supported by .NET Framework) |
netstandard2.0. For new libraries, target net8.0 (or later) to access the latest APIs.#if NET preprocessor directives to maintain dual-target builds during transition.You can target both .NET Framework and modern .NET during migration:
<TargetFrameworks>net472;net8.0</TargetFrameworks>
Use #if NET472 and #if NET8_0 in source code to isolate platform-specific code.
System.Drawing to resize images and AppDomain for plugin loading. Port it to .NET 8, replacing System.Drawing with SkiaSharp and AppDomain with AssemblyLoadContext. Run the portability analyzer before and after.