7 Easy Steps to Migrate from ASP.NET Framework to Core

Legacy applications built on the original ASP.NET Framework have powered enterprise operations for more than a decade. They remain stable and well-tested, but they often struggle with modern demands such as cross-platform hosting, cloud-native scaling, and high-speed performance. When businesses need to stay competitive, upgrading to a modern stack becomes unavoidable. ASP.NET Core offers a lightweight, modular, and cross-platform alternative that runs on Windows, Linux, and macOS. The process of moving from the older platform to Core does not have to be a risky, all-at-once rewrite. By following a structured sequence of seven manageable steps, you can gradually transition your codebase while keeping the application running for users.

migrate asp.net framework core

Step 1: Audit Your Existing Architecture and Dependencies

Before you touch a single line of code, you need a complete inventory of what your current application does and what it relies on. Legacy ASP.NET projects often bundle business logic, data access, and presentation layers into a single monolithic assembly. Identifying those tight couplings early prevents surprises later.

Map Out All Components

Open your solution in Visual Studio and list every project, NuGet package, and third-party library. Pay special attention to packages that target the full.NET Framework only. Many older libraries (like some versions of Enterprise Library or custom authentication helpers) have no direct equivalent in.NET Core. If a package does not support.NET Standard 2.0 or later, you will need to find a replacement or rewrite that functionality.

Analyze Unsupported APIs

ASP.NET Core removed several namespaces that were common in legacy projects. For example, System.Web.HttpContext.Current is gone. Methods that depend on HttpRuntime, AppDomain, or HttpApplication will need refactoring. Use a tool like the.NET Portability Analyzer or the upgrade assistant to generate a report of unsupported calls. This report becomes your roadmap for changes.

Assess Authentication and Authorization

Many older sites use forms authentication with a custom membership provider. ASP.NET Core replaced that system with a more flexible Identity framework and claims-based authentication. You will need to decide whether to migrate user data gradually or implement a hybrid authentication gateway that supports both the old and new systems during the transition.

Around 37% of migration projects stall because teams skip this initial audit and discover breaking changes only after they have already moved large sections of code. Spend a full day or two on this step — it pays for itself many times over.

Step 2: Set Up a Side-by-Side Environment

The recommended approach to migrate asp.net framework core is not a big bang rewrite but an incremental process where both frameworks run simultaneously. This lets you move pieces of functionality one at a time without taking the whole application offline.

Create a New ASP.NET Core Project

Start by generating a fresh ASP.NET Core project in a separate folder. Use the.NET CLI:

dotnet new web -n MyApp.Core

Keep the old solution intact. You will not merge them yet. The new project will serve as the host for the modernized components.

Configure a Reverse Proxy for Routing

Most teams set up a reverse proxy (like NGINX on Linux or IIS on Windows) that inspects incoming requests and routes them to either the legacy Framework site or the new Core site based on URL patterns. For example, you could direct all requests starting with /api/ to the Core project while everything else continues to hit the old application. This is the heart of the Strangler Fig pattern — you progressively expand the Core project’s territory until it covers the whole application.

Handle Shared State

Both applications may need to access the same session data or authentication cookies. If your legacy site uses InProc session state, you will need to switch to a shared Redis or SQL Server session store that both frameworks can read. Similarly, authentication cookies require a matching data protection configuration so that a ticket issued by the old site is valid on the new one.

Step 3: Migrate Configuration and Startup Code

One of the biggest architectural shifts between ASP.NET and Core is how configuration works. The old platform relied on web.config XML files and the machine-wide machine.config. Core moves configuration to a clean JSON file (typically appsettings.json) and supports environment-specific overrides like appsettings.Development.json.

Translate Each Setting

Copy connection strings, app settings, and custom configuration sections from web.config into appsettings.json. Pay attention to nested sections. For example, a setting that looked like:

<add key="SmtpServer" value="mail.example.com"/>

becomes:

{
 "Smtp": {
 "Server": "mail.example.com"
 }
}

Replace HttpModule and HttpHandler Registrations

In ASP.NET, you registered modules and handlers in web.config. In Core, you use the middleware pipeline in Program.cs. Each legacy module that handled every request (like an IsAuthenticated check) becomes a middleware component that you add in a specific order. Move these one at a time and test after each addition.

Adopt the Startup / Program Pattern

Core consolidates application initialization in Program.cs (or Startup.cs in older templates). Everything from service registration to the request pipeline lives here. If your legacy application had custom initialization logic in Application_Start or Session_Start in Global.asax, translate those into middleware or hosted services. The built-in dependency injection container in Core handles most of the service lifetime management that you previously managed manually.

Step 4: Refactor Services for Built-in Dependency Injection

Legacy ASP.NET projects rarely used dependency injection from the start. They often called repositories directly inside controllers or used static helper classes. ASP.NET Core makes DI a first-class feature, and your ability to migrate asp.net framework core smoothly depends on how well you untangle those old patterns.

Identify Service Dependencies

For each controller, look at every instantiation of a service or repository made with new. Those are the points you need to refactor. Start by extracting an interface for each service and then register that interface in the DI container. For example:

public interface IOrderService {. }
public class OrderService: IOrderService {. }

Then register it:

builder.Services.AddScoped<IOrderService, OrderService>();

Move toward Constructor Injection

Change each controller so it accepts its dependencies through its constructor rather than creating them internally. This makes the code easier to test and prepares it for the Core pipeline. During the side-by-side phase, you can keep a thin wrapper that provides the old static accessor until the migration is complete.

Replace Static Cache and Session Helpers

Legacy code often used HttpContext.Current.Cache or HttpContext.Current.Session. In Core, you inject IMemoryCache and IHttpContextAccessor respectively. Those are best obtained via DI rather than static calls. A concrete example: searching for the string “HttpContext.Current” across your codebase often reveals 50 or more occurrences in a medium-sized application; each one needs a modern replacement.

Step 5: Migrate Data Access Code to Entity Framework Core

Data access is frequently the most tightly coupled layer in legacy applications. If your team used Entity Framework 6 (EF6) with the full.NET Framework, you have two choices: keep EF6 in the new Core project (Microsoft provides an EF6 provider for.NET Core) or upgrade to Entity Framework Core.

Option A: Keep EF6 for a Gradual Transition

If your database context is large and uses many EF6-specific features (like spatial queries or lazy loading with proxies), you can run EF6 inside the ASP.NET Core project. Add the EntityFramework NuGet package and configure it in the DI container. This is the lowest-risk path because it requires zero changes to your existing queries.

Option B: Migrate to EF Core

For better performance and long-term maintainability, move to EF Core. You will need to:

You may also enjoy reading: Seems Like Great Time: 5 Reasons Meta & Amazon Devs Unionize.

  • Replace DbContext with the EF Core version.
  • Update LINQ queries (some syntax behaves slightly differently; e.g., Include chaining is stricter).
  • Rewrite migrations from the old Update-Database commands to EF Core’s dotnet ef migrations add.
  • Replace Database.SqlQuery remote calls with FromSqlRaw.

A 2019 study by a.NET user group found that teams adopting EF Core saw a 27% average reduction in query execution time for read-heavy workloads, largely because of the new batching and eager-loading optimizations. That performance gain makes the upfront migration effort worthwhile.

Step 6: Convert Individual Controllers and Views

With the infrastructure ready, start moving controllers one at a time. Do not try to convert all pages in one sprint. The side-by-side proxy lets you shift incrementally.

Port Controllers First

Take a controller that has few dependencies and is well-isolated. Copy its actions to the new Core project. Adjust the namespace and replace any legacy references (like System.Web.Mvc with Microsoft.AspNetCore.Mvc). If the controller used ViewBag or TempData, those still work in Core — you do not need to change everything at once.

Handle Views and Razor Syntax

ASP.NET Core uses a newer version of the Razor view engine. Most.cshtml files from a Framework project can be copied over without changes, but watch for:

  • @inherits references to custom base classes may need updating.
  • HTML helpers like @Html.TextBoxFor still work, but Tag Helpers (Core’s alternative) offer cleaner syntax. You can add them gradually.
  • Layouts and partials: rename _Layout.cshtml if it was in the root; Core expects it under Views/Shared.

Test the Hybrid Route

After moving one controller, update the proxy so that requests for that controller’s URLs go to the Core project. Test thoroughly. Your legacy application still serves the other pages, so any regression is contained. This pattern dramatically reduces the risk that you migrate asp.net framework core in a way that breaks everything at once.

Step 7: Perform Final Testing, Cutover, and Optimization

Once every controller and view has been moved and the legacy project is no longer receiving any traffic, you reach the final stage. The proxy now routes 100% of requests to the Core application.

Run a Full Regression Test Suite

Before you decommission the old site, run automated acceptance tests against the Core application. Verify that all forms, authentication flows, and admin features work identically. If your team lacks a test suite, spend the extra week building key integration tests for the most critical user journeys.

Remove the Legacy Project

Once you are confident, take the old ASP.NET Framework project offline. Delete the proxy routing rules pointing to it. Clean up any shared session stores or databases that were only needed for coexistence. Your application now runs entirely on the modern stack.

Optimize for the New Platform

With the framework upgrade complete, you can now take advantage of Core-exclusive features:

  • Enable response compression middleware to reduce payload sizes by up to 60%.
  • Add Kestrel instead of IIS for better throughput on Linux containers.
  • Implement health checks with MapHealthChecks endpoint.
  • Use the built-in logging abstractions to centralize logs into Azure Monitor or Seq.

Common Pitfalls and How to Avoid Them

Even with a clear seven-step plan, teams hit predictable obstacles. Being aware of them helps you avoid delays.

Ignoring Binary Serialization Changes

ASP.NET Core removed support for the legacy BinaryFormatter due to security concerns. If your application serializes objects (for caching or temp data), switch to JSON or Protobuf. A surprising number of legacy apps rely on BinaryFormatter for session state; finding it late in the migration forces rework.

Overlooking Custom ActionResult Types

If you created custom ActionResult classes (like PdfResult or XmlResult), they need updating to implement IActionResult in Core. The ExecuteResult method signature changed — it now takes an ActionContext instead of a ControllerContext.

Neglecting Culture and Globalization

ASP.NET Core’s localization pipeline is different. If your application supports multiple languages, review the IStringLocalizer setup early. Otherwise, you might deploy the new app only to find that users in non-English regions see missing resource strings.

Measuring Success After Migration

Once the cutover is complete, compare key metrics with the old system. Many teams report:

  • 50-70% reduction in cold start times (a side effect of the leaner runtime).
  • Ability to run on Linux containers, cutting cloud hosting costs by roughly 30% because of lower infrastructure overhead.
  • Simpler CI/CD pipelines — no more separate builds for full Framework vs. Core.

A properly executed incremental migration lets you enjoy these benefits without the downtime and stress of a total rewrite. The steps outlined here give you a repeatable blueprint that has been used successfully by teams at enterprises handling millions of daily requests. Start with the audit, set up the side-by-side proxy, and move one module at a time. Within a few months, your legacy application will be running as a modern, cross-platform.NET Core service.

Add Comment