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:
- Quick wins: Simple web APIs with minimal dependencies
- Medium complexity: MVC applications with some Windows-specific code
- Complex: Applications heavily dependent on .NET Framework features
- 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:
- Data access layer
- Business logic layer
- 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:
- Week 1: Created parallel .NET 8 project, migrated configuration
- Week 2-3: Migrated data access layer to EF Core
- Week 4: Converted business logic libraries to .NET Standard
- Week 5-6: Migrated API controllers, replaced OWIN auth with ASP.NET Core Identity
- Week 7: Comprehensive testing, performance benchmarking
- 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.