Migrating to ASP.NET Core
|
This section documents ASP.NET MVC 5.3.x, ASP.NET Web API 2.2, ASP.NET Web Pages 3, OWIN/Katana, SignalR 2,
and ASP.NET Identity 2 — all running on .NET Framework 4.8.1 — the This is not ASP.NET Core MVC. ASP.NET MVC 5 is the pre-Core, This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. This section’s bibliography lists the reference material consulted while preparing these pages. |
This page documents migrating from ASP.NET MVC 5.3.x on .NET Framework 4.8.1 to ASP.NET Core. It is referenced from Choosing an ASP.NET Framework, which covers when to migrate at all; this page covers the concrete mechanics once that decision is made.
The concept-to-concept mapping
| MVC 5 | ASP.NET Core |
|---|---|
|
|
|
Built-in |
|
|
|
|
HTML helpers ( |
Tag Helpers ( |
|
|
OWIN middleware ( |
ASP.NET Core middleware ( |
|
|
|
Policy-based authorization ( |
|
|
Web API 2 filters ( |
ASP.NET Core filters ( |
The ASPX view engine problem
Applications still carrying .aspx/.ascx views (the legacy WebFormViewEngine, superseded by Razor in MVC 3 — see Razor Syntax) have no automated conversion path: ASP.NET Core
has no ASPX view engine at all, and the WebForms control-tree model (postbacks, ViewState, server controls)
has no Core equivalent whatsoever. Every .aspx view must be hand-rewritten as Razor (or a Blazor component)
before the containing application can move — this is frequently the single largest line item in an MVC 5
migration estimate, and worth converting to .cshtml before starting the Core migration itself, as an
independent, lower-risk step on .NET Framework.
Incremental migration with System.Web.Adapters + YARP
For an application too large to migrate in one release, Microsoft’s supported incremental path runs the legacy
MVC 5 app and a new ASP.NET Core app side by side, routing traffic between them with YARP (Yet Another
Reverse Proxy) and sharing session/authentication state via System.Web.Adapters:
// In the new ASP.NET Core app
builder.Services.AddSystemWebAdapters()
.AddJsonSessionSerializer(options => options.RegisterKey<int>("UserId"))
.AddRemoteAppClient(options =>
{
options.RemoteAppUrl = new Uri("https://legacy.example.com/");
options.ApiKey = builder.Configuration["RemoteAppApiKey"];
});
app.UseSystemWebAdapters();
Requests are cut over route by route (YARP forwards unmigrated routes to the legacy MVC 5 app, migrated routes
to the new ASP.NET Core app), while System.Web.Adapters keeps HttpContext/session data readable from both
sides during the transition. See
Incremental ASP.NET to
ASP.NET Core migration.
The .NET Upgrade Assistant
For applications with limited System.Web-only surface, the .NET Upgrade Assistant
(dotnet tool install -g upgrade-assistant) automates much of the mechanical conversion: project-file format
(from packages.config/old-style .csproj to SDK-style), common namespace/API substitutions, and
web.config → appsettings.json scaffolding. It does not migrate ASPX views, OWIN middleware bodies, or
business logic — it removes boilerplate so a developer’s remaining work is the semantic changes below, not the
project-file mechanics.
upgrade-assistant upgrade MyApp.sln
What changes semantically (not just mechanically)
-
Sync-over-async — MVC 5 code that blocks on
.Result/.Wait()(see Caching and Performance) must become genuinelyasync/await; ASP.NET Core’s Kestrel/thread-pool model punishes blocking calls even more visibly than IIS did. -
HttpContext.Current— has no equivalent; every read must be replaced with an injectedHttpContext(via a constructor parameter orIHttpContextAccessor), which means any static helper or singleton service that reached forHttpContext.Currentneeds its call sites reworked, not just recompiled. -
TempDataproviders — MVC 5’sSessionStateTempDataProvider(see Controllers and Actions) becomes ASP.NET Core’s cookie-basedTempDataprovider by default; the one-read semantics are preserved but the storage mechanism, and therefore its size limits and farm behavior, differ. -
Model-binding differences — ASP.NET Core’s model binder unifies what MVC 5 split across MVC’s and Web API’s separate binders (see Model Binding and Validation and ASP.NET Web API 2); binding source attributes (
[FromBody],[FromRoute],[FromQuery]) become explicit rather than inferred from convention plus provider order, which occasionally changes what actually binds for an ambiguous parameter. -
Filters unify into one pipeline (MVC and Web API filters merge — see the mapping table above), so an application relying on the two filter hierarchies behaving differently needs that logic reconciled.
See ASP.NET to ASP.NET Core migration and Migrate from ASP.NET MVC to ASP.NET Core MVC for Microsoft’s own step-by-step guidance underlying this page.
See also the section landing page for every MVC 5 topic this migration touches, and Choosing an ASP.NET Framework for the decision of whether and when to migrate in the first place.