From .NET Framework to .NET Core: A Migration Story

Migrating from .NET Framework to .NET Core (now just ".NET") isn't just a technical upgrade—it's a strategic decision that can unlock modern development practices, better performance, and cross-platform capabilities. I've led several of these migrations, and here's what I've learned.

Why Migrate?

First, let's talk about why you should consider this migration:

  • Performance: .NET Core is significantly faster—we saw 30-50% performance improvements in most applications
  • Cross-platform: Run on Linux containers, reducing infrastructure costs
  • Modern tooling: Better CLI, improved package management, side-by-side versioning
  • Active development: .NET Framework is in maintenance mode; all new features go to .NET
  • Cloud-ready: Better suited for microservices and containerization

The Assessment Phase

Before writing a single line of code, we spent time understanding what we were dealing with:

Inventory Your Dependencies

Use the .NET Portability Analyzer to scan your codebase. It will tell you:

  • Which APIs aren't available in .NET Core
  • Third-party package compatibility
  • Platform-specific dependencies

Categorize Your Applications

Not everything should be migrated at once. We grouped applications into:

  1. Quick wins: Simple web APIs with minimal dependencies
  2. Medium complexity: MVC applications with some Windows-specific code
  3. Complex: Applications heavily dependent on .NET Framework features
  4. Don't migrate: Legacy apps scheduled for retirement

The Migration Process

Step 1: Upgrade to .NET Framework 4.8

Before jumping to .NET Core, upgrade to the latest .NET Framework version. This surfaces compatibility issues early and gives you access to .NET Standard libraries.

Step 2: Move to .NET Standard Libraries

Extract business logic into .NET Standard 2.0 class libraries. These can be used by both .NET Framework and .NET Core, allowing for incremental migration.

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
  </PropertyGroup>
</Project>

Step 3: Migrate Supporting Projects First

Start with class libraries, then move up to the application layer:

  1. Data access layer
  2. Business logic layer
  3. API/Web layer

Step 4: Update Project Files

The new SDK-style project format is much cleaner:

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
  </PropertyGroup>
</Project>

Common Challenges and Solutions

Challenge 1: Configuration System

Problem: .NET Core uses a completely different configuration system (appsettings.json vs web.config)

Solution:

// Old .NET Framework
var setting = ConfigurationManager.AppSettings["MySetting"];

// New .NET Core
private readonly IConfiguration _config;
var setting = _config["MySetting"];

Challenge 2: Dependency Injection

Problem: .NET Core has built-in DI; you might have been using Unity or Autofac

Solution: Embrace the built-in DI container. It's lightweight and sufficient for most scenarios:

// Startup.cs
public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<IMyService, MyService>();
    services.AddDbContext<MyContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("Default")));
}

Challenge 3: Entity Framework

Problem: Moving from EF6 to EF Core involves some breaking changes

Solution: The good news is EF Core is mostly compatible. Main issues:

  • Some LINQ queries need rewriting
  • Lazy loading requires explicit package
  • Some advanced features aren't available (yet)

Challenge 4: Windows-Specific Dependencies

Problem: Code using Windows registry, WCF, or System.Drawing

Solution:

  • WCF: Use gRPC or REST APIs instead
  • System.Drawing: Use ImageSharp or SkiaSharp
  • Registry access: Rethink if necessary, or use Windows Compatibility Pack

Real-World Migration: Enterprise API

Let me share a specific example. We had a large ASP.NET Web API application with these characteristics:

  • 200+ API endpoints
  • Entity Framework 6 with SQL Server
  • Custom authentication using OWIN
  • Autofac for dependency injection
  • Significant business logic in class libraries

Our Approach:

  1. Week 1: Created parallel .NET 8 project, migrated configuration
  2. Week 2-3: Migrated data access layer to EF Core
  3. Week 4: Converted business logic libraries to .NET Standard
  4. Week 5-6: Migrated API controllers, replaced OWIN auth with ASP.NET Core Identity
  5. Week 7: Comprehensive testing, performance benchmarking
  6. Week 8: Deployed to staging, gradual production rollout

Results:

  • 45% improvement in response times
  • 60% reduction in memory usage
  • Docker containerization enabled (now running on Linux)
  • Infrastructure costs reduced by 40%

Lessons Learned

1. Test Everything

Have comprehensive automated tests before starting. We caught numerous subtle behavioral differences between .NET Framework and .NET Core.

2. Don't Boil the Ocean

Migrate incrementally. Use the Strangler Fig pattern—gradually replace old system with new.

3. Update Your Skills

ASP.NET Core introduces new patterns (middleware, hosted services, options pattern). Invest time learning these.

4. Performance Test Early

We found that while most code ran faster, some LINQ queries performed worse in EF Core and needed optimization.

5. Embrace Modern Practices

Don't just port the code—use this as an opportunity to modernize your architecture.

Tools That Helped

  • .NET Upgrade Assistant: Microsoft's tool for automated migration (saves tons of time)
  • API Analyzer: Identifies compatibility issues
  • BenchmarkDotNet: Performance comparison before/after
  • Verify: Snapshot testing to ensure behavior consistency

When NOT to Migrate

Be honest about these scenarios:

  • Application is being retired within 12 months
  • Heavily dependent on WPF or Windows Forms
  • Uses obscure third-party libraries with no .NET Core version
  • Team lacks bandwidth or expertise

Final Thoughts

Migrating from .NET Framework to .NET Core is a significant undertaking, but the benefits are real and substantial. Better performance, modern tooling, cloud-readiness, and a future-proof platform make it worthwhile.

Start small, learn as you go, and don't try to do everything at once. The path to modern .NET is a journey, not a sprint.

Have you gone through a .NET migration? What challenges did you face? I'd love to hear your experience.