Arctone Systems

← Articles

Moving a .NET Framework 4.8 Web API to .NET 10: what breaks

Frank Saraceno · October 11, 2026 · 8 min read

Most .NET Framework migrations don't fail because the code is hard to port. They fail because a handful of framework assumptions are baked into every corner of the app. Here are the ones you'll hit, roughly in the order you'll hit them.

A quick note on the target. If you're planning a move now, aim for .NET 10, the current long-term support release. .NET 8 reaches end of support in November 2026, so landing there today means planning a second upgrade almost immediately.

1. Everything that touches System.Web

ASP.NET Core has no System.Web. That means no HttpContext.Current, no Global.asax, no HttpModule or HttpHandler. In older codebases HttpContext.Current is often reached deep inside business logic to read the current user, a header or a session value.

The fix is to push those reads to the edge. Inject IHttpContextAccessor where you truly need it, but better still, pass the user ID or tenant in as a plain parameter. Modules and handlers become middleware. Code in Application_Start moves to Program.cs.

2. web.config settings

ConfigurationManager.AppSettings and connection strings in web.config become appsettings.json plus environment variables, read through IConfiguration or bound to typed options classes. This is a good moment to get secrets out of config files and into Azure Key Vault or your CI/CD variables.

Watch for config transforms (Web.Release.config). Their job is now done by appsettings.Production.json and environment variables, and teams often forget a value that only existed in a transform.

3. Routing and controllers

Web API 2 controllers inherit from ApiController; ASP.NET Core controllers inherit from ControllerBase. Return types like IHttpActionResult become IActionResult or ActionResult<T>. Routes registered in WebApiConfig need to move to attribute routes or MapControllerRoute.

Test every URL. Small differences in how default routes and optional parameters match will quietly change which action handles a request.

4. Dependency injection

If the app uses Unity, Ninject or an older Autofac setup, you'll move registrations to the built-in container, or keep Autofac through its ASP.NET Core integration. The bigger issue is usually lifetimes: services that were effectively singletons by accident, or that held per-request state, show up as bugs once the container enforces scopes.

5. JSON serialization

Web API 2 used Newtonsoft.Json. ASP.NET Core defaults to System.Text.Json, which differs in ways that break clients: property name casing, how it handles enums, dates, reference loops and case-insensitive matching on input.

If you have external consumers, the safe first step is AddNewtonsoftJson() so responses stay byte-for-byte the same. Move to System.Text.Json later, on purpose, with contract tests in place.

6. Authentication

OWIN middleware, Forms Authentication and custom AuthorizeAttribute subclasses all need replacing. Windows Authentication is still supported, but it's configured differently. For token-based APIs, the JWT bearer handler and policy-based authorization usually end up simpler than what they replace.

7. Entity Framework 6

You don't have to switch to EF Core on day one. EF6 runs on modern .NET, so you can move the web layer first and keep data access unchanged. That keeps the migration to one risky change at a time. When you do move to EF Core, check lazy loading, query translation differences and any EDMX models, which EF Core doesn't support.

8. WCF

Calling WCF services from .NET 10 works through the System.ServiceModel client packages. Hosting WCF services is the harder case: the community-supported CoreWCF project covers many scenarios, but plenty of teams take the migration as the moment to replace SOAP endpoints with REST or gRPC.

9. Removed and Windows-only APIs

Some things are simply gone: AppDomains, .NET Remoting and Code Access Security. BinaryFormatter was removed in .NET 9, so any code that serializes objects with it, often for caching or session state, needs a new format. Code that touches the registry, the event log or COM keeps working on Windows through compatibility packages, but it ties you to Windows hosting.

10. Shared class libraries

Libraries used by both old and new apps should multi-target, for example net48;net10.0, or target netstandard2.0 while both worlds coexist. Check every NuGet package for a modern build. An abandoned package is often the single biggest blocker in the whole project.

Don't do it as a big-bang rewrite

For a large API, the safest route is incremental. Put a reverse proxy (YARP) in front of the old app, stand up the new ASP.NET Core app behind it, and move endpoints over a few at a time. Microsoft's System.Web adapters help shared code run in both apps during the transition. Customers see one API the whole time, and every step can be rolled back.

Before moving anything, write characterization tests: tests that record what the current API actually returns, quirks included. They're what tell you a migrated endpoint behaves the same, which matters far more than whether it compiles.

Planning a migration?

I've moved large .NET applications to modern .NET for healthcare and finance companies, including breaking a monolith into 25 services. If you'd like a second opinion on your plan, get in touch.