From 51cd5bab0bbd2b31e30798a5f735b8eeb2e2783e Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 30 Jun 2025 08:51:17 -0700 Subject: [PATCH 01/61] Initial fx-to-core session rewrite --- .../migration/fx-to-core/areas/session.md | 137 ++++++++++++++++++ .../fx-to-core/inc/remote-session.md | 59 -------- .../migration/fx-to-core/inc/session.md | 49 ------- .../migration/fx-to-core/inc/wrapped.md | 22 --- .../includes/uses-systemweb-adapters.md | 2 + aspnetcore/toc.yml | 8 +- 6 files changed, 141 insertions(+), 136 deletions(-) create mode 100644 aspnetcore/migration/fx-to-core/areas/session.md delete mode 100644 aspnetcore/migration/fx-to-core/inc/remote-session.md delete mode 100644 aspnetcore/migration/fx-to-core/inc/session.md delete mode 100644 aspnetcore/migration/fx-to-core/inc/wrapped.md create mode 100644 aspnetcore/migration/fx-to-core/includes/uses-systemweb-adapters.md diff --git a/aspnetcore/migration/fx-to-core/areas/session.md b/aspnetcore/migration/fx-to-core/areas/session.md new file mode 100644 index 000000000000..6cab243834ee --- /dev/null +++ b/aspnetcore/migration/fx-to-core/areas/session.md @@ -0,0 +1,137 @@ +--- +title: ASP.NET to ASP.NET Core incremental session state migration +description: ASP.NET to ASP.NET Core incremental session state migration +author: rick-anderson +ms.author: riande +monikerRange: '>= aspnetcore-6.0' +ms.date: 11/9/2022 +ms.topic: article +uid: migration/fx-to-core/areas/session +--- + +# Migrate ASP.NET Framework Session to ASP.NET Core + +For most applications, migrating to [ASP.NET Core session](fundamentals/app-state) provides the best performance and maintainability. However, larger applications may need an incremental approach using System.Web adapters. + +[!INCLUDE[](~/aspnetcore/migration/fx-to-core/includes/uses-systemweb-adapters.md)] + +## Choose your migration approach + +Two migration strategies are available, each designed for different scenarios: + +| Implementation | Best for | Strongly typed | Locking | Session sharing | +|----------------|----------|----------------|---------|-----------------| +| [Wrapped ASP.NET Core](#wrapped-aspnet-core-session-state) | Migrations where session doesn't need to be shared with the legacy app | ✔️ | ⛔ | ⛔ | +| [Remote app](#remote-app-session-state) | Incremental migrations requiring shared session state between apps | ✔️ | ✔️ | ✔️ | + +**Use Wrapped ASP.NET Core session** when: +* You're migrating components that don't need to share session data with the legacy application +* You want to leverage ASP.NET Core's native session infrastructure +* You're doing a more complete migration where both apps don't run simultaneously + +**Use Remote app session** when: +* You need to share session state between your ASP.NET Framework and ASP.NET Core applications +* You're running both applications simultaneously during migration +* You require the same session locking behavior as ASP.NET Framework + +## Understanding the technical differences + +These differences between ASP.NET Framework and Core determine your migration approach: + +### Session locking + +* ASP.NET Framework locks session usage within a session, handling subsequent requests serially +* ASP.NET Core provides no session locking guarantees + +### Object serialization + +* ASP.NET Framework automatically serializes and deserializes objects (unless using in-memory storage) +* ASP.NET Core requires manual serialization/deserialization and stores data as `byte[]` + +### Adapter infrastructure + +The [System.Web adapters](~/aspnetcore/migration/fx-to-core/inc/systemweb-adapters.md) bridge these differences through two key interfaces: + +* : Accepts an and session metadata, returns an `ISessionState` object +* `Microsoft.AspNetCore.SystemWebAdapters.ISessionState`: Describes session object state and backs the type + +## Wrapped ASP.NET Core session state + +Choose this approach when your migrated components don't need to share session data with your legacy application. + +The method adds a wraps ASP.NET Core session to work with the adapters. It uses the same backing store as [`Microsoft.AspNetCore.Http.ISession`](/dotnet/api/microsoft.aspnetcore.http.isession) while providing strongly-typed access. + +**Configuration for ASP.NET Core:** + +:::code language="csharp" source="~/migration/fx-to-core/inc/samples/wrapped/Program.cs" id="snippet_WrapAspNetCoreSession" ::: + +Your Framework application requires no changes. + +For more information, see the [wrapped session state sample app](https://github.com/dotnet/systemweb-adapters/blob/main/samples/SessionLocal/SessionLocalCore/Program.cs) + +## Remote app session state + +Choose this approach when you need to share session state between your ASP.NET Framework and ASP.NET Core applications during incremental migration. + +Remote app session enables communication between applications to retrieve and set session state by exposing an endpoint on the ASP.NET Framework app. + +### Prerequisites + +Complete the [remote app setup](xref:migration/fx-to-core/inc/remote-app-setup) instructions to connect your ASP.NET Core and ASP.NET Framework applications. + +### Serialization configuration + +The object requires serialization for remote app session state. + +**For HttpSessionState serialization**, implement `Microsoft.AspNetCore.SystemWebAdapters.SessionState.Serialization.ISessionSerializer`. A default binary writer implementation is provided: + +:::code language="csharp" source="~/migration/fx-to-core/inc/samples/remote-session/Program.cs" id="snippet_Serialization" ::: + +**For strongly-typed session access**, configure JSON serialization. Register each session key to a known type using `JsonSessionSerializerOptions`: + +* `RegisterKey(string)` - Registers a session key to a known type. This registration is required for correct serialization/deserialization. Missing registrations cause errors and prevent session access. + +:::code language="csharp" source="~/migration/fx-to-core/inc/samples/session/Program.cs" id="snippet_Serialization" ::: + +### Application configuration + +**ASP.NET Core configuration:** + +Call `AddRemoteAppSession` and `AddJsonSessionSerializer` to register known session item types: + +:::code language="csharp" source="~/migration/fx-to-core/inc/samples/remote-session/Program.cs" id="snippet_Configuration" ::: + +Session support requires explicit activation. Configure it per-route using ASP.NET Core metadata. + +#### Option 1: Annotate controllers + +:::code language="csharp" source="~/migration/fx-to-core/inc/samples/remote-session/SomeController.cs" id="snippet_Controller" ::: + +#### Option 2: Enable globally for all endpoints + +:::code language="csharp" source="~/migration/fx-to-core/inc/samples/remote-session/Program.cs" id="snippet_RequireSystemWebAdapterSession" ::: + +**ASP.NET Framework configuration:** + +Add this change to `Global.asax.cs`: + +:::code language="csharp" source="~/migration/fx-to-core/inc/samples/remote-session/Global.asax.cs"::: + +### Communication protocol + +#### Readonly sessions + +Readonly sessions retrieve session state without locking. The process uses a single `GET` request that returns session state and closes immediately. + +![Readonly session will retrieve the session state from the framework app](~/migration/fx-to-core/inc/overview/static/readonly_session.png) + +#### Writeable sessions + +Writeable sessions require additional steps: + +* Start with the same `GET` request as readonly sessions +* Keep the initial `GET` request open until the session completes +* Use an additional `PUT` request to update state +* Close the initial request only after updating is complete + +![Writeable session state protocol starts with the same as the readonly](~/migration/fx-to-core/inc/overview/static/writesession.png) diff --git a/aspnetcore/migration/fx-to-core/inc/remote-session.md b/aspnetcore/migration/fx-to-core/inc/remote-session.md deleted file mode 100644 index da7aa64f6438..000000000000 --- a/aspnetcore/migration/fx-to-core/inc/remote-session.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -title: Remote app session state -description: Remote app session state -author: rick-anderson -ms.author: riande -monikerRange: '>= aspnetcore-6.0' -ms.date: 11/9/2022 -ms.topic: article -uid: migration/fx-to-core/inc/remote-session ---- - -# Remote app session state - -Remote app session state will enable communication between the ASP.NET Core and ASP.NET app to retrieve the session state. This is enabled by exposing an endpoint on the ASP.NET app that can be queried to retrieve and set the session state. - -## HttpSessionState serialization - -The object must be serialized for remote app session state to be enabled. This is accomplished through implementation of the type `Microsoft.AspNetCore.SystemWebAdapters.SessionState.Serialization.ISessionSerializer`, of which a default binary writer implementation is provided. This is added by the following code: - -:::code language="csharp" source="~/migration/fx-to-core/inc/samples/remote-session/Program.cs" id="snippet_Serialization" ::: - -## Configuration - -First, follow the [remote app setup](xref:migration/fx-to-core/inc/remote-app-setup) instructions to connect the ASP.NET Core and ASP.NET apps. Then, there are just a couple extra extension methods to call to enable remote app session state. - -Configuration for ASP.NET Core involves calling `AddRemoteAppSession` and `AddJsonSessionSerializer` to register known session item types. The code should look similar to the following: - -:::code language="csharp" source="~/migration/fx-to-core/inc/samples/remote-session/Program.cs" id="snippet_Configuration" ::: - -Session support requires additional work for the ASP.NET Core pipeline, and is not turned on by default. It can be configured on a per-route basis via ASP.NET Core metadata. - -For example, session support requires either to annotate a controller: - -:::code language="csharp" source="~/migration/fx-to-core/inc/samples/remote-session/SomeController.cs" id="snippet_Controller" ::: - -or to enable for all endpoints by default: - -:::code language="csharp" source="~/migration/fx-to-core/inc/samples/remote-session/Program.cs" id="snippet_RequireSystemWebAdapterSession" ::: - -The framework equivalent would look like the following change in `Global.asax.cs`: - -:::code language="csharp" source="~/migration/fx-to-core/inc/samples/remote-session/Global.asax.cs"::: - -## Protocol - -### Readonly - -Readonly session will retrieve the session state from the framework app without any sort of locking. This consists of a single `GET` request that will return a session state and can be closed immediately. - -![Readonly session will retrieve the session state from the framework app](~/migration/fx-to-core/inc/overview/static/readonly_session.png) - -## Writeable - -Writeable session state protocol starts with the same as the readonly, but differs in the following: - -* Requires an additional `PUT` request to update the state -* The initial `GET` request must be kept open until the session is done; if closed, the session will not be able to be updated - -![Writeable session state protocol starts with the same as the readonly](~/migration/fx-to-core/inc/overview/static/writesession.png) diff --git a/aspnetcore/migration/fx-to-core/inc/session.md b/aspnetcore/migration/fx-to-core/inc/session.md deleted file mode 100644 index 4f1ea3107f94..000000000000 --- a/aspnetcore/migration/fx-to-core/inc/session.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -title: ASP.NET to ASP.NET Core incremental session state migration -description: ASP.NET to ASP.NET Core incremental session state migration -author: rick-anderson -ms.author: riande -monikerRange: '>= aspnetcore-6.0' -ms.date: 11/9/2022 -ms.topic: article -uid: migration/fx-to-core/inc/session ---- - -# ASP.NET to ASP.NET Core incremental session state migration - -## Session State - -Session state in ASP.NET Framework provided a number of features that ASP.NET Core does not provide. In order to update from ASP.NET Framework to Core, the adapters provide mechanisms to enable populating session state with similar behavior as `System.Web` did. Some of the differences between framework and core are: - -* ASP.NET Framework would lock session usage within a session, so subsequent requests in a session are handled in a serial fashion. This is different than ASP.NET Core that does not provide any of these guarantees. -* ASP.NET Framework would serialize and deserialize objects automatically (unless being done in-memory). ASP.NET Core provides a mechanism to store a `byte[]` given a key. Any object serialization/deserialization has to be done manually by the user. - -The adapter infrastructure exposes two interfaces that can be used to implement any session storage system. These are: - -* `Microsoft.AspNetCore.SystemWebAdapters.ISessionManager`: This has a single method that gets passed an and the session metadata and expects an `ISessionState` object to be returned. -* `Microsoft.AspNetCore.SystemWebAdapters.ISessionState`: This describes the state of a session object. It is used as the backing of the type. - -## Serialization -Since the adapters provide the ability to work with strongly-typed session state, we must be able to serialize and deserialize types. This is customized through the `Microsoft.AspNetCore.SystemWebAdapters.SessionState.Serialization.ISessionKeySerializer`. - -A default JSON implementation is provided that is configured via the `JsonSessionSerializerOptions`: - -* `RegisterKey(string)` - Registers a session key to a known type. This is required in order to serialize/deserialize the session state correctly. If a key is found that there is no registration for, an error will be thrown and session will not be available. - - -:::code language="csharp" source="~/migration/fx-to-core/inc/samples/session/Program.cs" id="snippet_Serialization" ::: - -## Implementations - -There are two available implementations of the session state object that currently ship, each with some trade offs of features. The best choice for an app may depend on which part of the migration it is in, and may change over time. - -* Strongly typed: Provides the ability to access an object and can be cast to the expected type -* Locking: Ensures multiple requests within a single session are queued up and aren't accessing the session at the same time -* Standalone: Use when you're not sharing session between ASP.NET Framework and ASP.NET Core to avoid modifying code in class libraries that references SessionState - -Below are the available implementations: - -| Implementation | Strongly typed | Locking | Standalone | -|-------------------------------------------------------------|----------------|---------|------------| -| [Remote app](xref:migration/fx-to-core/inc/remote-session) | ✔️ | ✔️ | ⛔ | -| [Wrapped ASP.NET Core](xref:migration/fx-to-core/inc/wrapped) | ✔️ | ⛔ | ✔️ | diff --git a/aspnetcore/migration/fx-to-core/inc/wrapped.md b/aspnetcore/migration/fx-to-core/inc/wrapped.md deleted file mode 100644 index 68c75cad73f2..000000000000 --- a/aspnetcore/migration/fx-to-core/inc/wrapped.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -title: Wrapped ASP.NET Core session state -description: Wrapped ASP.NET Core session state -author: rick-anderson -ms.author: riande -monikerRange: '>= aspnetcore-6.0' -ms.date: 2/24/2025 -ms.topic: article -uid: migration/fx-to-core/inc/wrapped ---- - -# Wrapped ASP.NET Core session state - -The [AddWrappedAspNetCoreSession](https://github.com/dotnet/systemweb-adapters/blob/main/src/Microsoft.AspNetCore.SystemWebAdapters.CoreServices/SessionState/Wrapped/WrappedSessionExtensions.cs) implementation wraps the session provided on ASP.NET Core so that it can be used with the adapters. The session uses the same backing store as [`Microsoft.AspNetCore.Http.ISession`](/dotnet/api/microsoft.aspnetcore.http.isession) but provides strongly-typed access to its members. - -Configuration for ASP.NET Core looks similar to the following: - -:::code language="csharp" source="~/migration/fx-to-core/inc/samples/wrapped/Program.cs" id="snippet_WrapAspNetCoreSession" ::: - -The framework app doesn't need any changes to enable this behavior. - -For more information, see the [AddWrappedAspNetCoreSession sample app](https://github.com/dotnet/systemweb-adapters/blob/main/samples/CoreApp/Program.cs) diff --git a/aspnetcore/migration/fx-to-core/includes/uses-systemweb-adapters.md b/aspnetcore/migration/fx-to-core/includes/uses-systemweb-adapters.md new file mode 100644 index 000000000000..e62d0884e33b --- /dev/null +++ b/aspnetcore/migration/fx-to-core/includes/uses-systemweb-adapters.md @@ -0,0 +1,2 @@ +> [!NOTE] +> This makes use of the [System.Web Adapters](~/aspnetcore/migration/fx-to-core/inc/systemweb-adapters.md) to simplify migration. diff --git a/aspnetcore/toc.yml b/aspnetcore/toc.yml index 61e3e17209cb..5b5f8111c0e3 100644 --- a/aspnetcore/toc.yml +++ b/aspnetcore/toc.yml @@ -2111,12 +2111,6 @@ items: uid: migration/fx-to-core/inc/remote-app-setup - name: Usage Guidance uid: migration/fx-to-core/inc/usage_guidance - - name: Wrapped session state - uid: migration/fx-to-core/inc/wrapped - - name: Session state migration - uid: migration/fx-to-core/inc/session - - name: Remote app session state - uid: migration/fx-to-core/inc/remote-session - name: Remote Authentication uid: migration/fx-to-core/inc/remote-authentication - name: Unit testing @@ -2145,6 +2139,8 @@ items: uid: migration/fx-to-core/areas/http-modules - name: HTTP Handlers uid: migration/fx-to-core/areas/http-handlers + - name: Session + uid: migration/fx-to-core/areas/session - name: Membership uid: migration/fx-to-core/areas/membership - name: Web API From 46e0529b7f6b1b962ada1930664caa0465ef1681 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 30 Jun 2025 08:58:40 -0700 Subject: [PATCH 02/61] update --- aspnetcore/migration/fx-to-core/areas/session.md | 4 ++-- aspnetcore/migration/fx-to-core/inc/remote-app-setup.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/aspnetcore/migration/fx-to-core/areas/session.md b/aspnetcore/migration/fx-to-core/areas/session.md index 6cab243834ee..2b15c6d272d1 100644 --- a/aspnetcore/migration/fx-to-core/areas/session.md +++ b/aspnetcore/migration/fx-to-core/areas/session.md @@ -13,7 +13,7 @@ uid: migration/fx-to-core/areas/session For most applications, migrating to [ASP.NET Core session](fundamentals/app-state) provides the best performance and maintainability. However, larger applications may need an incremental approach using System.Web adapters. -[!INCLUDE[](~/aspnetcore/migration/fx-to-core/includes/uses-systemweb-adapters.md)] +[!INCLUDE[](~/migration/fx-to-core/includes/uses-systemweb-adapters.md)] ## Choose your migration approach @@ -59,7 +59,7 @@ The [System.Web adapters](~/aspnetcore/migration/fx-to-core/inc/systemweb-adapte Choose this approach when your migrated components don't need to share session data with your legacy application. -The method adds a wraps ASP.NET Core session to work with the adapters. It uses the same backing store as [`Microsoft.AspNetCore.Http.ISession`](/dotnet/api/microsoft.aspnetcore.http.isession) while providing strongly-typed access. +The method adds a wraps ASP.NET Core session to work with the adapters. It uses the same backing store as while providing strongly-typed access. **Configuration for ASP.NET Core:** diff --git a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md index 3b051c4db461..c025b3f5ca91 100644 --- a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md +++ b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md @@ -13,7 +13,7 @@ uid: migration/fx-to-core/inc/remote-app-setup In some incremental upgrade scenarios, it's useful for the new ASP.NET Core app to be able to communicate with the original ASP.NET app. -Specifically, this capability is used, currently, for [remote app authentication](xref:migration/fx-to-core/inc/remote-authentication) and [remote session](xref:migration/fx-to-core/inc/remote-session) features. +Specifically, this capability is used, currently, for [remote app authentication](xref:migration/fx-to-core/inc/remote-authentication) and [remote session](xref:migration/fx-to-core/areas/session#remote) features. ## Configuration From 7213d945bdc07b506cefbb39a67ba1d60ecefc56 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 30 Jun 2025 09:17:44 -0700 Subject: [PATCH 03/61] Include built-in asp.net session migration --- .../migration/fx-to-core/areas/session.md | 78 +++++++++++++++---- .../fx-to-core/inc/remote-app-setup.md | 6 +- .../fx-to-core/inc/usage_guidance.md | 4 +- .../includes/uses-systemweb-adapters.md | 2 +- 4 files changed, 67 insertions(+), 23 deletions(-) diff --git a/aspnetcore/migration/fx-to-core/areas/session.md b/aspnetcore/migration/fx-to-core/areas/session.md index 2b15c6d272d1..021773f79e2c 100644 --- a/aspnetcore/migration/fx-to-core/areas/session.md +++ b/aspnetcore/migration/fx-to-core/areas/session.md @@ -11,55 +11,99 @@ uid: migration/fx-to-core/areas/session # Migrate ASP.NET Framework Session to ASP.NET Core -For most applications, migrating to [ASP.NET Core session](fundamentals/app-state) provides the best performance and maintainability. However, larger applications may need an incremental approach using System.Web adapters. +For most applications, migrating to [ASP.NET Core session](~/fundamentals/app-state) provides the best performance and maintainability. However, larger applications may need an incremental approach using System.Web adapters. [!INCLUDE[](~/migration/fx-to-core/includes/uses-systemweb-adapters.md)] ## Choose your migration approach -Two migration strategies are available, each designed for different scenarios: +There are a few options available for how to migrate session usage. As you decide which migration pattern to use, it helps to understand the differences between ASP.NET Framework and Core session designs: + +* **Object serialization** + * ASP.NET Framework automatically serializes and deserializes objects (unless using in-memory storage) + * ASP.NET Core requires manual serialization/deserialization and stores data as `byte[]` +* **Session locking** + * ASP.NET Framework locks session usage within a session, handling subsequent requests serially + * ASP.NET Core provides no session locking guarantees + +The [System.Web adapters](~/migration/fx-to-core/inc/systemweb-adapters.md) bridge these differences through two key interfaces: + +* `Microsoft.AspNetCore.SystemWebAdapters.ISessionManager`: Accepts an and session metadata, returns an `ISessionState` object +* `Microsoft.AspNetCore.SystemWebAdapters.ISessionState`: Describes session object state and backs the type + +The main scenarios covered in this document are: | Implementation | Best for | Strongly typed | Locking | Session sharing | |----------------|----------|----------------|---------|-----------------| +| [Built-in ASP.NET Core](#built-in-aspnet-core-session-state) | Complete rewrites with no legacy session compatibility needed | ⛔ | ⛔ | ⛔ | | [Wrapped ASP.NET Core](#wrapped-aspnet-core-session-state) | Migrations where session doesn't need to be shared with the legacy app | ✔️ | ⛔ | ⛔ | | [Remote app](#remote-app-session-state) | Incremental migrations requiring shared session state between apps | ✔️ | ✔️ | ✔️ | -**Use Wrapped ASP.NET Core session** when: +**Use built-in ASP.NET Core session** when: +* You're performing a complete rewrite and don't need System.Web compatibility +* You can rewrite all session-related code to use ASP.NET Core patterns +* You want the best performance and smallest footprint +* You don't need to maintain session data structure compatibility with legacy code + +**Use wrapped ASP.NET Core session** when: * You're migrating components that don't need to share session data with the legacy application * You want to leverage ASP.NET Core's native session infrastructure * You're doing a more complete migration where both apps don't run simultaneously -**Use Remote app session** when: +**Use remote app session** when: * You need to share session state between your ASP.NET Framework and ASP.NET Core applications * You're running both applications simultaneously during migration * You require the same session locking behavior as ASP.NET Framework -## Understanding the technical differences +## Built-in ASP.NET Core session state -These differences between ASP.NET Framework and Core determine your migration approach: +Choose this approach when you're performing a complete migration and can rewrite session-related code to use ASP.NET Core's native session implementation. -### Session locking +ASP.NET Core provides a lightweight, high-performance session state implementation that stores data as `byte[]` and requires explicit serialization. This approach offers the best performance but requires more code changes during migration. -* ASP.NET Framework locks session usage within a session, handling subsequent requests serially -* ASP.NET Core provides no session locking guarantees +For details on how to set this up and use it, see the [ASP.NET session documentation](~/fundamentals/app-state). -### Object serialization +### Pros and cons -* ASP.NET Framework automatically serializes and deserializes objects (unless using in-memory storage) -* ASP.NET Core requires manual serialization/deserialization and stores data as `byte[]` +| Pros | Cons | +|------|------| +| Best performance and lowest memory footprint | Requires rewriting all session access code | +| Native ASP.NET Core implementation | No automatic object serialization | +| Full control over serialization strategy | No session locking (concurrent requests may conflict) | +| No additional dependencies | Breaking change from ASP.NET Framework patterns | +| Supports all ASP.NET Core session providers | Session keys are case-sensitive (unlike Framework) | -### Adapter infrastructure +### Migration considerations -The [System.Web adapters](~/aspnetcore/migration/fx-to-core/inc/systemweb-adapters.md) bridge these differences through two key interfaces: +When migrating to built-in ASP.NET Core session: -* : Accepts an and session metadata, returns an `ISessionState` object -* `Microsoft.AspNetCore.SystemWebAdapters.ISessionState`: Describes session object state and backs the type +**Code changes required:** +* Replace `Session["key"]` with `HttpContext.Session.GetString("key")` +* Replace `Session["key"] = value` with `HttpContext.Session.SetString("key", value)` +* Add explicit serialization/deserialization for complex objects +* Handle null values explicitly (no automatic type conversion) + +**Data migration:** +* Session data structure changes require careful planning +* Consider running both systems in parallel during migration +* Implement session data import/export utilities if needed + +**Testing strategy:** +* Unit test session serialization/deserialization logic +* Integration test session behavior across requests +* Load test concurrent session access patterns + +**When to choose this approach:** +* You can afford to rewrite session-related code +* Performance is a top priority +* You're not sharing session data with legacy applications +* You want to eliminate System.Web dependencies completely ## Wrapped ASP.NET Core session state Choose this approach when your migrated components don't need to share session data with your legacy application. -The method adds a wraps ASP.NET Core session to work with the adapters. It uses the same backing store as while providing strongly-typed access. +The `Microsoft.Extensions.DependencyInjection.WrappedSessionExtensions.AddWrappedAspNetCoreSession` extension method adds a wraps ASP.NET Core session to work with the adapters. It uses the same backing store as while providing strongly-typed access. **Configuration for ASP.NET Core:** diff --git a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md index c025b3f5ca91..32c39a10a2d1 100644 --- a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md +++ b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md @@ -13,7 +13,7 @@ uid: migration/fx-to-core/inc/remote-app-setup In some incremental upgrade scenarios, it's useful for the new ASP.NET Core app to be able to communicate with the original ASP.NET app. -Specifically, this capability is used, currently, for [remote app authentication](xref:migration/fx-to-core/inc/remote-authentication) and [remote session](xref:migration/fx-to-core/areas/session#remote) features. +Specifically, this capability is used, currently, for [remote app authentication](xref:migration/fx-to-core/inc/remote-authentication) and [remote session](xref:migration/fx-to-core/areas/session#remote-app-session-state) features. ## Configuration @@ -22,7 +22,7 @@ To enable the ASP.NET Core app to communicate with the ASP.NET app, it's necessa ### ASP.NET app configuration To set up the ASP.NET app to be able to receive requests from the ASP.NET Core app: -1. Install the nuget package [`Microsoft.AspNetCore.SystemWebAdapters.FrameworkServices`](https://www.nuget.org/packages/Microsoft.AspNetCore.SystemWebAdapters) +1. Install the NuGet package [`Microsoft.AspNetCore.SystemWebAdapters.FrameworkServices`](https://www.nuget.org/packages/Microsoft.AspNetCore.SystemWebAdapters) 2. Call the `AddRemoteAppServer` extension method on the `ISystemWebAdapterBuilder`: ```CSharp @@ -69,7 +69,7 @@ In the preceding code: * The `AddRemoteApp` call is used to configure the remote app's URL and the shared secret API key. * The `RemoteAppUrl` property specifies the URL of the ASP.NET Framework app that the ASP.NET Core app communicates with. In this example, the URL is read from an existing configuration setting used by the YARP proxy that proxies requests to the ASP.NET Framework app as part of the incremental migration's *strangler fig pattern*. -With both the ASP.NET and ASP.NET Core app updated, extension methods can now be used to set up [remote app authentication](xref:migration/fx-to-core/inc/remote-authentication) or [remote session](xref:migration/fx-to-core/inc/remote-session), as needed. +With both the ASP.NET and ASP.NET Core app updated, extension methods can now be used to set up [remote app authentication](xref:migration/fx-to-core/inc/remote-authentication) or [remote session](xref:migration/fx-to-core/areas/session#remote-app-session-state), as needed. ## Securing the remote app connection diff --git a/aspnetcore/migration/fx-to-core/inc/usage_guidance.md b/aspnetcore/migration/fx-to-core/inc/usage_guidance.md index 84401431e1ec..7e44deaf97aa 100644 --- a/aspnetcore/migration/fx-to-core/inc/usage_guidance.md +++ b/aspnetcore/migration/fx-to-core/inc/usage_guidance.md @@ -97,11 +97,11 @@ app.MapDefaultControllerRoute() .RequireSystemWebAdapterSession(); ``` -This also requires some implementation of a session store. For details of options here, see [here](xref:migration/fx-to-core/inc/session). +This also requires some implementation of a session store. For details of options here, see [migration guidance for session](xref:migration/fx-to-core/areas/session). ## Remote session exposes additional endpoint for application -The [remote session support](xref:migration/fx-to-core/inc/remote-session) exposes an endpoint that allows the core app to retrieve session information. This may cause a potentially long-lived request to exist between the core app and the framework app, but will time out with the current request or the session timeout (by default is 20 minutes). +The [remote session support](xref:migration/fx-to-core/areas/session#remote-app-session-state) exposes an endpoint that allows the core app to retrieve session information. This may cause a potentially long-lived request to exist between the core app and the framework app, but will time out with the current request or the session timeout (by default is 20 minutes). **Recommendation**: Ensure the API key used is a strong one and that the connection with the framework app is done over SSL. diff --git a/aspnetcore/migration/fx-to-core/includes/uses-systemweb-adapters.md b/aspnetcore/migration/fx-to-core/includes/uses-systemweb-adapters.md index e62d0884e33b..323fd406f026 100644 --- a/aspnetcore/migration/fx-to-core/includes/uses-systemweb-adapters.md +++ b/aspnetcore/migration/fx-to-core/includes/uses-systemweb-adapters.md @@ -1,2 +1,2 @@ > [!NOTE] -> This makes use of the [System.Web Adapters](~/aspnetcore/migration/fx-to-core/inc/systemweb-adapters.md) to simplify migration. +> This makes use of the [System.Web Adapters](~/migration/fx-to-core/inc/systemweb-adapters.md) to simplify migration. From 2866ad6dc62f78340b16ad1a2344976f58935ebf Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 30 Jun 2025 10:00:46 -0700 Subject: [PATCH 04/61] clarify decision tree for session --- .openpublishing.redirection.json | 15 +++++ .../migration/fx-to-core/areas/session.md | 62 ++++++++++--------- aspnetcore/migration/fx-to-core/inc/start.md | 2 +- 3 files changed, 48 insertions(+), 31 deletions(-) diff --git a/.openpublishing.redirection.json b/.openpublishing.redirection.json index 3c96ddcb15a4..4df5e1b2ae51 100644 --- a/.openpublishing.redirection.json +++ b/.openpublishing.redirection.json @@ -1065,6 +1065,21 @@ "redirect_url": "/aspnet/core/migration/fx-to-core/inc/wrapped", "redirect_document_id": false }, + { + "source_path": "aspnetcore/migration/fx-to-core/inc/remote-session.md", + "redirect_url": "/aspnet/core/migration/fx-to-core/areas/session#remote-app-session-state", + "redirect_document_id": false + }, + { + "source_path": "aspnetcore/migration/fx-to-core/inc/session.md", + "redirect_url": "/aspnet/core/migration/fx-to-core/areas/session", + "redirect_document_id": false + }, + { + "source_path": "aspnetcore/migration/fx-to-core/inc/wrapped.md", + "redirect_url": "/aspnet/core/migration/fx-to-core/areas/session#wrapped-aspnet-core-session-state", + "redirect_document_id": false + }, { "source_path": "aspnetcore/security/blazor/server-side.md", "redirect_url": "/aspnet/core/blazor/security/server/", diff --git a/aspnetcore/migration/fx-to-core/areas/session.md b/aspnetcore/migration/fx-to-core/areas/session.md index 021773f79e2c..20dea444f7e4 100644 --- a/aspnetcore/migration/fx-to-core/areas/session.md +++ b/aspnetcore/migration/fx-to-core/areas/session.md @@ -11,13 +11,27 @@ uid: migration/fx-to-core/areas/session # Migrate ASP.NET Framework Session to ASP.NET Core -For most applications, migrating to [ASP.NET Core session](~/fundamentals/app-state) provides the best performance and maintainability. However, larger applications may need an incremental approach using System.Web adapters. - -[!INCLUDE[](~/migration/fx-to-core/includes/uses-systemweb-adapters.md)] +For most applications, migrating to [ASP.NET Core session]((xref:fundamentals/app-state.md) provides the best performance and maintainability. However, larger applications may need an incremental approach using System.Web adapters. ## Choose your migration approach -There are a few options available for how to migrate session usage. As you decide which migration pattern to use, it helps to understand the differences between ASP.NET Framework and Core session designs: +You have three main options for migrating session state from ASP.NET Framework to ASP.NET Core. Your choice depends on your migration timeline, whether you need to run both applications simultaneously, and how much code you're willing to rewrite. + +### Quick decision guide + +**Answer these questions to choose your approach:** + +1. **Are you doing a complete rewrite or incremental migration?** + * Complete rewrite → [Built-in ASP.NET Core session](#built-in-aspnet-core-session-state) + * Incremental migration → Continue to question 2 + +2. **Do both your ASP.NET Framework and ASP.NET Core apps need to access the same session data?** + * Yes, shared session needed → [Remote app session](#remote-app-session-state) + * No, separate sessions are fine → [Wrapped ASP.NET Core session](#wrapped-aspnet-core-session-state) + +### Understanding the differences + +Before diving into implementation details, it's important to understand how ASP.NET Framework and ASP.NET Core handle session state differently: * **Object serialization** * ASP.NET Framework automatically serializes and deserializes objects (unless using in-memory storage) @@ -26,34 +40,18 @@ There are a few options available for how to migrate session usage. As you decid * ASP.NET Framework locks session usage within a session, handling subsequent requests serially * ASP.NET Core provides no session locking guarantees -The [System.Web adapters](~/migration/fx-to-core/inc/systemweb-adapters.md) bridge these differences through two key interfaces: +### Migration approaches comparison -* `Microsoft.AspNetCore.SystemWebAdapters.ISessionManager`: Accepts an and session metadata, returns an `ISessionState` object -* `Microsoft.AspNetCore.SystemWebAdapters.ISessionState`: Describes session object state and backs the type +| Approach | Code Changes | Performance | Session Sharing | When to Use | +|----------|-------------|-------------|-----------------|-------------| +| **[Built-in ASP.NET Core](#built-in-aspnet-core-session-state)** | High - Rewrite all session code | Best | None | Complete rewrites, performance-critical apps | +| **[Wrapped ASP.NET Core](#wrapped-aspnet-core-session-state)** | Low - Keep existing session patterns | Good | None | Incremental migrations, no shared state needed | +| **[Remote app](#remote-app-session-state)** | Low - Keep existing session patterns | Fair | Full | Running both apps simultaneously | -The main scenarios covered in this document are: +The [System.Web adapters](~/migration/fx-to-core/inc/systemweb-adapters.md) enable the "Wrapped" and "Remote app" approaches by bridging the differences between ASP.NET Framework and Core session implementations through two key interfaces: -| Implementation | Best for | Strongly typed | Locking | Session sharing | -|----------------|----------|----------------|---------|-----------------| -| [Built-in ASP.NET Core](#built-in-aspnet-core-session-state) | Complete rewrites with no legacy session compatibility needed | ⛔ | ⛔ | ⛔ | -| [Wrapped ASP.NET Core](#wrapped-aspnet-core-session-state) | Migrations where session doesn't need to be shared with the legacy app | ✔️ | ⛔ | ⛔ | -| [Remote app](#remote-app-session-state) | Incremental migrations requiring shared session state between apps | ✔️ | ✔️ | ✔️ | - -**Use built-in ASP.NET Core session** when: -* You're performing a complete rewrite and don't need System.Web compatibility -* You can rewrite all session-related code to use ASP.NET Core patterns -* You want the best performance and smallest footprint -* You don't need to maintain session data structure compatibility with legacy code - -**Use wrapped ASP.NET Core session** when: -* You're migrating components that don't need to share session data with the legacy application -* You want to leverage ASP.NET Core's native session infrastructure -* You're doing a more complete migration where both apps don't run simultaneously - -**Use remote app session** when: -* You need to share session state between your ASP.NET Framework and ASP.NET Core applications -* You're running both applications simultaneously during migration -* You require the same session locking behavior as ASP.NET Framework +* `Microsoft.AspNetCore.SystemWebAdapters.ISessionManager`: Accepts an and session metadata, returns an `ISessionState` object +* `Microsoft.AspNetCore.SystemWebAdapters.ISessionState`: Describes session object state and backs the type ## Built-in ASP.NET Core session state @@ -61,7 +59,7 @@ Choose this approach when you're performing a complete migration and can rewrite ASP.NET Core provides a lightweight, high-performance session state implementation that stores data as `byte[]` and requires explicit serialization. This approach offers the best performance but requires more code changes during migration. -For details on how to set this up and use it, see the [ASP.NET session documentation](~/fundamentals/app-state). +For details on how to set this up and use it, see the [ASP.NET session documentation]((xref:fundamentals/app-state.md). ### Pros and cons @@ -101,6 +99,8 @@ When migrating to built-in ASP.NET Core session: ## Wrapped ASP.NET Core session state +[!INCLUDE[](~/migration/fx-to-core/includes/uses-systemweb-adapters.md)] + Choose this approach when your migrated components don't need to share session data with your legacy application. The `Microsoft.Extensions.DependencyInjection.WrappedSessionExtensions.AddWrappedAspNetCoreSession` extension method adds a wraps ASP.NET Core session to work with the adapters. It uses the same backing store as while providing strongly-typed access. @@ -115,6 +115,8 @@ For more information, see the [wrapped session state sample app](https://github. ## Remote app session state +[!INCLUDE[](~/migration/fx-to-core/includes/uses-systemweb-adapters.md)] + Choose this approach when you need to share session state between your ASP.NET Framework and ASP.NET Core applications during incremental migration. Remote app session enables communication between applications to retrieve and set session state by exposing an endpoint on the ASP.NET Framework app. diff --git a/aspnetcore/migration/fx-to-core/inc/start.md b/aspnetcore/migration/fx-to-core/inc/start.md index 9e91f4ba7bab..f154173147d2 100644 --- a/aspnetcore/migration/fx-to-core/inc/start.md +++ b/aspnetcore/migration/fx-to-core/inc/start.md @@ -36,7 +36,7 @@ This step may require a number of projects to change depending on your solution ## Enable Session Support -Session is a commonly used feature of ASP.NET that shares the name with a feature in ASP.NET Core the APIs are much different. See the documentation on [session support](xref:migration/fx-to-core/inc/session). +Session is a commonly used feature of ASP.NET that shares the name with a feature in ASP.NET Core the APIs are much different. See the documentation on [session support](xref:migration/fx-to-core/fx-to-core/session). ## Enable shared authentication support From 13264b0681d67a36cb40f7ce8a65b08ba2768828 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 30 Jun 2025 10:08:32 -0700 Subject: [PATCH 05/61] clarify introduction --- .../migration/fx-to-core/areas/session.md | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/aspnetcore/migration/fx-to-core/areas/session.md b/aspnetcore/migration/fx-to-core/areas/session.md index 20dea444f7e4..1e9ce4ad94d0 100644 --- a/aspnetcore/migration/fx-to-core/areas/session.md +++ b/aspnetcore/migration/fx-to-core/areas/session.md @@ -11,7 +11,26 @@ uid: migration/fx-to-core/areas/session # Migrate ASP.NET Framework Session to ASP.NET Core -For most applications, migrating to [ASP.NET Core session]((xref:fundamentals/app-state.md) provides the best performance and maintainability. However, larger applications may need an incremental approach using System.Web adapters. +Session state is a critical component of many web applications, storing user-specific data across HTTP requests. When migrating from ASP.NET Framework to ASP.NET Core, session state presents unique challenges because the two frameworks handle sessions very differently. + +## Why session migration is complex + +ASP.NET Framework and ASP.NET Core have fundamentally different approaches to session management: + +* **ASP.NET Framework** provides automatic object serialization and built-in session locking +* **ASP.NET Core** requires manual serialization and offers no session locking guarantees + +These differences mean you can't simply move your session code from Framework to Core without changes. + +## Migration strategies overview + +You have three main approaches for handling session state during migration: + +1. **Complete rewrite** - Rewrite all session code to use ASP.NET Core's native session implementation +2. **Incremental with separate sessions** - Migrate components piece by piece, with each app maintaining its own session state +3. **Incremental with shared sessions** - Migrate components while sharing session data between Framework and Core applications + +For most applications, migrating to [ASP.NET Core session](xref:fundamentals/app-state) provides the best performance and maintainability. However, larger applications or those with complex session requirements may benefit from an incremental approach using [System.Web adapters](xref:migration/fx-to-core/inc/systemweb-adapters). ## Choose your migration approach From 59c8f3d474758f7193796cd9e6198e80798e358f Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 30 Jun 2025 10:10:24 -0700 Subject: [PATCH 06/61] fix cross reference --- aspnetcore/migration/fx-to-core/inc/start.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aspnetcore/migration/fx-to-core/inc/start.md b/aspnetcore/migration/fx-to-core/inc/start.md index f154173147d2..cf87a2b005ca 100644 --- a/aspnetcore/migration/fx-to-core/inc/start.md +++ b/aspnetcore/migration/fx-to-core/inc/start.md @@ -36,7 +36,7 @@ This step may require a number of projects to change depending on your solution ## Enable Session Support -Session is a commonly used feature of ASP.NET that shares the name with a feature in ASP.NET Core the APIs are much different. See the documentation on [session support](xref:migration/fx-to-core/fx-to-core/session). +Session is a commonly used feature of ASP.NET that shares the name with a feature in ASP.NET Core the APIs are much different. See the documentation on [session support](xref:migration/fx-to-core/areas/session). ## Enable shared authentication support From 9d55732eb085aee52f17dd4810c43bff63fee018 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 30 Jun 2025 10:21:39 -0700 Subject: [PATCH 07/61] add serialization details --- aspnetcore/migration/fx-to-core/areas/session.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/aspnetcore/migration/fx-to-core/areas/session.md b/aspnetcore/migration/fx-to-core/areas/session.md index 1e9ce4ad94d0..29d1adf6c692 100644 --- a/aspnetcore/migration/fx-to-core/areas/session.md +++ b/aspnetcore/migration/fx-to-core/areas/session.md @@ -30,7 +30,7 @@ You have three main approaches for handling session state during migration: 2. **Incremental with separate sessions** - Migrate components piece by piece, with each app maintaining its own session state 3. **Incremental with shared sessions** - Migrate components while sharing session data between Framework and Core applications -For most applications, migrating to [ASP.NET Core session](xref:fundamentals/app-state) provides the best performance and maintainability. However, larger applications or those with complex session requirements may benefit from an incremental approach using [System.Web adapters](xref:migration/fx-to-core/inc/systemweb-adapters). +For most applications, migrating to [ASP.NET Core session](xref:fundamentals/app-state) provides the best performance and maintainability. However, larger applications or those with complex session requirements may benefit from an incremental approach using [System.Web adapters](~/migration/fx-to-core/inc/systemweb-adapters.md). ## Choose your migration approach @@ -148,11 +148,13 @@ Complete the [remote app setup](xref:migration/fx-to-core/inc/remote-app-setup) The object requires serialization for remote app session state. -**For HttpSessionState serialization**, implement `Microsoft.AspNetCore.SystemWebAdapters.SessionState.Serialization.ISessionSerializer`. A default binary writer implementation is provided: +In order to serialize session state, a serializer for the state object must be registered: :::code language="csharp" source="~/migration/fx-to-core/inc/samples/remote-session/Program.cs" id="snippet_Serialization" ::: -**For strongly-typed session access**, configure JSON serialization. Register each session key to a known type using `JsonSessionSerializerOptions`: +In ASP.NET Core, was used to automatically serialize session value contents. In order to serialize these with for use with the System.Web adapters, the serialization must be explicitly configured using `ISessionKeySerializer` implementations. + +Out of the box, there is a simple JSON serializer that allows each session key to be registered to a known type using `JsonSessionSerializerOptions`: * `RegisterKey(string)` - Registers a session key to a known type. This registration is required for correct serialization/deserialization. Missing registrations cause errors and prevent session access. From 85abddabfad5e4ed6fdc5ed6a50c51ac82ee4bc5 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 30 Jun 2025 10:34:59 -0700 Subject: [PATCH 08/61] move samples --- aspnetcore/migration/fx-to-core/areas/session.md | 16 ++++++++-------- .../session/samples/remote}/Global.asax.cs | 0 .../session/samples/remote}/Program.cs | 0 .../session/samples/remote}/SomeController.cs | 0 .../session/samples/serialization}/Program.cs | 0 .../session}/samples/wrapped/Program.cs | 0 6 files changed, 8 insertions(+), 8 deletions(-) rename aspnetcore/migration/fx-to-core/{inc/samples/remote-session => areas/session/samples/remote}/Global.asax.cs (100%) rename aspnetcore/migration/fx-to-core/{inc/samples/remote-session => areas/session/samples/remote}/Program.cs (100%) rename aspnetcore/migration/fx-to-core/{inc/samples/remote-session => areas/session/samples/remote}/SomeController.cs (100%) rename aspnetcore/migration/fx-to-core/{inc/samples/session => areas/session/samples/serialization}/Program.cs (100%) rename aspnetcore/migration/fx-to-core/{inc => areas/session}/samples/wrapped/Program.cs (100%) diff --git a/aspnetcore/migration/fx-to-core/areas/session.md b/aspnetcore/migration/fx-to-core/areas/session.md index 29d1adf6c692..324a16db9e44 100644 --- a/aspnetcore/migration/fx-to-core/areas/session.md +++ b/aspnetcore/migration/fx-to-core/areas/session.md @@ -30,7 +30,7 @@ You have three main approaches for handling session state during migration: 2. **Incremental with separate sessions** - Migrate components piece by piece, with each app maintaining its own session state 3. **Incremental with shared sessions** - Migrate components while sharing session data between Framework and Core applications -For most applications, migrating to [ASP.NET Core session](xref:fundamentals/app-state) provides the best performance and maintainability. However, larger applications or those with complex session requirements may benefit from an incremental approach using [System.Web adapters](~/migration/fx-to-core/inc/systemweb-adapters.md). +For most applications, migrating to [ASP.NET Core session](xref:fundamentals/app-state) provides the best performance and maintainability. However, larger applications or those with complex session requirements may benefit from an incremental approach using the System.Web adapters. ## Choose your migration approach @@ -126,7 +126,7 @@ The `Microsoft.Extensions.DependencyInjection.WrappedSessionExtensions.AddWrappe **Configuration for ASP.NET Core:** -:::code language="csharp" source="~/migration/fx-to-core/inc/samples/wrapped/Program.cs" id="snippet_WrapAspNetCoreSession" ::: +:::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/wrapped/Program.cs" id="snippet_WrapAspNetCoreSession" ::: Your Framework application requires no changes. @@ -150,7 +150,7 @@ The object requires serializatio In order to serialize session state, a serializer for the state object must be registered: -:::code language="csharp" source="~/migration/fx-to-core/inc/samples/remote-session/Program.cs" id="snippet_Serialization" ::: +:::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/remote/Program.cs" id="snippet_Serialization" ::: In ASP.NET Core, was used to automatically serialize session value contents. In order to serialize these with for use with the System.Web adapters, the serialization must be explicitly configured using `ISessionKeySerializer` implementations. @@ -158,7 +158,7 @@ Out of the box, there is a simple JSON serializer that allows each session key t * `RegisterKey(string)` - Registers a session key to a known type. This registration is required for correct serialization/deserialization. Missing registrations cause errors and prevent session access. -:::code language="csharp" source="~/migration/fx-to-core/inc/samples/session/Program.cs" id="snippet_Serialization" ::: +:::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/remote/Program.cs" id="snippet_Serialization" ::: ### Application configuration @@ -166,23 +166,23 @@ Out of the box, there is a simple JSON serializer that allows each session key t Call `AddRemoteAppSession` and `AddJsonSessionSerializer` to register known session item types: -:::code language="csharp" source="~/migration/fx-to-core/inc/samples/remote-session/Program.cs" id="snippet_Configuration" ::: +:::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/remote/Program.cs" id="snippet_Configuration" ::: Session support requires explicit activation. Configure it per-route using ASP.NET Core metadata. #### Option 1: Annotate controllers -:::code language="csharp" source="~/migration/fx-to-core/inc/samples/remote-session/SomeController.cs" id="snippet_Controller" ::: +:::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/remote/SomeController.cs" id="snippet_Controller" ::: #### Option 2: Enable globally for all endpoints -:::code language="csharp" source="~/migration/fx-to-core/inc/samples/remote-session/Program.cs" id="snippet_RequireSystemWebAdapterSession" ::: +:::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/remote/Program.cs" id="snippet_RequireSystemWebAdapterSession" ::: **ASP.NET Framework configuration:** Add this change to `Global.asax.cs`: -:::code language="csharp" source="~/migration/fx-to-core/inc/samples/remote-session/Global.asax.cs"::: +:::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/remote/Global.asax.cs"::: ### Communication protocol diff --git a/aspnetcore/migration/fx-to-core/inc/samples/remote-session/Global.asax.cs b/aspnetcore/migration/fx-to-core/areas/session/samples/remote/Global.asax.cs similarity index 100% rename from aspnetcore/migration/fx-to-core/inc/samples/remote-session/Global.asax.cs rename to aspnetcore/migration/fx-to-core/areas/session/samples/remote/Global.asax.cs diff --git a/aspnetcore/migration/fx-to-core/inc/samples/remote-session/Program.cs b/aspnetcore/migration/fx-to-core/areas/session/samples/remote/Program.cs similarity index 100% rename from aspnetcore/migration/fx-to-core/inc/samples/remote-session/Program.cs rename to aspnetcore/migration/fx-to-core/areas/session/samples/remote/Program.cs diff --git a/aspnetcore/migration/fx-to-core/inc/samples/remote-session/SomeController.cs b/aspnetcore/migration/fx-to-core/areas/session/samples/remote/SomeController.cs similarity index 100% rename from aspnetcore/migration/fx-to-core/inc/samples/remote-session/SomeController.cs rename to aspnetcore/migration/fx-to-core/areas/session/samples/remote/SomeController.cs diff --git a/aspnetcore/migration/fx-to-core/inc/samples/session/Program.cs b/aspnetcore/migration/fx-to-core/areas/session/samples/serialization/Program.cs similarity index 100% rename from aspnetcore/migration/fx-to-core/inc/samples/session/Program.cs rename to aspnetcore/migration/fx-to-core/areas/session/samples/serialization/Program.cs diff --git a/aspnetcore/migration/fx-to-core/inc/samples/wrapped/Program.cs b/aspnetcore/migration/fx-to-core/areas/session/samples/wrapped/Program.cs similarity index 100% rename from aspnetcore/migration/fx-to-core/inc/samples/wrapped/Program.cs rename to aspnetcore/migration/fx-to-core/areas/session/samples/wrapped/Program.cs From 78e5524184b68a649d9da1fca7fbafeca8bd31c0 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 30 Jun 2025 10:38:52 -0700 Subject: [PATCH 09/61] move session images --- aspnetcore/migration/fx-to-core/areas/session.md | 4 ++-- .../session/_static}/readonly_session.png | Bin .../session/_static}/writesession.png | Bin 3 files changed, 2 insertions(+), 2 deletions(-) rename aspnetcore/migration/fx-to-core/{inc/overview/static => areas/session/_static}/readonly_session.png (100%) rename aspnetcore/migration/fx-to-core/{inc/overview/static => areas/session/_static}/writesession.png (100%) diff --git a/aspnetcore/migration/fx-to-core/areas/session.md b/aspnetcore/migration/fx-to-core/areas/session.md index 324a16db9e44..770efcfb600e 100644 --- a/aspnetcore/migration/fx-to-core/areas/session.md +++ b/aspnetcore/migration/fx-to-core/areas/session.md @@ -190,7 +190,7 @@ Add this change to `Global.asax.cs`: Readonly sessions retrieve session state without locking. The process uses a single `GET` request that returns session state and closes immediately. -![Readonly session will retrieve the session state from the framework app](~/migration/fx-to-core/inc/overview/static/readonly_session.png) +![Readonly session will retrieve the session state from the framework app](~/migration/fx-to-core/areas/session/_static/readonly_session.png) #### Writeable sessions @@ -201,4 +201,4 @@ Writeable sessions require additional steps: * Use an additional `PUT` request to update state * Close the initial request only after updating is complete -![Writeable session state protocol starts with the same as the readonly](~/migration/fx-to-core/inc/overview/static/writesession.png) +![Writeable session state protocol starts with the same as the readonly](~/migration/fx-to-core/areas/session/_static/writesession.png) diff --git a/aspnetcore/migration/fx-to-core/inc/overview/static/readonly_session.png b/aspnetcore/migration/fx-to-core/areas/session/_static/readonly_session.png similarity index 100% rename from aspnetcore/migration/fx-to-core/inc/overview/static/readonly_session.png rename to aspnetcore/migration/fx-to-core/areas/session/_static/readonly_session.png diff --git a/aspnetcore/migration/fx-to-core/inc/overview/static/writesession.png b/aspnetcore/migration/fx-to-core/areas/session/_static/writesession.png similarity index 100% rename from aspnetcore/migration/fx-to-core/inc/overview/static/writesession.png rename to aspnetcore/migration/fx-to-core/areas/session/_static/writesession.png From ef2f0e3b6b5d0915e8ed1495a2c6720dfa5a4fe9 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 30 Jun 2025 10:44:54 -0700 Subject: [PATCH 10/61] fix cross reference --- aspnetcore/migration/fx-to-core/areas/session.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aspnetcore/migration/fx-to-core/areas/session.md b/aspnetcore/migration/fx-to-core/areas/session.md index 770efcfb600e..2cda6057e4e6 100644 --- a/aspnetcore/migration/fx-to-core/areas/session.md +++ b/aspnetcore/migration/fx-to-core/areas/session.md @@ -152,7 +152,7 @@ In order to serialize session state, a serializer for the state object must be r :::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/remote/Program.cs" id="snippet_Serialization" ::: -In ASP.NET Core, was used to automatically serialize session value contents. In order to serialize these with for use with the System.Web adapters, the serialization must be explicitly configured using `ISessionKeySerializer` implementations. +In ASP.NET Core, was used to automatically serialize session value contents. In order to serialize these with for use with the System.Web adapters, the serialization must be explicitly configured using `ISessionKeySerializer` implementations. Out of the box, there is a simple JSON serializer that allows each session key to be registered to a known type using `JsonSessionSerializerOptions`: From 0b14eab6be513c5078b4dd1957789492b0fd3f5a Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 30 Jun 2025 10:58:19 -0700 Subject: [PATCH 11/61] clean up remote-app setup --- .../migration/fx-to-core/areas/session.md | 2 +- .../fx-to-core/inc/remote-app-setup.md | 58 ++++++++++++++----- 2 files changed, 44 insertions(+), 16 deletions(-) diff --git a/aspnetcore/migration/fx-to-core/areas/session.md b/aspnetcore/migration/fx-to-core/areas/session.md index 2cda6057e4e6..7d3ae756d477 100644 --- a/aspnetcore/migration/fx-to-core/areas/session.md +++ b/aspnetcore/migration/fx-to-core/areas/session.md @@ -152,7 +152,7 @@ In order to serialize session state, a serializer for the state object must be r :::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/remote/Program.cs" id="snippet_Serialization" ::: -In ASP.NET Core, was used to automatically serialize session value contents. In order to serialize these with for use with the System.Web adapters, the serialization must be explicitly configured using `ISessionKeySerializer` implementations. +In ASP.NET Core, [BinaryFormatter](/dotnet/api/system.runtime.serializer.formatters.binary.binaryFormatter) was used to automatically serialize session value contents. In order to serialize these with for use with the System.Web adapters, the serialization must be explicitly configured using `ISessionKeySerializer` implementations. Out of the box, there is a simple JSON serializer that allows each session key to be registered to a known type using `JsonSessionSerializerOptions`: diff --git a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md index 32c39a10a2d1..0c24e929e1be 100644 --- a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md +++ b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md @@ -19,19 +19,50 @@ Specifically, this capability is used, currently, for [remote app authentication To enable the ASP.NET Core app to communicate with the ASP.NET app, it's necessary to make a couple small changes to each app. +You need to configure two configuration values in both applications: + +* `RemoteAppApiKey`: A key (required to be parseable as a [GUID](/dotnet/api/system.guid)) that is shared between the two applications. This should be a GUID value like `12345678-1234-1234-1234-123456789012`. +* `RemoteAppUri`: The URI of the remote ASP.NET Framework application (only required in the ASP.NET Core application configuration). This should be the full URL where the ASP.NET Framework app is hosted, such as `https://localhost:44300` or `https://myapp.example.com`. + +For ASP.NET Framework applications, add these values to your `web.config` in the `` section: + +```xml + + + +``` + +For ASP.NET Core applications, add these values to your `appsettings.json`: + +```json +{ + "RemoteAppApiKey": "...", + "RemoteAppUri": "https://localhost:44300" +} +``` + +For ASP.NET Framework applications, it is recommended to use to allow injecting values into the application without touching the `web.config`. + ### ASP.NET app configuration To set up the ASP.NET app to be able to receive requests from the ASP.NET Core app: + 1. Install the NuGet package [`Microsoft.AspNetCore.SystemWebAdapters.FrameworkServices`](https://www.nuget.org/packages/Microsoft.AspNetCore.SystemWebAdapters) -2. Call the `AddRemoteAppServer` extension method on the `ISystemWebAdapterBuilder`: + +2. Add the configuration code to the `Application_Start` method in your `Global.asax.cs` file: ```CSharp -SystemWebAdapterConfiguration.AddSystemWebAdapters(this) - .AddRemoteAppServer(options => - { - // ApiKey is a string representing a GUID - options.ApiKey = ConfigurationManager.AppSettings["RemoteAppApiKey"]; - }); +protected void Application_Start() +{ + SystemWebAdapterConfiguration.AddSystemWebAdapters(this) + .AddRemoteAppServer(options => + { + // ApiKey is a string representing a GUID + options.ApiKey = ConfigurationManager.AppSettings["RemoteAppApiKey"]; + }); + + // ...existing code... +} ``` In the options configuration method passed to the `AddRemoteAppServer` call, an API key must be specified. The API key is: @@ -40,7 +71,7 @@ In the options configuration method passed to the `AddRemoteAppServer` call, an * The same API key provided to the ASP.NET Core app when it is configured. * A string and must be parsable as a [GUID](/dotnet/api/system.guid). Hyphens in the key are optional. -3. **Optional :** Add the `SystemWebAdapterModule` module to the `web.config` if it wasn't already added by NuGet. The `SystemWebAdapterModule` module is not added automatically when using SDK style projects for ASP.NET Core. +1. Add the `SystemWebAdapterModule` module to the `web.config` if it wasn't already added by NuGet. This module configuration is required for IIS hosting scenarios. The `SystemWebAdapterModule` module is not added automatically when using SDK style projects for ASP.NET Core. ```diff @@ -53,22 +84,19 @@ In the options configuration method passed to the `AddRemoteAppServer` call, an ### ASP.NET Core app -To set up the ASP.NET Core app to be able to send requests to the ASP.NET app, you need to make a similar change, calling `AddRemoteApp` after registering System.Web adapter services with `AddSystemWebAdapters`. +To set up the ASP.NET Core app to be able to send requests to the ASP.NET app, configure the remote app client by calling `AddRemoteAppClient` after registering System.Web adapter services with `AddSystemWebAdapters`. + +Add this configuration to your `Program.cs` file: ```CSharp builder.Services.AddSystemWebAdapters() .AddRemoteAppClient(options => { - options.RemoteAppUrl = new(builder.Configuration["ReverseProxy:Clusters:fallbackCluster:Destinations:fallbackApp:Address"]); + options.RemoteAppUrl = new(builder.Configuration["RemoteAppUri"]); options.ApiKey = builder.Configuration["RemoteAppApiKey"]; }); ``` -In the preceding code: - -* The `AddRemoteApp` call is used to configure the remote app's URL and the shared secret API key. -* The `RemoteAppUrl` property specifies the URL of the ASP.NET Framework app that the ASP.NET Core app communicates with. In this example, the URL is read from an existing configuration setting used by the YARP proxy that proxies requests to the ASP.NET Framework app as part of the incremental migration's *strangler fig pattern*. - With both the ASP.NET and ASP.NET Core app updated, extension methods can now be used to set up [remote app authentication](xref:migration/fx-to-core/inc/remote-authentication) or [remote session](xref:migration/fx-to-core/areas/session#remote-app-session-state), as needed. ## Securing the remote app connection From 2deb4b11b93bec08855860ee4794be4e8130ba5d Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 30 Jun 2025 11:07:14 -0700 Subject: [PATCH 12/61] some links --- aspnetcore/migration/fx-to-core/areas/session.md | 6 +++--- aspnetcore/migration/fx-to-core/inc/remote-app-setup.md | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/aspnetcore/migration/fx-to-core/areas/session.md b/aspnetcore/migration/fx-to-core/areas/session.md index 7d3ae756d477..7e5be10c36bb 100644 --- a/aspnetcore/migration/fx-to-core/areas/session.md +++ b/aspnetcore/migration/fx-to-core/areas/session.md @@ -1,6 +1,6 @@ --- -title: ASP.NET to ASP.NET Core incremental session state migration -description: ASP.NET to ASP.NET Core incremental session state migration +title: ASP.NET to ASP.NET Core session state migration +description: ASP.NET to ASP.NET Core session state migration author: rick-anderson ms.author: riande monikerRange: '>= aspnetcore-6.0' @@ -152,7 +152,7 @@ In order to serialize session state, a serializer for the state object must be r :::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/remote/Program.cs" id="snippet_Serialization" ::: -In ASP.NET Core, [BinaryFormatter](/dotnet/api/system.runtime.serializer.formatters.binary.binaryFormatter) was used to automatically serialize session value contents. In order to serialize these with for use with the System.Web adapters, the serialization must be explicitly configured using `ISessionKeySerializer` implementations. +In ASP.NET Core, [BinaryFormatter](dotnet/api/system.runtime.serialization.formatters.binary.binaryformatter) was used to automatically serialize session value contents. In order to serialize these with for use with the System.Web adapters, the serialization must be explicitly configured using `ISessionKeySerializer` implementations. Out of the box, there is a simple JSON serializer that allows each session key to be registered to a known type using `JsonSessionSerializerOptions`: diff --git a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md index 0c24e929e1be..453df0ed77e3 100644 --- a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md +++ b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md @@ -41,7 +41,7 @@ For ASP.NET Core applications, add these values to your `appsettings.json`: } ``` -For ASP.NET Framework applications, it is recommended to use to allow injecting values into the application without touching the `web.config`. +For ASP.NET Framework applications, it is recommended to use [Configuration Builders](/aspnet/config-builder) to allow injecting values into the application without touching the `web.config`. ### ASP.NET app configuration From d4e6443ecf4e5c792e6ea3720bce671a07906f50 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 30 Jun 2025 11:34:20 -0700 Subject: [PATCH 13/61] rework authentication --- .../fx-to-core/areas/authentication.md | 383 ++++++++++++++++++ .../authentication/samples}/AspNetApp.cs | 0 .../authentication/samples}/AspNetCore.cs | 0 .../fx-to-core/inc/remote-authentication.md | 86 ---- 4 files changed, 383 insertions(+), 86 deletions(-) create mode 100644 aspnetcore/migration/fx-to-core/areas/authentication.md rename aspnetcore/migration/fx-to-core/{inc/samples/remote-authentication => areas/authentication/samples}/AspNetApp.cs (100%) rename aspnetcore/migration/fx-to-core/{inc/samples/remote-authentication => areas/authentication/samples}/AspNetCore.cs (100%) delete mode 100644 aspnetcore/migration/fx-to-core/inc/remote-authentication.md diff --git a/aspnetcore/migration/fx-to-core/areas/authentication.md b/aspnetcore/migration/fx-to-core/areas/authentication.md new file mode 100644 index 000000000000..3dd2d0dc8a13 --- /dev/null +++ b/aspnetcore/migration/fx-to-core/areas/authentication.md @@ -0,0 +1,383 @@ +--- +title: ASP.NET Framework to Core Authentication Migration +description: ASP.NET Framework to Core Authentication Migration +author: rick-anderson +ms.author: riande +monikerRange: '>= aspnetcore-6.0' +ms.date: 11/9/2022 +ms.topic: article +uid: migration/fx-to-core/areas/authentication +--- + +# Migrate ASP.NET Framework Authentication to ASP.NET Core + +Authentication is a critical component of web applications, handling user identity verification across HTTP requests. When migrating from ASP.NET Framework to ASP.NET Core, authentication presents unique challenges because the two frameworks handle authentication very differently. + +For general information about authentication in ASP.NET Core, see . For information about authorization, see . + +## Why authentication migration is complex + +ASP.NET Framework and ASP.NET Core have fundamentally different approaches to authentication: + +* **ASP.NET Framework** provides built-in authentication modules with automatic configuration and tight integration with System.Web +* **ASP.NET Core** uses a middleware-based approach with explicit configuration and dependency injection + +These differences mean you can't simply move your authentication code from Framework to Core without changes. + +## Authentication types and migration challenges + +Different authentication types present varying levels of migration complexity: + +### Cookie-based authentication + +* **ASP.NET Framework**: Uses `Microsoft.Owin` cookie authentication middleware +* **ASP.NET Core**: Uses `CookieAuthentication` middleware with different configuration +* **Migration challenge**: Cookie format, encryption keys, and configuration differences + +### JWT Bearer tokens + +* **ASP.NET Framework**: Often handled through custom modules or OWIN middleware +* **ASP.NET Core**: Native support through `Microsoft.AspNetCore.Authentication.JwtBearer` +* **Migration challenge**: Token validation parameter differences and middleware registration + +### Windows authentication + +* **ASP.NET Framework**: Built-in IIS integration +* **ASP.NET Core**: Requires explicit configuration and may need hosting model changes +* **Migration challenge**: Server configuration and authentication flow differences + +### Forms authentication + +* **ASP.NET Framework**: Built-in `System.Web.Security.FormsAuthentication` +* **ASP.NET Core**: No direct equivalent, requires migration to cookie authentication +* **Migration challenge**: Complete authentication system rewrite needed + +### Custom authentication + +* **ASP.NET Framework**: Custom modules implementing `IHttpModule` +* **ASP.NET Core**: Custom middleware or authentication handlers +* **Migration challenge**: Complete architecture change from modules to middleware + +## Migration strategies overview + +You have three main approaches for handling authentication during migration: + +1. **Complete rewrite** - Rewrite all authentication code to use ASP.NET Core's native authentication +2. **Remote authentication** - Use System.Web adapters to delegate authentication to the ASP.NET Framework app +3. **Shared cookie authentication** - Share authentication cookies between Framework and Core applications (for OWIN-based scenarios) + +For most applications, migrating to native ASP.NET Core authentication provides the best performance and maintainability. However, larger applications or those with complex authentication requirements may benefit from an incremental approach using the System.Web adapters. + +## Choose your migration approach + +You have three main options for migrating authentication from ASP.NET Framework to ASP.NET Core. Your choice depends on your authentication type, migration timeline, whether you need to run both applications simultaneously, and how much code you're willing to rewrite. + +### Quick decision guide + +**Answer these questions to choose your approach:** + +1. **Are you doing a complete rewrite or incremental migration?** + * Complete rewrite → [Complete rewrite to ASP.NET Core authentication](#complete-rewrite-to-aspnet-core-authentication) + * Incremental migration → Continue to question 2 + +2. **What type of authentication does your ASP.NET Framework app use?** + * OWIN cookie authentication → Continue to question 3 + * Forms authentication, JWT Bearer tokens, Windows auth, or Custom authentication → [Remote authentication](#remote-authentication) + +3. **Do both your ASP.NET Framework and ASP.NET Core apps need to access the same authentication state?** + * Yes, shared authentication needed → Continue to question 4 + * No, separate authentication is fine → [Complete rewrite to ASP.NET Core authentication](#complete-rewrite-to-aspnet-core-authentication) + +4. **Can you configure matching data protection settings between both apps?** + * Yes → [Shared cookie authentication](#shared-cookie-authentication) (see Alternatives section, best performance) + * No or unsure → [Remote authentication](#remote-authentication) + +### Migration approaches comparison + +| Approach | Code Changes | Performance | Auth Sharing | When to Use | +|----------|-------------|-------------|--------------|-------------| +| **[Complete rewrite](#complete-rewrite-to-aspnet-core-authentication)** | High - Rewrite all auth code | Best | None | Complete rewrites, performance-critical apps, non-OWIN auth | +| **[Remote authentication](#remote-authentication)** | Low - Keep existing patterns | Fair | Full | Incremental migrations, complex auth, Windows auth | +| **[Shared cookies](#shared-cookie-authentication)** | Medium - Update configuration | Good | Full | OWIN cookie auth, performance-critical shared auth (see Alternatives) | + +## Complete rewrite to ASP.NET Core authentication + +Choose this approach when you're performing a complete migration, have non-OWIN authentication, or want the best performance and maintainability. + +ASP.NET Core provides comprehensive authentication support with high performance and extensive customization options. This approach requires rewriting authentication code but offers the most benefits in the long term. + +### Complete rewrite pros and cons + +| Pros | Cons | +|------|------| +| Best performance and security | Requires rewriting all authentication code | +| Native ASP.NET Core implementation | No automatic migration path | +| Full control over authentication flow | Learning curve for new authentication patterns | +| No additional dependencies | Breaking change from Framework patterns | +| Access to latest ASP.NET Core auth features | Potential downtime during migration | + +### Migration considerations + +When migrating to native ASP.NET Core authentication: + +**Choose based on your Framework authentication type:** +* **Forms authentication** → Migrate to [Cookie authentication](xref:security/authentication/cookie) +* **JWT Bearer tokens** → Migrate to [JWT Bearer authentication](xref:security/authentication/configure-jwt-bearer-authentication) +* **Windows authentication** → Use [Windows authentication](xref:security/authentication/windowsauth) +* **OWIN OAuth providers** → Use corresponding ASP.NET Core OAuth providers +* **Custom authentication** → Implement [custom authentication handlers](xref:security/authentication/index#authentication-handler) + +**Code changes required:** +* Replace `HttpContext.User` access patterns (mostly compatible) +* Update authentication middleware registration in `Program.cs` +* Migrate custom authentication logic to ASP.NET Core patterns +* Update authorization attributes and policies + +**When to choose this approach:** +* You can afford to rewrite authentication-related code +* Performance is a top priority +* You're not sharing authentication state with legacy applications +* You want to eliminate System.Web dependencies completely +* Your Framework app uses Forms authentication, custom modules, or JWT tokens + +## Remote authentication + +[!INCLUDE[](~/migration/fx-to-core/includes/uses-systemweb-adapters.md)] + +Choose this approach when you need to share authentication between your ASP.NET Framework and ASP.NET Core applications during incremental migration, or when you have complex authentication that's difficult to migrate. + +The System.Web adapters' remote authentication feature allows an ASP.NET Core app to determine a user's identity by deferring to an ASP.NET app. This enables gradual migration while maintaining a single authentication system. + +### How remote authentication works + +1. When requests are processed by the ASP.NET Core app, if remote app authentication is the default scheme or specified by the request's endpoint, the `RemoteAuthenticationAuthHandler` will attempt to authenticate the user. +2. The handler makes an HTTP request to the ASP.NET app's authenticate endpoint, forwarding configured headers from the current request (by default, `Authorization` and `Cookie` headers). +3. The ASP.NET app processes the authentication and returns either a serialized `ClaimsPrincipal` or an HTTP status code indicating failure. +4. The ASP.NET Core app uses the result to establish the user's identity or handle authentication challenges. + +### Remote authentication pros and cons + +| Pros | Cons | +|------|------| +| Minimal code changes required | Additional HTTP request overhead | +| Works with any Framework auth type | Network dependency between apps | +| Gradual migration capability | More complex debugging | +| Preserves existing auth logic | Requires both apps to be running | +| Handles complex auth scenarios | Limited Windows auth support | + +### When to choose remote authentication + +**Choose Remote Authentication when:** +* Your ASP.NET app doesn't use `Microsoft.Owin` cookie authentication +* You want a flexible solution that works with various authentication mechanisms +* You need to gradually migrate authentication logic to ASP.NET Core +* You have complex custom authentication that's difficult to rewrite +* You're doing an incremental migration and need shared authentication state + +### Remote authentication configuration + +There are just a few small code changes needed to enable remote authentication in a solution that's already set up according to the [Getting Started](xref:migration/fx-to-core/inc/overview). + +First, follow the [remote app setup](xref:migration/fx-to-core/inc/remote-app-setup) instructions to connect the ASP.NET Core and ASP.NET apps. Then, there are just a couple extra extension methods to call to enable remote app authentication. + +#### ASP.NET app configuration + +The ASP.NET app needs to be configured to add the authentication endpoint. Adding the authentication endpoint is done by calling the `AddAuthenticationServer` extension method to set up the HTTP module that watches for requests to the authentication endpoint. Note that remote authentication scenarios typically want to add proxy support as well, so that any authentication related redirects correctly route to the ASP.NET Core app rather than the ASP.NET one. + +:::code language="csharp" source="~/migration/fx-to-core/areas/authentication/samples/AspNetApp.cs" id="snippet_SystemWebAdapterConfiguration" ::: + +#### ASP.NET Core app configuration + +Next, the ASP.NET Core app needs to be configured to enable the authentication handler that will authenticate users by making an HTTP request to the ASP.NET app. Again, this is done by calling `AddAuthenticationClient` when registering System.Web adapters services: + +:::code language="csharp" source="~/migration/fx-to-core/areas/authentication/samples/AspNetCore.cs" id="snippet_AddSystemWebAdapters" highlight="8" ::: + +The boolean that is passed to the `AddAuthenticationClient` call specifies whether remote app authentication should be the default authentication scheme. Passing `true` will cause the user to be authenticated via remote app authentication for all requests, whereas passing `false` means that the user will only be authenticated with remote app authentication if the remote app scheme is specifically requested (with `[Authorize(AuthenticationSchemes = RemoteAppAuthenticationDefaults.AuthenticationScheme)]` on a controller or action method, for example). Passing false for this parameter has the advantage of only making HTTP requests to the original ASP.NET app for authentication for endpoints that require remote app authentication but has the disadvantage of requiring annotating all such endpoints to indicate that they will use remote app auth. + +#### Using Remote Authentication with Specific Endpoints + +When you set the default scheme to `false`, you can specify remote authentication for specific controllers or actions: + +```csharp +[Authorize(AuthenticationSchemes = RemoteAppAuthenticationDefaults.AuthenticationScheme)] +public class SecureController : Controller +{ + // This controller uses remote authentication + public IActionResult Index() + { + return View(); + } +} + +// Or on specific actions +public class HomeController : Controller +{ + [Authorize(AuthenticationSchemes = RemoteAppAuthenticationDefaults.AuthenticationScheme)] + public IActionResult SecureAction() + { + return View(); + } +} +``` + +#### Advanced Configuration Options + +In addition to the require boolean, an optional callback may be passed to `AddAuthenticationClient` to modify some other aspects of the remote authentication process's behavior: + +* `RequestHeadersToForward`: This property contains headers that should be forwarded from a request when calling the authenticate API. By default, the only headers forwarded are `Authorization` and `Cookie`. Additional headers can be forwarded by adding them to this list. Alternatively, if the list is cleared (so that no headers are specified), then all headers will be forwarded. that no headers are specified), then all headers will be forwarded. +* `ResponseHeadersToForward`: This property lists response headers that should be propagated back from the authenticate request to the original call that prompted authentication in scenarios where identity is challenged. By default, this includes `Location`, `Set-Cookie`, and `WWW-Authenticate` headers. +* `AuthenticationEndpointPath`: The endpoint on the ASP.NET app where authenticate requests should be made. This defaults to `/systemweb-adapters/authenticate` and must match the endpoint specified in the ASP.NET authentication endpoint configuration. + +Here's an example of configuring these options: + +```csharp +builder.Services.AddSystemWebAdapters() + .AddRemoteAppClient(options => + { + options.RemoteAppUrl = new Uri(builder.Configuration + ["ReverseProxy:Clusters:fallbackCluster:Destinations:fallbackApp:Address"]); + options.ApiKey = builder.Configuration["RemoteAppApiKey"]; + }) + .AddAuthenticationClient(false, options => + { + // Forward additional headers for authentication + options.RequestHeadersToForward.Add("X-Custom-Auth-Header"); + + // Forward additional response headers + options.ResponseHeadersToForward.Add("X-Custom-Response-Header"); + + // Use a custom authentication endpoint path + options.AuthenticationEndpointPath = "/custom-auth-endpoint"; + }); +``` + +#### Implementing Custom Authentication Result Processors + +You can implement custom processors to modify authentication results before they are used: + +```csharp +public class CustomAuthResultProcessor : IRemoteAuthenticationResultProcessor +{ + public Task ProcessAsync(RemoteAuthenticationResult result, HttpContext context) + { + // Custom logic to process authentication results + if (result.Headers.ContainsKey("Location")) + { + // Modify redirect URLs or other logic + } + + return Task.CompletedTask; + } +} + +// Register the custom processor +builder.Services.AddScoped(); +``` + +Finally, if the ASP.NET Core app didn't previously include authentication middleware, that will need to be enabled (after routing middleware, but before authorization middleware). For more information about middleware ordering, see : + +:::code language="csharp" source="~/migration/fx-to-core/areas/authentication/samples/AspNetCore.cs" id="snippet_UseAuthentication" ::: + +#### Security Considerations + +When implementing remote authentication, consider the following security aspects: + +* **API Key Security**: The API key used for communication between the ASP.NET Core and ASP.NET apps should be stored securely using [configuration providers](xref:fundamentals/configuration/index) and not hardcoded. +* **Network Security**: Communication between the apps should occur over secure channels (HTTPS) in production environments. +* **Header Forwarding**: Be cautious about which headers you forward to avoid exposing sensitive information. Only forward headers that are necessary for authentication. +* **Endpoint Protection**: The authentication endpoint on the ASP.NET app should only be accessible to the ASP.NET Core app, not external clients. + +#### Troubleshooting + +Common issues when configuring remote authentication: + +* **Authentication failures**: Verify that the API keys match between both applications and that the authentication endpoint path is correctly configured. +* **Redirect loops**: Ensure that the `RedirectUrlProcessor` is properly configured to redirect to the ASP.NET Core app rather than the ASP.NET app. +* **Missing claims**: Verify that the ASP.NET app is properly serializing the `ClaimsPrincipal` and that all required claims are included. + +#### Design + +1. When requests are processed by the ASP.NET Core app, if remote app authentication is the default scheme or specified by the request's endpoint, the `RemoteAuthenticationAuthHandler` will attempt to authenticate the user. + 1. The handler will make an HTTP request to the ASP.NET app's authenticate endpoint. It will copy configured headers from the current request onto this new one in order to forward auth-relevant data. As mentioned above, default behavior is to copy the `Authorization` and `Cookie` headers. The API key header is also added for security purposes. +1. The ASP.NET app will serve requests sent to the authenticate endpoint. As long as the API keys match, the ASP.NET app will return either the current user's serialized into the response body or it will return an HTTP status code (like 401 or 302) and response headers indicating failure. +1. When the ASP.NET Core app's `RemoteAuthenticationAuthHandler` receives the response from the ASP.NET app: + 1. If a ClaimsPrincipal was successfully returned, the auth handler will deserialize it and use it as the current user's identity. + 1. If a ClaimsPrincipal was not successfully returned, the handler will store the result and if authentication is challenged (because the user is accessing a protected resource, for example), the request's response will be updated with the status code and selected response headers from the response from the authenticate endpoint. This enables challenge responses (like redirects to a login page) to be propagated to end users. + 1. Because results from the ASP.NET app's authenticate endpoint may include data specific to that endpoint, users can register `IRemoteAuthenticationResultProcessor` implementations with the ASP.NET Core app which will run on any authentication results before they are used. As an example, the one built-in `IRemoteAuthenticationResultProcessor` is `RedirectUrlProcessor` which looks for `Location` response headers returned from the authenticate endpoint and ensures that they redirect back to the host of the ASP.NET Core app and not the ASP.NET app directly. + +#### Known limitations + +This remote authentication approach has a couple known limitations: + +1. **Windows Authentication**: Because Windows authentication depends on a handle to a Windows identity, Windows authentication is not supported by this feature. Future work is planned to explore how shared Windows authentication might work. See [dotnet/systemweb-adapters#246](https://github.com/dotnet/systemweb-adapters/issues/246) for more information. For Windows authentication scenarios, consider using in your ASP.NET Core application instead. +1. **User Management Actions**: This feature allows the ASP.NET Core app to make use of an identity authenticated by the ASP.NET app, but all actions related to users (logging on, logging off, etc.) still need to be routed through the ASP.NET app. +1. **Performance Considerations**: Each authentication request requires an HTTP call to the ASP.NET app, which may impact performance. Consider using shared cookie authentication (described in the Alternatives section) if performance is critical. + +## Shared cookie authentication + +If authentication in the ASP.NET app is done using `Microsoft.Owin` Cookie Authentication Middleware, an alternative solution to remote authentication is to configure the ASP.NET and ASP.NET Core apps so that they are able to share an authentication cookie. + +### How shared cookies work + +Sharing an authentication cookie enables: + +* Both apps to determine the user identity from the same cookie. +* Signing in or out of one app signs the user in or out of the other app. + +Both applications are configured to: +* Use the same cookie name and domain settings +* Share data protection keys for cookie encryption/decryption +* Use compatible cookie authentication middleware + +This allows users authenticated in one app to be automatically authenticated in the other app when they make requests. + +### Shared cookie authentication pros and cons + +| Pros | Cons | +|------|------| +| Best performance for shared auth | Only works with OWIN cookie auth | +| No additional HTTP requests | Requires matching data protection setup | +| Both apps can handle sign-in/sign-out | More complex initial configuration | +| Seamless user experience | Limited to cookie-based authentication | +| Lower network overhead | Requires coordination of deployments | + +### Authentication limitations with shared cookies + +Note that because signing in typically depends on a specific database, not all authentication functionality will work in both apps: + +* Users should sign in through only one of the apps, either the ASP.NET or ASP.NET Core app, whichever the database is setup to work with. +* Both apps are able to see the users' identity and claims. +* Both apps are able to sign the user out. + +Details on how to configure sharing auth cookies between ASP.NET and ASP.NET Core apps are available in [cookie sharing documentation](xref:security/cookie-sharing). For more information about cookie authentication in ASP.NET Core, see . + +The following samples in the [System.Web adapters](https://github.com/dotnet/systemweb-adapters) GitHub repo demonstrates remote app authentication with shared cookie configuration enabling both apps to sign users in and out: + +* [ASP.NET app](https://github.com/dotnet/systemweb-adapters/tree/main/samples/RemoteAuth/Identity/MvcApp) +* [ASP.NET Core app](https://github.com/dotnet/systemweb-adapters/tree/main/samples/RemoteAuth/Identity/MvcCoreApp) + +### When to choose shared cookie authentication + +**Choose Shared Cookie Authentication when:** +* Your ASP.NET app already uses `Microsoft.Owin` cookie authentication +* You can configure matching data protection settings between both apps +* Performance is critical and you want to minimize HTTP requests +* You want both apps to handle user sign-in/sign-out operations +* You're comfortable managing shared encryption keys + +Sharing authentication is a good option if both the following are true: + +* The ASP.NET app is already using `Microsoft.Owin` cookie authentication. +* It's possible to update the ASP.NET app and ASP.NET Core apps to use matching data protection settings. Matching shared data protection settings includes a shared file path, Redis cache, or Azure Blob Storage for storing data protection keys. For more information, see . + +For other scenarios, the remote authentication approach described previously in this doc is more flexible and is probably a better fit. + +## See also + +* +* +* +* +* +* +* diff --git a/aspnetcore/migration/fx-to-core/inc/samples/remote-authentication/AspNetApp.cs b/aspnetcore/migration/fx-to-core/areas/authentication/samples/AspNetApp.cs similarity index 100% rename from aspnetcore/migration/fx-to-core/inc/samples/remote-authentication/AspNetApp.cs rename to aspnetcore/migration/fx-to-core/areas/authentication/samples/AspNetApp.cs diff --git a/aspnetcore/migration/fx-to-core/inc/samples/remote-authentication/AspNetCore.cs b/aspnetcore/migration/fx-to-core/areas/authentication/samples/AspNetCore.cs similarity index 100% rename from aspnetcore/migration/fx-to-core/inc/samples/remote-authentication/AspNetCore.cs rename to aspnetcore/migration/fx-to-core/areas/authentication/samples/AspNetCore.cs diff --git a/aspnetcore/migration/fx-to-core/inc/remote-authentication.md b/aspnetcore/migration/fx-to-core/inc/remote-authentication.md deleted file mode 100644 index b5a095e57d72..000000000000 --- a/aspnetcore/migration/fx-to-core/inc/remote-authentication.md +++ /dev/null @@ -1,86 +0,0 @@ ---- -title: Remote Authentication -description: Remote Authentication -author: rick-anderson -ms.author: riande -monikerRange: '>= aspnetcore-6.0' -ms.date: 11/9/2022 -ms.topic: article -uid: migration/fx-to-core/inc/remote-authentication ---- - -# Remote Authentication - -The System.Web adapters' remote authentication feature allows an ASP.NET Core app to determine a user's identity (authenticate an HTTP request) by deferring to an ASP.NET app. Enabling the feature adds an endpoint to the ASP.NET app that returns a serialized representing the authenticated user for any requests made to the endpoint. The ASP.NET Core app, then, registers a custom authentication handler that will (for endpoints with remote authentication enabled) determine a user's identity by calling that endpoint on the ASP.NET app and passing selected headers and cookies from the original request received by the ASP.NET Core app. - -## Configuration - -There are just a few small code changes needed to enable remote authentication in a solution that's already set up according to the [Getting Started](xref:migration/fx-to-core/inc/overview). - -First, follow the [remote app setup](xref:migration/fx-to-core/inc/remote-app-setup) instructions to connect the ASP.NET Core and ASP.NET apps. Then, there are just a couple extra extension methods to call to enable remote app authentication. - -### ASP.NET app configuration - -The ASP.NET app needs to be configured to add the authentication endpoint. Adding the authentication endpoint is done by calling the `AddAuthenticationServer` extension method to set up the HTTP module that watches for requests to the authentication endpoint. Note that remote authentication scenarios typically want to add proxy support as well, so that any authentication related redirects correctly route to the ASP.NET Core app rather than the ASP.NET one. - -:::code language="csharp" source="~/migration/fx-to-core/inc/samples/remote-authentication/AspNetApp.cs" id="snippet_SystemWebAdapterConfiguration" ::: - -### ASP.NET Core app configuration - -Next, the ASP.NET Core app needs to be configured to enable the authentication handler that will authenticate users by making an HTTP request to the ASP.NET app. Again, this is done by calling `AddAuthenticationClient` when registering System.Web adapters services: - -:::code language="csharp" source="~/migration/fx-to-core/inc/samples/remote-authentication/AspNetCore.cs" id="snippet_AddSystemWebAdapters" highlight="8" ::: - -The boolean that is passed to the `AddAuthenticationClient` call specifies whether remote app authentication should be the default authentication scheme. Passing `true` will cause the user to be authenticated via remote app authentication for all requests, whereas passing `false` means that the user will only be authenticated with remote app authentication if the remote app scheme is specifically requested (with `[Authorize(AuthenticationSchemes = RemoteAppAuthenticationDefaults.AuthenticationScheme)]` on a controller or action method, for example). Passing false for this parameter has the advantage of only making HTTP requests to the original ASP.NET app for authentication for endpoints that require remote app authentication but has the disadvantage of requiring annotating all such endpoints to indicate that they will use remote app auth. - -In addition to the require boolean, an optional callback may be passed to `AddAuthenticationClient` to modify some other aspects of the remote authentication process's behavior: - -* `RequestHeadersToForward`: This property contains headers that should be forwarded from a request when calling the authenticate API. By default, the only headers forwarded are `Authorization` and `Cookie`. Additional headers can be forwarded by adding them to this list. Alternatively, if the list is cleared (so that no headers are specified), then all headers will be forwarded. -* `ResponseHeadersToForward`: This property lists response headers that should be propagated back from the authenticate request to the original call that prompted authentication in scenarios where identity is challenged. By default, this includes `Location`, `Set-Cookie`, and `WWW-Authenticate` headers. -* `AuthenticationEndpointPath`: The endpoint on the ASP.NET app where authenticate requests should be made. This defaults to `/systemweb-adapters/authenticate` and must match the endpoint specified in the ASP.NET authentication endpoint configuration. - -Finally, if the ASP.NET Core app didn't previously include authentication middleware, that will need to be enabled (after routing middleware, but before authorization middleware): - -:::code language="csharp" source="~/migration/fx-to-core/inc/samples/remote-authentication/AspNetCore.cs" id="snippet_UseAuthentication" ::: - -## Design - -1. When requests are processed by the ASP.NET Core app, if remote app authentication is the default scheme or specified by the request's endpoint, the `RemoteAuthenticationAuthHandler` will attempt to authenticate the user. - 1. The handler will make an HTTP request to the ASP.NET app's authenticate endpoint. It will copy configured headers from the current request onto this new one in order to forward auth-relevant data. As mentioned above, default behavior is to copy the `Authorize` and `Cookie` headers. The API key header is also added for security purposes. -1. The ASP.NET app will serve requests sent to the authenticate endpoint. As long as the API keys match, the ASP.NET app will return either the current user's serialized into the response body or it will return an HTTP status code (like 401 or 302) and response headers indicating failure. -1. When the ASP.NET Core app's `RemoteAuthenticationAuthHandler` receives the response from the ASP.NET app: - 1. If a ClaimsPrincipal was successfully returned, the auth handler will deserialize it and use it as the current user's identity. - 1. If a ClaimsPrincipal was not successfully returned, the handler will store the result and if authentication is challenged (because the user is accessing a protected resource, for example), the request's response will be updated with the status code and selected response headers from the response from the authenticate endpoint. This enables challenge responses (like redirects to a login page) to be propagated to end users. - 1. Because results from the ASP.NET app's authenticate endpoint may include data specific to that endpoint, users can register `IRemoteAuthenticationResultProcessor` implementations with the ASP.NET Core app which will run on any authentication results before they are used. As an example, the one built-in `IRemoteAuthenticationResultProcessor` is `RedirectUrlProcessor` which looks for `Location` response headers returned from the authenticate endpoint and ensures that they redirect back to the host of the ASP.NET Core app and not the ASP.NET app directly. - -## Known limitations - -This remote authentication approach has a couple known limitations: - -1. Because Windows authentication depends on a handle to a Windows identity, Windows authentication is not supported by this feature. Future work is planned to explore how shared Windows authentication might work. See [dotnet/systemweb-adapters#246](https://github.com/dotnet/systemweb-adapters/issues/246) for more information. -1. This feature allows the ASP.NET Core app to make use of an identity authenticated by the ASP.NET app, but all actions related to users (logging on, logging off, etc.) still need to be routed through the ASP.NET app. - -## Alternatives - -If authentication in the ASP.NET app is done using `Microsoft.Owin` Cookie Authentication Middleware, an alternative solution to sharing identity is to configure the ASP.NET and ASP.NET Core apps so that they are able to share an authentication cookie. Sharing an authentication cookie enables: - -* Both apps to determine the user identity from the same cookie. -* Signing in or out of one app signs the user in or out of the other app. - -Note that because signing in typically depends on a specific database, not all authentication functionality will work in both apps: - -* Users should sign in through only one of the apps, either the ASP.NET or ASP.NET Core app, whichever the database is setup to work with. -* Both apps are able to see the users' identity and claims. -* Both apps are able to sign the user out. - -Details on how to configure sharing auth cookies between ASP.NET and ASP.NET Core apps are available in [cookie sharing documentation](xref:security/cookie-sharing). The following samples in the [System.Web adapters](https://github.com/dotnet/systemweb-adapters) GitHub repo demonstrates remote app authentication with shared cookie configuration enabling both apps to sign users in and out : - -* [ASP.NET app](https://github.com/dotnet/systemweb-adapters/tree/main/samples/RemoteAuth/Identity/MvcApp) -* [ASP.NET Core app](https://github.com/dotnet/systemweb-adapters/tree/main/samples/RemoteAuth/Identity/MvcCoreApp) - -Sharing authentication is a good option if both the following are true: - -* The ASP.NET app is already using `Microsoft.Owin` cookie authentication. -* It's possible to update the ASP.NET app and ASP.NET Core apps to use matching data protection settings. Matching shared data protection settings includes a shared file path, Redis cache, or Azure Blob Storage for storing data protection keys. - -For other scenarios, the remote authentication approach described previously in this doc is more flexible and is probably a better fit. From e09a90e21a51840ea592750f58a7134bcfab1eff Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 30 Jun 2025 11:41:43 -0700 Subject: [PATCH 14/61] fix cross references --- .openpublishing.redirection.json | 5 +++++ aspnetcore/migration/fx-to-core/areas/session.md | 2 +- aspnetcore/migration/fx-to-core/inc/remote-app-setup.md | 4 ++-- aspnetcore/migration/fx-to-core/inc/start.md | 2 +- aspnetcore/toc.yml | 4 ++-- 5 files changed, 11 insertions(+), 6 deletions(-) diff --git a/.openpublishing.redirection.json b/.openpublishing.redirection.json index 4df5e1b2ae51..c208747fcc12 100644 --- a/.openpublishing.redirection.json +++ b/.openpublishing.redirection.json @@ -1070,6 +1070,11 @@ "redirect_url": "/aspnet/core/migration/fx-to-core/areas/session#remote-app-session-state", "redirect_document_id": false }, + { + "source_path": "aspnetcore/migration/fx-to-core/inc/remote-authentication.md", + "redirect_url": "/aspnet/core/migration/fx-to-core/areas/authentication#remote-authentication", + "redirect_document_id": false + }, { "source_path": "aspnetcore/migration/fx-to-core/inc/session.md", "redirect_url": "/aspnet/core/migration/fx-to-core/areas/session", diff --git a/aspnetcore/migration/fx-to-core/areas/session.md b/aspnetcore/migration/fx-to-core/areas/session.md index 7e5be10c36bb..fbbd32d0bc5f 100644 --- a/aspnetcore/migration/fx-to-core/areas/session.md +++ b/aspnetcore/migration/fx-to-core/areas/session.md @@ -152,7 +152,7 @@ In order to serialize session state, a serializer for the state object must be r :::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/remote/Program.cs" id="snippet_Serialization" ::: -In ASP.NET Core, [BinaryFormatter](dotnet/api/system.runtime.serialization.formatters.binary.binaryformatter) was used to automatically serialize session value contents. In order to serialize these with for use with the System.Web adapters, the serialization must be explicitly configured using `ISessionKeySerializer` implementations. +In ASP.NET Core, [BinaryFormatter](/dotnet/api/system.runtime.serialization.formatters.binary.binaryformatter) was used to automatically serialize session value contents. In order to serialize these with for use with the System.Web adapters, the serialization must be explicitly configured using `ISessionKeySerializer` implementations. Out of the box, there is a simple JSON serializer that allows each session key to be registered to a known type using `JsonSessionSerializerOptions`: diff --git a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md index 453df0ed77e3..14bbbd92e9dc 100644 --- a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md +++ b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md @@ -13,7 +13,7 @@ uid: migration/fx-to-core/inc/remote-app-setup In some incremental upgrade scenarios, it's useful for the new ASP.NET Core app to be able to communicate with the original ASP.NET app. -Specifically, this capability is used, currently, for [remote app authentication](xref:migration/fx-to-core/inc/remote-authentication) and [remote session](xref:migration/fx-to-core/areas/session#remote-app-session-state) features. +Specifically, this capability is used, currently, for [remote app authentication](xref:migration/fx-to-core/areas/authentication#remote-authenticationn) and [remote session](xref:migration/fx-to-core/areas/session#remote-app-session-state) features. ## Configuration @@ -97,7 +97,7 @@ builder.Services.AddSystemWebAdapters() }); ``` -With both the ASP.NET and ASP.NET Core app updated, extension methods can now be used to set up [remote app authentication](xref:migration/fx-to-core/inc/remote-authentication) or [remote session](xref:migration/fx-to-core/areas/session#remote-app-session-state), as needed. +With both the ASP.NET and ASP.NET Core app updated, extension methods can now be used to set up [remote app authentication](xref:migration/fx-to-core/areas/authentication#remote-authenticationn) or [remote session](xref:migration/fx-to-core/areas/session#remote-app-session-state), as needed. ## Securing the remote app connection diff --git a/aspnetcore/migration/fx-to-core/inc/start.md b/aspnetcore/migration/fx-to-core/inc/start.md index cf87a2b005ca..66a05630043c 100644 --- a/aspnetcore/migration/fx-to-core/inc/start.md +++ b/aspnetcore/migration/fx-to-core/inc/start.md @@ -40,7 +40,7 @@ Session is a commonly used feature of ASP.NET that shares the name with a featur ## Enable shared authentication support -It is possible to share authentication between the original ASP.NET app and the new ASP.NET Core app by using the `System.Web` adapters remote authentication feature. This feature allows the ASP.NET Core app to defer authentication to the ASP.NET app. See the [remote app connection](xref:migration/fx-to-core/inc/remote-app-setup) and [remote authentication](xref:migration/fx-to-core/inc/remote-authentication) docs for more details. +It is possible to share authentication between the original ASP.NET app and the new ASP.NET Core app by using the `System.Web` adapters remote authentication feature. This feature allows the ASP.NET Core app to defer authentication to the ASP.NET app. See the [remote app connection](xref:migration/fx-to-core/inc/remote-app-setup) and [remote authentication](xref:migration/fx-to-core/areas/authentication#remote-authenticationn) docs for more details. ## General Usage Guidance diff --git a/aspnetcore/toc.yml b/aspnetcore/toc.yml index 5b5f8111c0e3..0263265da0ab 100644 --- a/aspnetcore/toc.yml +++ b/aspnetcore/toc.yml @@ -2111,8 +2111,6 @@ items: uid: migration/fx-to-core/inc/remote-app-setup - name: Usage Guidance uid: migration/fx-to-core/inc/usage_guidance - - name: Remote Authentication - uid: migration/fx-to-core/inc/remote-authentication - name: Unit testing uid: migration/fx-to-core/inc/unit-testing - name: A/B Testing endpoints @@ -2141,6 +2139,8 @@ items: uid: migration/fx-to-core/areas/http-handlers - name: Session uid: migration/fx-to-core/areas/session + - name: Authentication + uid: migration/fx-to-core/areas/authentication - name: Membership uid: migration/fx-to-core/areas/membership - name: Web API From 91446754ffae8cf453fb6391c1df8df784e6d6fc Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 30 Jun 2025 12:04:24 -0700 Subject: [PATCH 15/61] expand starting --- aspnetcore/migration/fx-to-core/inc/start.md | 155 +++++++++++++++++-- 1 file changed, 140 insertions(+), 15 deletions(-) diff --git a/aspnetcore/migration/fx-to-core/inc/start.md b/aspnetcore/migration/fx-to-core/inc/start.md index 66a05630043c..34f067cb425e 100644 --- a/aspnetcore/migration/fx-to-core/inc/start.md +++ b/aspnetcore/migration/fx-to-core/inc/start.md @@ -11,37 +11,162 @@ uid: migration/fx-to-core/inc/start # Get started with incremental ASP.NET to ASP.NET Core migration +> [!IMPORTANT] +> **Before you begin**: This article assumes you have read the [Incremental ASP.NET to ASP.NET Core migration overview](xref:migration/fx-to-core/inc/overview). If you haven't read it yet, please start there to understand the concepts, approach, and benefits of incremental migration. + For a large migration, we recommend setting up a ASP.NET Core app that proxies to the original .NET Framework app. The new proxy enabled app is shown in the following image: ![start migrating routes](~/migration/fx-to-core/inc/overview/static/nop.png) -To understand how this approach is helpful in the migration process, see [Incremental ASP.NET to ASP.NET Core migration](xref:migration/fx-to-core/inc/overview). The rest of this article provides the steps to proceed with an incremental migration. +This article provides the practical steps to proceed with an incremental migration after you understand the approach. + +## Prerequisites + +Before starting your incremental migration, ensure you have: + +1. **Read the overview**: [Incremental ASP.NET to ASP.NET Core migration](xref:migration/fx-to-core/inc/overview) +2. **A working ASP.NET Framework application** that you want to migrate +3. **Visual Studio 2022** with the latest updates +4. **.NET 8 or later SDK** installed +5. **Understanding of your application's dependencies** and third-party libraries + +## Migration Steps Overview + +The incremental migration process follows these key steps: + +1. [Set up ASP.NET Core Project](#set-up-aspnet-core-project) +2. [Remediate Technical Debt](#remediate-technical-debt) +3. [Identify and address cross-cutting concerns](#identify-and-address-cross-cutting-concerns) +4. [Upgrade supporting libraries](#upgrade-supporting-libraries) ## Set up ASP.NET Core Project -See for help in setting up projects required for incremental migration. +The first step is to create the new ASP.NET Core application that will serve as your proxy. + +**What you'll do:** +* Create a new ASP.NET Core project alongside your existing ASP.NET Framework app +* Configure it to proxy requests to your original application using YARP (Yet Another Reverse Proxy) +* Set up the basic infrastructure for incremental migration + +**Detailed instructions:** +* See to understand how to set up an application for incremental migration. +* See for help in setting up projects required for incremental migration using Visual Studio tooling. + +## Remediate Technical Debt + +**When to do this step:** Before upgrading any supporting libraries, address technical debt that could complicate the migration process. + +Before you begin upgrading your supporting libraries, it's important to clean up technical debt that could interfere with the migration process. This step should be completed first to ensure a smoother upgrade experience. + +### Update Package Dependencies + +Review and update your NuGet packages to their latest compatible versions: + +1. **Audit existing packages**: Use Visual Studio's NuGet Package Manager as the `dotnet` CLI does not work for ASP.NET Framework applications +2. **Update packages incrementally**: Update packages one at a time to avoid compatibility issues +3. **Test after each update**: Ensure your application still functions correctly after each package update +4. **Address breaking changes**: Some package updates may introduce breaking changes that need to be addressed + +### Modernize Build Tools + +Update your build tools and project configuration: + +1. **Update tools**: Ensure you're using a recent version of MSBuild/Visual Studio +2. **Migrate to SDK-style project files**: Convert your existing project files to the modern SDK-style format. This is essential for .NET Core/.NET 5+ compatibility and provides better tooling support +3. **Review project files**: Consider migrating from `packages.config` to `PackageReference` format if you haven't already in the Web application project +4. **Update build scripts**: Review and update any custom build scripts or CI/CD configurations +5. **Clean up unused references**: Remove any unused assembly references or NuGet packages + +### Address Code Quality Issues + +Fix known code quality issues that could complicate migration: + +1. **Run static analysis**: Use tools like CodeQL or Visual Studio's built-in analyzers +2. **Fix compiler warnings**: Address any compiler warnings, especially those related to deprecated APIs +3. **Remove dead code**: Clean up unused classes, methods, and other code elements +4. **Update deprecated API usage**: Replace usage of deprecated APIs with their modern equivalents where possible + +This preparation work will make the library upgrade process much smoother and reduce the likelihood of encountering complex issues during migration. + +## Identify and address cross-cutting concerns + +**When to do this step:** While remediating technical debt but before upgrading supporting libraries, identify and configure cross-cutting concerns that affect your entire application. + +Cross-cutting concerns are aspects of your application that span multiple layers or components, such as authentication, session management, logging, and caching. These need to be addressed early in the migration process because they affect how your ASP.NET Framework and ASP.NET Core applications communicate and share state during the incremental migration. + +The following sections cover the most common cross-cutting concerns. Configure only the ones that apply to your application: + +### Session Support Configuration + +**Configure this if:** Your ASP.NET Framework application uses session state. + +See the general [session migration documentation](xref:migration/fx-to-core/areas/session#remote-app-session state) for guidance here. + +Session is a commonly used feature of ASP.NET that shares the name with a feature in ASP.NET Core, but the APIs are much different. When upgrading libraries that use session state, you'll need to configure session support. See the documentation on [remote session support](xref:migration/fx-to-core/areas/session) for detailed guidance on how to enable session state sharing between your applications. + +### Authentication Configuration + +**Configure this if:** Your ASP.NET Framework application uses authentication and you want to share authentication state between the old and new applications. + +See the general [authentication migration documentation](xref:migration/fx-to-core/areas/authentication) for guidance here. + +It is possible to share authentication between the original ASP.NET app and the new ASP.NET Core app by using the System.Web adapters remote authentication feature. This feature allows the ASP.NET Core app to defer authentication to the ASP.NET app. See the documentation on [remote authentication](xref:migration/fx-to-core/areas/authentication#remote-authentication) for more details. + +### Other Cross-Cutting Concerns to Consider + +Depending on your application, you may also need to address: + +* **Logging**: Ensure consistent logging across both applications. Consider using a shared logging provider or ensuring logs are aggregated properly. +* **Caching**: If your application uses caching (in-memory, distributed, or output caching), plan how to maintain cache consistency between applications. +* **Error Handling**: Establish consistent error handling and reporting across both the ASP.NET Framework and ASP.NET Core applications. +* **Configuration Management**: Plan how configuration settings will be shared or managed between the two applications. +* **Health Monitoring**: Set up monitoring and health checks for both applications during the migration process. +* **Dependency Injection**: If using a DI container in your ASP.NET Framework app, plan the migration to ASP.NET Core's built-in DI container. ## Upgrade supporting libraries -If you have supporting libraries in your solution that you will need to use, they should be upgraded to .NET Standard 2.0, if possible. [Upgrade Assistant](https://github.com/dotnet/upgrade-assistant) is a great tool for this. If libraries are unable to target .NET Standard, you can target .NET 6 or later either along with the .NET Framework target in the original project or in a new project alongside the original. +**When to do this step:** Only when you need to migrate specific routes that depend on class libraries containing business logic you'll need to share between the old and new applications. -The [adapters](xref:migration/fx-to-core/systemweb-adapters) can be used in these libraries to enable support for `System.Web.HttpContext` usage in class libraries. In order to enable `System.Web.HttpContext` usage in a library: +> [!NOTE] +> **Incremental approach**: With the incremental migration process, you don't need to upgrade all your supporting libraries at once. You only need to upgrade the libraries that are required for the specific routes you're currently migrating. This allows you to tackle the migration in smaller, more manageable pieces. -1. Remove reference to `System.Web` in the project file -1. Add the `Microsoft.AspNetCore.SystemWebAdapters` package -1. Enable multi-targeting and add a .NET 6 target or later, or convert the project to .NET Standard 2.0. -1. Ensure the target framework supports .NET Core. Multi-targeting can be used if .NET Standard 2.0 is not sufficient +### Library Upgrade Process -This step may require a number of projects to change depending on your solution structure. Upgrade Assistant can help you identify which ones need to change and automate a number of steps in the process. +> [!IMPORTANT] +> Supporting libraries must be upgraded in a **postorder depth-first search ordering**. This means: +> +> 1. **Start with leaf dependencies**: Begin with libraries that have no dependencies on other libraries in your solution +> 2. **Work upward through the dependency tree**: Only upgrade a library after all of its dependencies have been successfully upgraded +> 3. **End with the main application**: The main ASP.NET Framework application should be the last item to be modified +> +>This ordering is essential because: +> * It ensures that when you upgrade a library, all of its dependencies are already compatible +> * It prevents circular dependency issues during the upgrade process +> * It allows you to test each library independently before moving to its dependents +> +> **NOTE**: You only need to follow this ordering for the subset of libraries required by the routes you're currently migrating, not your entire solution. + +**Upgrade process for each library:** + +If you have supporting libraries in your solution that you will need to use for the routes you're migrating, they should be upgraded to .NET Standard 2.0, if possible. [Upgrade Assistant](https://github.com/dotnet/upgrade-assistant) is a great tool for this. If libraries are unable to target .NET Standard, you can target .NET 8 or later either along with the .NET Framework target in the original project or in a new project alongside the original. + +The [System.Web adapters](xref:migration/fx-to-core/inc/usage_guidance) can be used in these libraries to enable support for usage in class libraries. In order to enable usage in a library: + +1. Remove reference to `System.Web` in the project file +2. Add the `Microsoft.AspNetCore.SystemWebAdapters` package +3. Enable multi-targeting and add a .NET 8 target or later, or convert the project to .NET Standard 2.0. +4. Ensure the target framework supports .NET Core. Multi-targeting can be used if .NET Standard 2.0 is not sufficient -## Enable Session Support +This step may require a number of projects to change depending on your solution structure and which routes you're migrating. Upgrade Assistant can help you identify which ones need to change and automate a number of steps in the process. -Session is a commonly used feature of ASP.NET that shares the name with a feature in ASP.NET Core the APIs are much different. See the documentation on [session support](xref:migration/fx-to-core/areas/session). -## Enable shared authentication support +## Next Steps -It is possible to share authentication between the original ASP.NET app and the new ASP.NET Core app by using the `System.Web` adapters remote authentication feature. This feature allows the ASP.NET Core app to defer authentication to the ASP.NET app. See the [remote app connection](xref:migration/fx-to-core/inc/remote-app-setup) and [remote authentication](xref:migration/fx-to-core/areas/authentication#remote-authenticationn) docs for more details. +Once you've completed the setup and library upgrade steps above: -## General Usage Guidance +1. **Start small**: Begin by migrating simple, stateless endpoints first +2. **Test thoroughly**: Ensure each migrated component works correctly in both environments +3. **Monitor performance**: Watch for any performance impacts from the proxy setup +4. **Iterate**: Continue migrating components incrementally until the migration is complete -There are a number of differences between ASP.NET and ASP.NET Core that the adapters are able to help update. However, there are some features that require an opt-in as they incur some cost. There are also behaviors that cannot be adapted. See [usage guidance](xref:migration/fx-to-core/inc/usage_guidance) for a list of these. +For ongoing support and advanced scenarios, refer to the [usage guidance](xref:migration/fx-to-core/inc/usage_guidance) documentation. From efacc907d99d5eecb2b084234b7827fc3d33f25b Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 30 Jun 2025 12:08:15 -0700 Subject: [PATCH 16/61] combine unit testing into systemweb-adapters --- .../fx-to-core/inc/systemweb-adapters.md | 10 ++++++++-- .../migration/fx-to-core/inc/unit-testing.md | 18 ------------------ aspnetcore/toc.yml | 2 -- 3 files changed, 8 insertions(+), 22 deletions(-) delete mode 100644 aspnetcore/migration/fx-to-core/inc/unit-testing.md diff --git a/aspnetcore/migration/fx-to-core/inc/systemweb-adapters.md b/aspnetcore/migration/fx-to-core/inc/systemweb-adapters.md index ab45898f5937..556cf1e37dd2 100644 --- a/aspnetcore/migration/fx-to-core/inc/systemweb-adapters.md +++ b/aspnetcore/migration/fx-to-core/inc/systemweb-adapters.md @@ -73,6 +73,12 @@ public class SomeController : Controller Notice that since there's a property, they can pass that through, but it generally looks the same. Using implicit conversions, the can be converted into the adapter that could then be passed around through the levels utilizing the code in the same way. -## See also +## Unit Testing -* +When unit testing code that uses the System.Web adapters, there are some special considerations to keep in mind. + +In most cases, there's no need to set up additional components for running tests. But if the component being tested uses , it might be necessary to start up the `SystemWebAdapters` service, as shown in the following example: + +:::code language="csharp" source="~/migration/fx-to-core/inc/samples/unit-testing/Program.cs" id="snippet_UnitTestingFixture" ::: + +The tests must be executed in sequence, not in parallel. The preceding example illustrates how to achieve this by setting [XUnit's `DisableParallelization` option](https://xunit.net/docs/running-tests-in-parallel#parallelism-in-test-frameworks) to `true`. This setting disables parallel execution for a specific test collection, ensuring that the tests within that collection run one after the other, without concurrency. diff --git a/aspnetcore/migration/fx-to-core/inc/unit-testing.md b/aspnetcore/migration/fx-to-core/inc/unit-testing.md deleted file mode 100644 index b4bf29e1730f..000000000000 --- a/aspnetcore/migration/fx-to-core/inc/unit-testing.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -title: Unit Testing -description: Unit Testing -author: afshinm -ms.author: amehrabani -monikerRange: '>= aspnetcore-6.0' -ms.date: 10/03/2023 -ms.topic: article -uid: migration/fx-to-core/inc/unit-testing ---- - -# Unit Testing - -In most cases, there's no need to set up additional components for running tests. But if the component being tested uses , it might be necessary to start up the `SystemWebAdapters` service, as shown in the following example: - -:::code language="csharp" source="~/migration/fx-to-core/inc/samples/unit-testing/Program.cs" id="snippet_UnitTestingFixture" ::: - -The tests must be executed in sequence, not in parallel. The preceding example illustrates how to achieve this by setting [XUnit's `DisableParallelization` option](https://xunit.net/docs/running-tests-in-parallel#parallelism-in-test-frameworks) to `true`. This setting disables parallel execution for a specific test collection, ensuring that the tests within that collection run one after the other, without concurrency. diff --git a/aspnetcore/toc.yml b/aspnetcore/toc.yml index 0263265da0ab..f614f507c743 100644 --- a/aspnetcore/toc.yml +++ b/aspnetcore/toc.yml @@ -2111,8 +2111,6 @@ items: uid: migration/fx-to-core/inc/remote-app-setup - name: Usage Guidance uid: migration/fx-to-core/inc/usage_guidance - - name: Unit testing - uid: migration/fx-to-core/inc/unit-testing - name: A/B Testing endpoints uid: migration/fx-to-core/inc/ab-testing - name: Blazor support with YARP From ec497b83e51f3a756f4f2f3224a143e42bcdec15 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 30 Jun 2025 12:32:57 -0700 Subject: [PATCH 17/61] update httpcontext docs --- .../fx-to-core/areas/http-context.md | 206 +++++++++--------- 1 file changed, 108 insertions(+), 98 deletions(-) diff --git a/aspnetcore/migration/fx-to-core/areas/http-context.md b/aspnetcore/migration/fx-to-core/areas/http-context.md index 0dbe26775c85..ee21e52f9db4 100644 --- a/aspnetcore/migration/fx-to-core/areas/http-context.md +++ b/aspnetcore/migration/fx-to-core/areas/http-context.md @@ -1,159 +1,168 @@ --- -title: Migrate from System.Web.HttpContext to Micrsoft.AspNetCore.Http.HttpContext -description: Learn how to migrate from System.Web.HttpContext to Micrsoft.AspNetCore.Http.HttpContext +title: Migrate ASP.NET Framework HttpContext to ASP.NET Core +description: Learn how to migrate from System.Web.HttpContext to Microsoft.AspNetCore.Http.HttpContext author: twsouthwick ms.author: tasou ms.date: 6/20/2025 uid: migration/fx-to-core/areas/http-context --- -# Migrate from System.Web.HttpContext to Micrsoft.AspNetCore.Http.HttpContext +# Migrate ASP.NET Framework HttpContext to ASP.NET Core -This article shows how to translate the most commonly used properties of to the equivalent in ASP.NET Core. +HttpContext is a fundamental component of web applications, providing access to HTTP request and response information. When migrating from ASP.NET Framework to ASP.NET Core, HttpContext presents unique challenges because the two frameworks have different APIs and approaches. -## Overview +## Why HttpContext migration is complex -`HttpContext` has significantly changed in ASP.NET Core. When migrating HTTP modules or handlers to middleware, you'll need to update your code to work with the new `HttpContext` API. - -In ASP.NET Core middleware, the `Invoke` method takes a parameter of type `HttpContext`: - -```csharp -public async Task Invoke(HttpContext context) -``` - -This `HttpContext` is different from the ASP.NET Framework version and requires different approaches to access request and response information. - -## HttpContext - -**HttpContext.Items** translates to: - -[!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Items)] - -**Unique request ID (no System.Web.HttpContext counterpart)** - -Gives you a unique id for each request. Very useful to include in your logs. - -[!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Trace)] - -## HttpContext.Request - -**HttpContext.Request.HttpMethod** translates to: - -[!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Method)] - -**HttpContext.Request.QueryString** translates to: - -[!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Query)] - -**HttpContext.Request.Url** and **HttpContext.Request.RawUrl** translate to: - -[!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Url)] +ASP.NET Framework and ASP.NET Core have fundamentally different HttpContext implementations: -**HttpContext.Request.IsSecureConnection** translates to: +* **ASP.NET Framework** uses with built-in properties and methods +* **ASP.NET Core** uses with a more modular, extensible design -[!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Secure)] +These differences mean you can't simply move your HttpContext code from Framework to Core without changes. -**HttpContext.Request.UserHostAddress** translates to: +## Migration strategies overview -[!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Host)] +You have two main approaches for handling HttpContext during migration: -**HttpContext.Request.Cookies** translates to: +1. **Complete rewrite** - Rewrite all HttpContext code to use ASP.NET Core's native HttpContext implementation +2. **System.Web adapters** - Use adapters to minimize code changes while migrating incrementally -[!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Cookies)] +For most applications, migrating to ASP.NET Core's native HttpContext provides the best performance and maintainability. However, larger applications or those with extensive HttpContext usage may benefit from using System.Web adapters during incremental migration. -**HttpContext.Request.RequestContext.RouteData** translates to: +## Choose your migration approach -[!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Route)] +You have two main options for migrating HttpContext from ASP.NET Framework to ASP.NET Core. Your choice depends on your migration timeline, whether you need to run both applications simultaneously, and how much code you're willing to rewrite. -**HttpContext.Request.Headers** translates to: +### Quick decision guide -[!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Headers)] +**Answer these questions to choose your approach:** -**HttpContext.Request.UserAgent** translates to: +1. **Are you doing a complete rewrite or incremental migration?** + * Complete rewrite → [Complete rewrite to ASP.NET Core HttpContext](#complete-rewrite-to-aspnet-core-httpcontext) + * Incremental migration → Continue to question 2 -[!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Agent)] +2. **Do you have extensive HttpContext usage across shared libraries?** + * Yes, lots of shared code → [System.Web adapters](#systemweb-adapters) + * No, isolated HttpContext usage → [Complete rewrite to ASP.NET Core HttpContext](#complete-rewrite-to-aspnet-core-httpcontext) -**HttpContext.Request.UrlReferrer** translates to: +### Migration approaches comparison -[!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Referrer)] +| Approach | Code Changes | Performance | Shared Libraries | When to Use | +|----------|-------------|-------------|------------------|-------------| +| **[Complete rewrite](#complete-rewrite-to-aspnet-core-httpcontext)** | High - Rewrite all HttpContext code | Best | Requires updates | Complete rewrites, performance-critical apps | +| **[System.Web adapters](#systemweb-adapters)** | Low - Keep existing patterns | Good | Works with existing code | Incremental migrations, extensive HttpContext usage | -**HttpContext.Request.ContentType** translates to: +## Complete rewrite to ASP.NET Core HttpContext -[!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Type)] +Choose this approach when you're performing a complete migration and can rewrite HttpContext-related code to use ASP.NET Core's native implementation. -**HttpContext.Request.Form** translates to: +ASP.NET Core's HttpContext provides a more modular and extensible design compared to ASP.NET Framework. This approach offers the best performance but requires more code changes during migration. -[!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Form)] +### Overview -> [!WARNING] -> Read form values only if the content sub type is *x-www-form-urlencoded* or *form-data*. - -**HttpContext.Request.InputStream** translates to: - -[!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Input)] - -> [!WARNING] -> Use this code only in a handler type middleware, at the end of a pipeline. -> ->You can read the raw body as shown above only once per request. Middleware trying to read the body after the first read will read an empty body. -> ->This doesn't apply to reading a form as shown earlier, because that's done from a buffer. - -## HttpContext.Response +`HttpContext` has significantly changed in ASP.NET Core. When migrating HTTP modules or handlers to middleware, you'll need to update your code to work with the new `HttpContext` API. -**HttpContext.Response.Status** and **HttpContext.Response.StatusDescription** translate to: +In ASP.NET Core middleware, the `Invoke` method takes a parameter of type `HttpContext`: -[!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Status)] +```csharp +public async Task Invoke(HttpContext context) +``` -**HttpContext.Response.ContentEncoding** and **HttpContext.Response.ContentType** translate to: +This `HttpContext` is different from the ASP.NET Framework version and requires different approaches to access request and response information. -[!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_RespType)] +### Property translations -**HttpContext.Response.ContentType** on its own also translates to: +This section shows how to translate the most commonly used properties of to the equivalent in ASP.NET Core. -[!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_RespTypeOnly)] +#### HttpContext properties -**HttpContext.Response.Output** translates to: +| ASP.NET Framework | ASP.NET Core | Code Sample | Notes | +|-------------------|--------------|-------------|-------| +| | | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Items)] | Works the same way | +| *No equivalent* | | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Trace)] | Unique request ID for logging | -[!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Output)] +#### HttpRequest properties -**HttpContext.Response.TransmitFile** +| ASP.NET Framework | ASP.NET Core | Code Sample | Notes | +|-------------------|--------------|-------------|-------| +| | | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Method)] | | +| | | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Query)] | | +|
| Multiple properties | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Url)] | Use Request.Scheme, Host, PathBase, Path, QueryString | +| | | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Secure)] | | +| | | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Host)] | | +| | | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Cookies)] | | +| | | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Route)] | | +| | | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Headers)] | | +| | | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Agent)] | Access via Headers["User-Agent"] | +| | | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Referrer)] | Access via Headers["Referer"] | +| | | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Type)] | | +| | | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Form)] | **Warning**: Read form values only if content type is *x-www-form-urlencoded* or *form-data* | +| | | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Input)] | **Warning**: Use only in handler middleware at end of pipeline. Body can only be read once per request | -Serving up a file is discussed in . +#### HttpResponse properties -**HttpContext.Response.Headers** +| ASP.NET Framework | ASP.NET Core | Code Sample | Notes | +|-------------------|--------------|-------------|-------| +|
| | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Status)] | | +|
| | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_RespType)] | | +| | | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_RespTypeOnly)] | | +| | | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Output)] | | +| | See request features | | Serving files is discussed in | +| | | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_SetHeaders)] | Must use callback pattern to set headers before response starts | +| | | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_SetCookies)] | Must use callback pattern to set cookies before response starts | -Sending response headers is complicated by the fact that if you set them after anything has been written to the response body, they will not be sent. +#### Response headers and cookies patterns -The solution is to set a callback method that will be called right before writing to the response starts. This is best done at the start of the `Invoke` method in your middleware. It's this callback method that sets your response headers. +Since response headers and cookies require special handling in ASP.NET Core, here are the patterns: -The following code sets a callback method called `SetHeaders`: +**Setting response headers:** ```csharp public async Task Invoke(HttpContext httpContext) { - // ... + // Set callback to execute before response starts httpContext.Response.OnStarting(SetHeaders, state: httpContext); + // ... rest of middleware logic +} ``` -The `SetHeaders` callback method would look like this: - -[!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_SetHeaders)] - -**HttpContext.Response.Cookies** - -Cookies travel to the browser in a *Set-Cookie* response header. As a result, sending cookies requires the same callback as used for sending response headers: +**Setting response cookies:** ```csharp public async Task Invoke(HttpContext httpContext) { - // ... + // Set callbacks to execute before response starts httpContext.Response.OnStarting(SetCookies, state: httpContext); httpContext.Response.OnStarting(SetHeaders, state: httpContext); + // ... rest of middleware logic +} ``` -The `SetCookies` callback method would look like the following: +## System.Web adapters + +[!INCLUDE[](~/migration/fx-to-core/includes/uses-systemweb-adapters.md)] + +Choose this approach when you have extensive HttpContext usage across shared libraries or when performing an incremental migration where you want to minimize code changes. + +The [System.Web adapters](~/migration/fx-to-core/inc/systemweb-adapters.md) provide a compatibility layer that allows you to use familiar APIs in ASP.NET Core applications. This approach is particularly useful when: + +* You have shared libraries that use +* You're performing an incremental migration +* You want to minimize code changes during the migration process + +### Benefits of using System.Web adapters + +* **Minimal code changes**: Keep your existing `System.Web.HttpContext` usage patterns +* **Shared libraries**: Libraries can work with both ASP.NET Framework and ASP.NET Core +* **Incremental migration**: Migrate applications piece by piece without breaking shared dependencies +* **Faster migration**: Reduce the time needed to migrate complex applications + +### Considerations + +* **Performance**: While good, adapters introduce some overhead compared to native ASP.NET Core APIs +* **Feature parity**: Not all features are available through adapters +* **Long-term strategy**: Consider eventually migrating to native ASP.NET Core APIs for best performance -[!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_SetCookies)] +For more information about System.Web adapters, see the [System.Web adapters documentation](~/migration/fx-to-core/inc/systemweb-adapters.md). ## Additional resources @@ -161,3 +170,4 @@ The `SetCookies` callback method would look like the following: * [HttpContext in ASP.NET Core](xref:fundamentals/httpcontext) * [Middleware](xref:fundamentals/middleware/index) * [Configuration](xref:fundamentals/configuration/index) +* [System.Web adapters](~/migration/fx-to-core/inc/systemweb-adapters.md) From 0bebf0cceea70f1de51f23879a0ce9941034b14a Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 30 Jun 2025 12:46:17 -0700 Subject: [PATCH 18/61] list again --- .openpublishing.redirection.json | 5 + .../fx-to-core/areas/http-context.md | 125 ++++++++++++++---- .../migration/fx-to-core/inc/overview.md | 1 - aspnetcore/security/cookie-sharing.md | 2 +- 4 files changed, 103 insertions(+), 30 deletions(-) diff --git a/.openpublishing.redirection.json b/.openpublishing.redirection.json index c208747fcc12..b31c32c7432c 100644 --- a/.openpublishing.redirection.json +++ b/.openpublishing.redirection.json @@ -1010,6 +1010,11 @@ "redirect_url": "/aspnet/core/migration/fx-to-core/systemweb-adapters", "redirect_document_id": false }, + { + "source_path": "aspnetcore/migration/inc/unit-testing.md", + "redirect_url": "/aspnet/core/migration/fx-to-core/systemweb-adapters", + "redirect_document_id": false + }, { "source_path": "aspnetcore/migration/inc/blazor.md", "redirect_url": "/aspnet/core/migration/fx-to-core/inc/blazor", diff --git a/aspnetcore/migration/fx-to-core/areas/http-context.md b/aspnetcore/migration/fx-to-core/areas/http-context.md index ee21e52f9db4..c4abfd3c8343 100644 --- a/aspnetcore/migration/fx-to-core/areas/http-context.md +++ b/aspnetcore/migration/fx-to-core/areas/http-context.md @@ -75,40 +75,109 @@ This section shows how to translate the most commonly used properties of | | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Items)] | Works the same way | -| *No equivalent* | | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Trace)] | Unique request ID for logging | +* **** → **** + + [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Items)] + +* ***No equivalent*** → **** + + [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Trace)] + + Unique request ID for logging #### HttpRequest properties -| ASP.NET Framework | ASP.NET Core | Code Sample | Notes | -|-------------------|--------------|-------------|-------| -| | | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Method)] | | -| | | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Query)] | | -|
| Multiple properties | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Url)] | Use Request.Scheme, Host, PathBase, Path, QueryString | -| | | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Secure)] | | -| | | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Host)] | | -| | | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Cookies)] | | -| | | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Route)] | | -| | | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Headers)] | | -| | | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Agent)] | Access via Headers["User-Agent"] | -| | | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Referrer)] | Access via Headers["Referer"] | -| | | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Type)] | | -| | | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Form)] | **Warning**: Read form values only if content type is *x-www-form-urlencoded* or *form-data* | -| | | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Input)] | **Warning**: Use only in handler middleware at end of pipeline. Body can only be read once per request | +* **** → **** + + [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Method)] + +* **** → **** + + [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Query)] + +* **** / **** → **Multiple properties** + + [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Url)] + + Use Request.Scheme, Host, PathBase, Path, QueryString + +* **** → **** + + [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Secure)] + +* **** → **** + + [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Host)] + +* **** → **** + + [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Cookies)] + +* **** → **** + + [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Route)] + +* **** → **** + + [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Headers)] + +* **** → **** + + [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Agent)] + +* **** → **** + + [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Referrer)] + +* **** → **** + + [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Type)] + +* **** → **** + + [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Form)] + + **Warning**: Read form values only if content type is *x-www-form-urlencoded* or *form-data* + +* **** → **** + + [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Input)] + + **Warning**: Use only in handler middleware at end of pipeline. Body can only be read once per request #### HttpResponse properties -| ASP.NET Framework | ASP.NET Core | Code Sample | Notes | -|-------------------|--------------|-------------|-------| -|
| | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Status)] | | -|
| | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_RespType)] | | -| | | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_RespTypeOnly)] | | -| | | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Output)] | | -| | See request features | | Serving files is discussed in | -| | | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_SetHeaders)] | Must use callback pattern to set headers before response starts | -| | | [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_SetCookies)] | Must use callback pattern to set cookies before response starts | +* **** / **** → **** + + [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Status)] + +* **** / **** → **** + + [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_RespType)] + +* **** → **** + + [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_RespTypeOnly)] + +* **** → **** + + [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Output)] + +* **** → **See request features** + + Serving files is discussed in + +* **** → **** + + [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_SetHeaders)] + + Must use callback pattern to set headers before response starts + +* **** → **** + + [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_SetCookies)] + + Must use callback pattern to set cookies before response starts #### Response headers and cookies patterns diff --git a/aspnetcore/migration/fx-to-core/inc/overview.md b/aspnetcore/migration/fx-to-core/inc/overview.md index 13f7f38519cb..e20a83e27376 100644 --- a/aspnetcore/migration/fx-to-core/inc/overview.md +++ b/aspnetcore/migration/fx-to-core/inc/overview.md @@ -76,4 +76,3 @@ For guidance around usage, see the [usage guidance article](xref:migration/fx-to * [Example migration of eShop to ASP.NET Core](/dotnet/architecture/porting-existing-aspnet-apps/example-migration-eshop) * [Video:Tooling for Incremental ASP.NET Core Migrations](https://www.youtube.com/watch?v=P96l0pDNVpM) -* diff --git a/aspnetcore/security/cookie-sharing.md b/aspnetcore/security/cookie-sharing.md index 724c2991bc7a..23b64cedceaa 100644 --- a/aspnetcore/security/cookie-sharing.md +++ b/aspnetcore/security/cookie-sharing.md @@ -85,7 +85,7 @@ When the Identity schema is different among apps, usually because apps are using ASP.NET 4.x apps that use Microsoft.Owin Cookie Authentication Middleware can be configured to generate authentication cookies that are compatible with the ASP.NET Core Cookie Authentication Middleware. This can be useful if a web application consists of both ASP.NET 4.x apps and ASP.NET Core apps that must share a single sign-on experience. A specific example of such a scenario is [incrementally migrating](xref:migration/fx-to-core/inc/overview) a web app from ASP.NET to ASP.NET Core. In such scenarios, it's common for some parts of an app to be served by the original ASP.NET app while others are served by the new ASP.NET Core app. Users should only have to sign in once, though. This can be accomplished by either of the following approaches: -* Using the System.Web adapters' [remote authentication](xref:migration/fx-to-core/inc/remote-authentication) feature, which uses the ASP.NET app to sign users in. +* Using the System.Web adapters' [remote authentication](xref:migration/fx-to-core/areas/authentication#remote-authentication) feature, which uses the ASP.NET app to sign users in. * Configuring the ASP.NET app to use Microsoft.Owin Cookie Authentication Middleware so that authentication cookies are shared with the ASP.NET Core app. To configure ASP.NET Microsoft.Owin Cookie Authentication Middleware to share cookies with an ASP.NET Core app, follow the preceding instructions to configure the ASP.NET Core app to use a specific cookie name, app name, and to persist data protection keys to a well-known location. See [Configure ASP.NET Core Data Protection](xref:security/data-protection/configuration/overview) for more information on persisting data protection keys. From aa224b063e584ad4c7d336870750a12977b46d72 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 30 Jun 2025 13:00:04 -0700 Subject: [PATCH 19/61] spread out usage_guidance --- .openpublishing.redirection.json | 2 +- .../areas/claimsprincipal-current.md | 9 ++ .../fx-to-core/areas/http-context.md | 51 ++++++++ aspnetcore/migration/fx-to-core/areas/misc.md | 17 ++- .../migration/fx-to-core/areas/session.md | 16 +++ .../migration/fx-to-core/inc/overview.md | 2 - .../fx-to-core/inc/remote-app-setup.md | 15 ++- .../fx-to-core/inc/systemweb-adapters.md | 16 +++ .../fx-to-core/inc/usage_guidance.md | 112 ------------------ 9 files changed, 116 insertions(+), 124 deletions(-) delete mode 100644 aspnetcore/migration/fx-to-core/inc/usage_guidance.md diff --git a/.openpublishing.redirection.json b/.openpublishing.redirection.json index b31c32c7432c..13e1f7da4355 100644 --- a/.openpublishing.redirection.json +++ b/.openpublishing.redirection.json @@ -1062,7 +1062,7 @@ }, { "source_path": "aspnetcore/migration/inc/usage_guidance.md", - "redirect_url": "/aspnet/core/migration/fx-to-core/inc/usage_guidance", + "redirect_url": "/aspnet/core/migration/fx-to-core/", "redirect_document_id": false }, { diff --git a/aspnetcore/migration/fx-to-core/areas/claimsprincipal-current.md b/aspnetcore/migration/fx-to-core/areas/claimsprincipal-current.md index a6555eb93426..6aec6ab71599 100644 --- a/aspnetcore/migration/fx-to-core/areas/claimsprincipal-current.md +++ b/aspnetcore/migration/fx-to-core/areas/claimsprincipal-current.md @@ -29,3 +29,12 @@ There are several options for retrieving the current authenticated user's `Claim * Retrieve the current user's `ClaimsPrincipal` using `HttpContextAccessor.HttpContext?.User`. If this code is used outside of the context of an HTTP request, the `HttpContext` is null. The final option, using an `IHttpContextAccessor` instance stored in a static variable, is contrary to the ASP.NET Core principle of preferring injected dependencies to static dependencies. Plan to eventually retrieve `IHttpContextAccessor` instances from DI instead. A static helper can be a useful bridge, though, when migrating large existing ASP.NET apps that use `ClaimsPrincipal.Current`. + +## Thread.CurrentPrincipal migration + +> [!WARNING] +> Using `Thread.CurrentPrincipal` should be avoided in ASP.NET Core. This approach is only provided for incremental migration scenarios and has performance implications. + +In ASP.NET Framework, and would be set to the current user. This is not available on ASP.NET Core out of the box. Support for this is available with these adapters by adding the `ISetThreadCurrentPrincipal` to the endpoint (available to controllers via the `SetThreadCurrentPrincipalAttribute`). However, it should only be used if the code cannot be refactored to remove usage. + +**Recommendation**: If possible, use the property or instead by passing it through to the call site. If not possible, enable setting the current user and also consider setting the request to be a logical single thread (see [HttpContext threading considerations](xref:migration/fx-to-core/areas/http-context#request-threading-considerations) for details). diff --git a/aspnetcore/migration/fx-to-core/areas/http-context.md b/aspnetcore/migration/fx-to-core/areas/http-context.md index c4abfd3c8343..7f44365120c3 100644 --- a/aspnetcore/migration/fx-to-core/areas/http-context.md +++ b/aspnetcore/migration/fx-to-core/areas/http-context.md @@ -51,6 +51,57 @@ You have two main options for migrating HttpContext from ASP.NET Framework to AS | **[Complete rewrite](#complete-rewrite-to-aspnet-core-httpcontext)** | High - Rewrite all HttpContext code | Best | Requires updates | Complete rewrites, performance-critical apps | | **[System.Web adapters](#systemweb-adapters)** | Low - Keep existing patterns | Good | Works with existing code | Incremental migrations, extensive HttpContext usage | +## Important differences + +### HttpContext lifetime + +The adapters are backed by which cannot be used past the lifetime of a request. Thus, when run on ASP.NET Core cannot be used past a request as well, while on ASP.NET Framework it would work at times. An will be thrown in cases where it is used past a request end. + +**Recommendation**: Store the values needed into a POCO and hold onto that. + +### Request threading considerations + +> [!WARNING] +> ASP.NET Core does not guarantee thread affinity for requests. If your code requires thread-safe access to `HttpContext`, you must ensure proper synchronization. + +In ASP.NET Framework, a request had thread-affinity and would only be available if on that thread. ASP.NET Core does not have this guarantee so will be available within the same async context, but no guarantees about threads are made. + +**Recommendation**: If reading/writing to the , you must ensure you are doing so in a single-threaded way. You can force a request to never run concurrently on any async context by setting the `ISingleThreadedRequestMetadata`. This will have performance implications and should only be used if you can't refactor usage to ensure non-concurrent access. There is an implementation available to add to controllers with `SingleThreadedRequestAttribute`: + +```csharp +[SingleThreadedRequest] +public class SomeController : Controller +{ + ... +} +``` + +### Request stream buffering + +By default, the incoming request is not always seekable nor fully available. In order to get behavior seen in .NET Framework, you can opt into prebuffering the input stream. This will fully read the incoming stream and buffer it to memory or disk (depending on settings). + +**Recommendation**: This can be enabled by applying endpoint metadata that implements the `IPreBufferRequestStreamMetadata` interface. This is available as an attribute `PreBufferRequestStreamAttribute` that can be applied to controllers or methods. + +To enable this on all MVC endpoints, there is an extension method that can be used as follows: + +```cs +app.MapDefaultControllerRoute() + .PreBufferRequestStream(); +``` + +### Response stream buffering + +Some APIs on require that the output stream is buffered, such as , , , and . + +**Recommendation**: In order to support behavior for that requires buffering the response before sending, endpoints must opt-into it with endpoint metadata implementing `IBufferResponseStreamMetadata`. + +To enable this on all MVC endpoints, there is an extension method that can be used as follows: + +```cs +app.MapDefaultControllerRoute() + .BufferResponseStream(); +``` + ## Complete rewrite to ASP.NET Core HttpContext Choose this approach when you're performing a complete migration and can rewrite HttpContext-related code to use ASP.NET Core's native implementation. diff --git a/aspnetcore/migration/fx-to-core/areas/misc.md b/aspnetcore/migration/fx-to-core/areas/misc.md index 5e92a481ec05..931f60e9bf00 100644 --- a/aspnetcore/migration/fx-to-core/areas/misc.md +++ b/aspnetcore/migration/fx-to-core/areas/misc.md @@ -19,8 +19,23 @@ ASP.NET Core handles URI encoding differently: | `\` | `%5C` | `\` | `/` | | `/` | `%2F` | `%2F` | `/` | -**Solution**: Use `new Uri(this.AspNetCoreHttpRequest.GetEncodedUrl())` for proper URL handling. +**Recommendation**: Use `new Uri(this.AspNetCoreHttpRequest.GetEncodedUrl())` for proper URL handling. ## User Secrets migration User Secrets require special handling. See [GitHub issue #27611](https://github.com/dotnet/AspNetCore.Docs/issues/27611) for current guidance. + +## CultureInfo.CurrentCulture differences + +> [!NOTE] +> ASP.NET Core does not automatically set `CultureInfo.CurrentCulture` for requests like ASP.NET Framework does. You must explicitly configure localization middleware. + +In ASP.NET Framework, was set for a request, but this is not done automatically in ASP.NET Core. Instead, you must add the appropriate middleware to your pipeline. + +**Recommendation**: See [ASP.NET Core Localization](/aspnet/core/fundamentals/localization#localization-middleware) for details on how to enable this. + +Simplest way to enable this with similar behavior as ASP.NET Framework would be to add the following to your pipeline: + +```csharp +app.UseRequestLocalization(); +``` diff --git a/aspnetcore/migration/fx-to-core/areas/session.md b/aspnetcore/migration/fx-to-core/areas/session.md index fbbd32d0bc5f..528d42452435 100644 --- a/aspnetcore/migration/fx-to-core/areas/session.md +++ b/aspnetcore/migration/fx-to-core/areas/session.md @@ -72,6 +72,22 @@ The [System.Web adapters](~/migration/fx-to-core/inc/systemweb-adapters.md) enab * `Microsoft.AspNetCore.SystemWebAdapters.ISessionManager`: Accepts an and session metadata, returns an `ISessionState` object * `Microsoft.AspNetCore.SystemWebAdapters.ISessionState`: Describes session object state and backs the type +### Shared session state requirements + +> [!NOTE] +> To use session state with System.Web adapters, endpoints must explicitly opt-in via metadata implementing `ISessionMetadata`. + +In order to support , endpoints must opt-into it via metadata implementing `ISessionMetadata`. + +**Recommendation**: To enable this on all MVC endpoints, there is an extension method that can be used as follows: + +```cs +app.MapDefaultControllerRoute() + .RequireSystemWebAdapterSession(); +``` + +This also requires some implementation of a session store. For details of options here, see the sections below on different session approaches. + ## Built-in ASP.NET Core session state Choose this approach when you're performing a complete migration and can rewrite session-related code to use ASP.NET Core's native session implementation. diff --git a/aspnetcore/migration/fx-to-core/inc/overview.md b/aspnetcore/migration/fx-to-core/inc/overview.md index e20a83e27376..838c08f72682 100644 --- a/aspnetcore/migration/fx-to-core/inc/overview.md +++ b/aspnetcore/migration/fx-to-core/inc/overview.md @@ -70,8 +70,6 @@ The `Microsoft.AspNetCore.SystemWebAdapters` namespace is a collection of runtim For examples of scenarios where this is useful, see [the adapters article](xref:migration/fx-to-core/systemweb-adapters). -For guidance around usage, see the [usage guidance article](xref:migration/fx-to-core/inc/usage_guidance). - ## Additional Resources * [Example migration of eShop to ASP.NET Core](/dotnet/architecture/porting-existing-aspnet-apps/example-migration-eshop) diff --git a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md index 14bbbd92e9dc..cd91b562f903 100644 --- a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md +++ b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md @@ -17,6 +17,13 @@ Specifically, this capability is used, currently, for [remote app authentication ## Configuration +> [!IMPORTANT] +> Framework and Core applications must use identical virtual directory layouts. +> +> The virtual directory setup is used for route generation, authorization, and other services within the system. At this point, no reliable method has been found to enable different virtual directories due to how ASP.NET Framework works. + +**Recommendation**: Ensure your two applications are on different sites (hosts and/or ports) with the same application/virtual directory layout. + To enable the ASP.NET Core app to communicate with the ASP.NET app, it's necessary to make a couple small changes to each app. You need to configure two configuration values in both applications: @@ -98,11 +105,3 @@ builder.Services.AddSystemWebAdapters() ``` With both the ASP.NET and ASP.NET Core app updated, extension methods can now be used to set up [remote app authentication](xref:migration/fx-to-core/areas/authentication#remote-authenticationn) or [remote session](xref:migration/fx-to-core/areas/session#remote-app-session-state), as needed. - -## Securing the remote app connection - -Because remote app features involve serving requests on new endpoints from the ASP.NET app, it's important that communication to and from the ASP.NET app be secure. - -First, make sure that the API key string used to authenticate the ASP.NET Core app with the ASP.NET app is unique and kept secret. It is a best practice to not store the API key in source control. Instead, load it at runtime from a secure source such as Azure Key Vault or other secure runtime configuration. In order to encourage secure API keys, remote app connections require that the keys be non-empty GUIDs (128-bit hex numbers). - -Second, because it's important for the ASP.NET Core app to be able to trust that it is requesting information from the correct ASP.NET app, the ASP.NET app should use HTTPS in any production scenarios so that the ASP.NET Core app can know responses are being served by a trusted source. diff --git a/aspnetcore/migration/fx-to-core/inc/systemweb-adapters.md b/aspnetcore/migration/fx-to-core/inc/systemweb-adapters.md index 556cf1e37dd2..86d5bd76a1f7 100644 --- a/aspnetcore/migration/fx-to-core/inc/systemweb-adapters.md +++ b/aspnetcore/migration/fx-to-core/inc/systemweb-adapters.md @@ -24,6 +24,22 @@ Let's take a look at an example using the adapters moving from .NET Framework to * `Microsoft.AspNetCore.SystemWebAdapters.CoreServices`: This package only targets .NET 6+ and is intended to provide services to ASP.NET Core applications to configure behavior of `System.Web` APIs as well as opting into any behaviors for incremental migration. This is generally not expected to be referenced from libraries, but rather from the applications themselves. * `Microsoft.AspNetCore.SystemWebAdapters.Abstractions`: This package is a supporting package that provides abstractions for services used by both the ASP.NET Core and ASP.NET Framework application such as session state serialization. +### Converting to System.Web.HttpContext + +To convert between the two representations of HttpContext, you may do the following: + +For to : + +* Implicit casting +* `HttpContext.AsSystemWeb()` + +For to + +* Implicit casting +* `HttpContext.AsAspNetCore()` + +Both of these methods will use a cached representation for the duration of a request. This allows for targeted rewrites to as needed. + ## Example ### ASP.NET Framework diff --git a/aspnetcore/migration/fx-to-core/inc/usage_guidance.md b/aspnetcore/migration/fx-to-core/inc/usage_guidance.md deleted file mode 100644 index 7e44deaf97aa..000000000000 --- a/aspnetcore/migration/fx-to-core/inc/usage_guidance.md +++ /dev/null @@ -1,112 +0,0 @@ ---- -title: Incremental ASP.NET to ASP.NET Core Migration Usage Guidance -description: Incremental ASP.NET to ASP.NET Core Migration Usage Guidance -author: rick-anderson -ms.author: riande -monikerRange: '>= aspnetcore-6.0' -ms.date: 11/9/2022 -ms.topic: article -uid: migration/fx-to-core/inc/usage_guidance ---- - -# Usage Guidance - -`Microsoft.AspNetCore.SystemWebAdapters` provides an emulation layer to mimic behavior from ASP.NET framework on ASP.NET Core. Below are some guidelines for some of the considerations when using them: - -## `HttpContext` lifetime - -The adapters are backed by which cannot be used past the lifetime of a request. Thus, when run on ASP.NET Core cannot be used past a request as well, while on ASP.NET Framework it would work at times. An will be thrown in cases where it is used past a request end. - -**Recommendation**: Store the values needed into a POCO and hold onto that. - -## Conversion to - -There are two ways to convert an to a : - -* Implicit casting -* Constructor usage - -**Recommendation**: For the most cases, implicit casting should be preferred as this will cache the created instance and ensure only a single per request. - -## is not set by default - -In ASP.NET Framework, was set for a request, but this is not done automatically in ASP.NET Core. Instead, you must add the appropriate middleware to your pipeline. - -**Recommendation**: See [ASP.NET Core Localization](/aspnet/core/fundamentals/localization#localization-middleware) for details on how to enable this. - -Simplest way to enable this with similar behavior as ASP.NET Framework would be to add the following to your pipeline: - -```csharp -app.UseRequestLocalization(); -``` - -## - -In ASP.NET Framework, and would be set to the current user. This is not available on ASP.NET Core out of the box. Support for this is available with these adapters by adding the `ISetThreadCurrentPrincipal` to the endpoint (available to controllers via the `SetThreadCurrentPrincipalAttribute`). However, it should only be used if the code cannot be refactored to remove usage. - -**Recommendation**: If possible, use the property or instead by passing it through to the call site. If not possible, enable setting the current user and also consider setting the request to be a logical single thread (see below for details). - -## Request thread does not exist in ASP.NET Core - -In ASP.NET Framework, a request had thread-affinity and would only be available if on that thread. ASP.NET Core does not have this guarantee so will be available within the same async context, but no guarantees about threads are made. - -**Recommendation**: If reading/writing to the , you must ensure you are doing so in a single-threaded way. You can force a request to never run concurrently on any async context by setting the `ISingleThreadedRequestMetadata`. This will have performance implications and should only be used if you can't refactor usage to ensure non-concurrent access. There is an implementation available to add to controllers with `SingleThreadedRequestAttribute`: - -```csharp -[SingleThreadedRequest] -public class SomeController : Controller -{ - ... -} -``` - -## may need to be prebuffered - -By default, the incoming request is not always seekable nor fully available. In order to get behavior seen in .NET Framework, you can opt into prebuffering the input stream. This will fully read the incoming stream and buffer it to memory or disk (depending on settings). - -**Recommendation**: This can be enabled by applying endpoint metadata that implements the `IPreBufferRequestStreamMetadata` interface. This is available as an attribute `PreBufferRequestStreamAttribute` that can be applied to controllers or methods. - -To enable this on all MVC endpoints, there is an extension method that can be used as follows: - -```cs -app.MapDefaultControllerRoute() - .PreBufferRequestStream(); -``` - -## may require buffering - -Some APIs on require that the output stream is buffered, such as , , , and . - -**Recommendation**: In order to support behavior for that requires buffering the response before sending, endpoints must opt-into it with endpoint metadata implementing `IBufferResponseStreamMetadata`. - -To enable this on all MVC endpoints, there is an extension method that can be used as follows: - -```cs -app.MapDefaultControllerRoute() - .BufferResponseStream(); -``` - -## Shared session state - -In order to support , endpoints must opt-into it via metadata implementing `ISessionMetadata`. - -**Recommendation**: To enable this on all MVC endpoints, there is an extension method that can be used as follows: - -```cs -app.MapDefaultControllerRoute() - .RequireSystemWebAdapterSession(); -``` - -This also requires some implementation of a session store. For details of options here, see [migration guidance for session](xref:migration/fx-to-core/areas/session). - -## Remote session exposes additional endpoint for application - -The [remote session support](xref:migration/fx-to-core/areas/session#remote-app-session-state) exposes an endpoint that allows the core app to retrieve session information. This may cause a potentially long-lived request to exist between the core app and the framework app, but will time out with the current request or the session timeout (by default is 20 minutes). - -**Recommendation**: Ensure the API key used is a strong one and that the connection with the framework app is done over SSL. - -## Virtual directories must be identical for framework and core applications - -The virtual directory setup is used for route generation, authorization, and other services within the system. At this point, no reliable method has been found to enable different virtual directories due to how ASP.NET Framework works. - -**Recommendation**: Ensure your two applications are on different sites (hosts and/or ports) with the same application/virtual directory layout. From e5c5fa90266254c229c090caa4d42ee78025ff38 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 30 Jun 2025 13:47:04 -0700 Subject: [PATCH 20/61] clean up errors --- .openpublishing.redirection.json | 5 ----- aspnetcore/migration/fx-to-core/areas/http-context.md | 4 ++-- aspnetcore/migration/fx-to-core/inc/start.md | 4 +--- aspnetcore/toc.yml | 2 -- 4 files changed, 3 insertions(+), 12 deletions(-) diff --git a/.openpublishing.redirection.json b/.openpublishing.redirection.json index 13e1f7da4355..87b1275e9ef9 100644 --- a/.openpublishing.redirection.json +++ b/.openpublishing.redirection.json @@ -1055,11 +1055,6 @@ "redirect_url": "/aspnet/core/migration/fx-to-core/inc/start", "redirect_document_id": false }, - { - "source_path": "aspnetcore/migration/inc/unit-testing.md", - "redirect_url": "/aspnet/core/migration/fx-to-core/inc/unit-testing", - "redirect_document_id": false - }, { "source_path": "aspnetcore/migration/inc/usage_guidance.md", "redirect_url": "/aspnet/core/migration/fx-to-core/", diff --git a/aspnetcore/migration/fx-to-core/areas/http-context.md b/aspnetcore/migration/fx-to-core/areas/http-context.md index 7f44365120c3..496f84c077fc 100644 --- a/aspnetcore/migration/fx-to-core/areas/http-context.md +++ b/aspnetcore/migration/fx-to-core/areas/http-context.md @@ -164,7 +164,7 @@ This section shows how to translate the most commonly used properties of ** → **** +* **** → **** [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Route)] @@ -210,7 +210,7 @@ This section shows how to translate the most commonly used properties of ** → **** +* **** → **** [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Output)] diff --git a/aspnetcore/migration/fx-to-core/inc/start.md b/aspnetcore/migration/fx-to-core/inc/start.md index 34f067cb425e..7b4bdd643b46 100644 --- a/aspnetcore/migration/fx-to-core/inc/start.md +++ b/aspnetcore/migration/fx-to-core/inc/start.md @@ -150,7 +150,7 @@ Depending on your application, you may also need to address: If you have supporting libraries in your solution that you will need to use for the routes you're migrating, they should be upgraded to .NET Standard 2.0, if possible. [Upgrade Assistant](https://github.com/dotnet/upgrade-assistant) is a great tool for this. If libraries are unable to target .NET Standard, you can target .NET 8 or later either along with the .NET Framework target in the original project or in a new project alongside the original. -The [System.Web adapters](xref:migration/fx-to-core/inc/usage_guidance) can be used in these libraries to enable support for usage in class libraries. In order to enable usage in a library: +The [System.Web adapters](xref:migration/fx-to-core/inc/systemweb-adapters) can be used in these libraries to enable support for usage in class libraries. In order to enable usage in a library: 1. Remove reference to `System.Web` in the project file 2. Add the `Microsoft.AspNetCore.SystemWebAdapters` package @@ -168,5 +168,3 @@ Once you've completed the setup and library upgrade steps above: 2. **Test thoroughly**: Ensure each migrated component works correctly in both environments 3. **Monitor performance**: Watch for any performance impacts from the proxy setup 4. **Iterate**: Continue migrating components incrementally until the migration is complete - -For ongoing support and advanced scenarios, refer to the [usage guidance](xref:migration/fx-to-core/inc/usage_guidance) documentation. diff --git a/aspnetcore/toc.yml b/aspnetcore/toc.yml index f614f507c743..fe5996680a7c 100644 --- a/aspnetcore/toc.yml +++ b/aspnetcore/toc.yml @@ -2109,8 +2109,6 @@ items: uid: migration/fx-to-core/systemweb-adapters - name: Remote app setup uid: migration/fx-to-core/inc/remote-app-setup - - name: Usage Guidance - uid: migration/fx-to-core/inc/usage_guidance - name: A/B Testing endpoints uid: migration/fx-to-core/inc/ab-testing - name: Blazor support with YARP From 9bed76048cb02c288202cb4b89d35df23cf2711f Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 30 Jun 2025 13:56:39 -0700 Subject: [PATCH 21/61] update --- .openpublishing.redirection.json | 10 ++++++++++ aspnetcore/migration/fx-to-core/inc/start.md | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.openpublishing.redirection.json b/.openpublishing.redirection.json index 87b1275e9ef9..ec99d8c26dd1 100644 --- a/.openpublishing.redirection.json +++ b/.openpublishing.redirection.json @@ -1015,6 +1015,11 @@ "redirect_url": "/aspnet/core/migration/fx-to-core/systemweb-adapters", "redirect_document_id": false }, + { + "source_path": "aspnetcore/migration/fx-to-core/inc/unit-testing.md", + "redirect_url": "/aspnet/core/migration/fx-to-core/systemweb-adapters", + "redirect_document_id": false + }, { "source_path": "aspnetcore/migration/inc/blazor.md", "redirect_url": "/aspnet/core/migration/fx-to-core/inc/blazor", @@ -1060,6 +1065,11 @@ "redirect_url": "/aspnet/core/migration/fx-to-core/", "redirect_document_id": false }, + { + "source_path": "aspnetcore/migration/fx-to-core/inc/usage_guidance.md", + "redirect_url": "/aspnet/core/migration/fx-to-core/", + "redirect_document_id": false + }, { "source_path": "aspnetcore/migration/inc/wrapped.md", "redirect_url": "/aspnet/core/migration/fx-to-core/inc/wrapped", diff --git a/aspnetcore/migration/fx-to-core/inc/start.md b/aspnetcore/migration/fx-to-core/inc/start.md index 7b4bdd643b46..d729dd2b0737 100644 --- a/aspnetcore/migration/fx-to-core/inc/start.md +++ b/aspnetcore/migration/fx-to-core/inc/start.md @@ -150,7 +150,7 @@ Depending on your application, you may also need to address: If you have supporting libraries in your solution that you will need to use for the routes you're migrating, they should be upgraded to .NET Standard 2.0, if possible. [Upgrade Assistant](https://github.com/dotnet/upgrade-assistant) is a great tool for this. If libraries are unable to target .NET Standard, you can target .NET 8 or later either along with the .NET Framework target in the original project or in a new project alongside the original. -The [System.Web adapters](xref:migration/fx-to-core/inc/systemweb-adapters) can be used in these libraries to enable support for usage in class libraries. In order to enable usage in a library: +The [System.Web adapters](~/migration/fx-to-core/inc/systemweb-adapters.md) can be used in these libraries to enable support for usage in class libraries. In order to enable usage in a library: 1. Remove reference to `System.Web` in the project file 2. Add the `Microsoft.AspNetCore.SystemWebAdapters` package From 6f48d2bdab8726cf601ef288dc614d615161c656 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 30 Jun 2025 13:59:58 -0700 Subject: [PATCH 22/61] toc --- .../fx-to-core/inc/remote-app-setup.md | 48 ++++++++++--------- aspnetcore/toc.yml | 4 +- 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md index cd91b562f903..f604617f68c2 100644 --- a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md +++ b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md @@ -13,7 +13,11 @@ uid: migration/fx-to-core/inc/remote-app-setup In some incremental upgrade scenarios, it's useful for the new ASP.NET Core app to be able to communicate with the original ASP.NET app. -Specifically, this capability is used, currently, for [remote app authentication](xref:migration/fx-to-core/areas/authentication#remote-authenticationn) and [remote session](xref:migration/fx-to-core/areas/session#remote-app-session-state) features. +Common scenarios this enables: + +* Fallback to the legacy application with YARP +* [Remote app authentication](xref:migration/fx-to-core/areas/authentication#remote-authenticationn) +* [Remote session](xref:migration/fx-to-core/areas/session#remote-app-session-state) features. ## Configuration @@ -22,8 +26,6 @@ Specifically, this capability is used, currently, for [remote app authentication > > The virtual directory setup is used for route generation, authorization, and other services within the system. At this point, no reliable method has been found to enable different virtual directories due to how ASP.NET Framework works. -**Recommendation**: Ensure your two applications are on different sites (hosts and/or ports) with the same application/virtual directory layout. - To enable the ASP.NET Core app to communicate with the ASP.NET app, it's necessary to make a couple small changes to each app. You need to configure two configuration values in both applications: @@ -56,28 +58,28 @@ To set up the ASP.NET app to be able to receive requests from the ASP.NET Core a 1. Install the NuGet package [`Microsoft.AspNetCore.SystemWebAdapters.FrameworkServices`](https://www.nuget.org/packages/Microsoft.AspNetCore.SystemWebAdapters) -2. Add the configuration code to the `Application_Start` method in your `Global.asax.cs` file: +1. Add the configuration code to the `Application_Start` method in your `Global.asax.cs` file: -```CSharp -protected void Application_Start() -{ - SystemWebAdapterConfiguration.AddSystemWebAdapters(this) - .AddRemoteAppServer(options => - { - // ApiKey is a string representing a GUID - options.ApiKey = ConfigurationManager.AppSettings["RemoteAppApiKey"]; - }); + ```CSharp + protected void Application_Start() + { + SystemWebAdapterConfiguration.AddSystemWebAdapters(this) + .AddRemoteAppServer(options => + { + // ApiKey is a string representing a GUID + options.ApiKey = ConfigurationManager.AppSettings["RemoteAppApiKey"]; + }); + + // ...existing code... + } + ``` + + In the options configuration method passed to the `AddRemoteAppServer` call, an API key must be specified. The API key is: + + * Used to secure the endpoint so that only trusted callers can make requests to it. + * The same API key provided to the ASP.NET Core app when it is configured. + * A string and must be parsable as a [GUID](/dotnet/api/system.guid). Hyphens in the key are optional. - // ...existing code... -} -``` - -In the options configuration method passed to the `AddRemoteAppServer` call, an API key must be specified. The API key is: - -* Used to secure the endpoint so that only trusted callers can make requests to it. -* The same API key provided to the ASP.NET Core app when it is configured. -* A string and must be parsable as a [GUID](/dotnet/api/system.guid). Hyphens in the key are optional. - 1. Add the `SystemWebAdapterModule` module to the `web.config` if it wasn't already added by NuGet. This module configuration is required for IIS hosting scenarios. The `SystemWebAdapterModule` module is not added automatically when using SDK style projects for ASP.NET Core. ```diff diff --git a/aspnetcore/toc.yml b/aspnetcore/toc.yml index fe5996680a7c..134250c850db 100644 --- a/aspnetcore/toc.yml +++ b/aspnetcore/toc.yml @@ -2103,10 +2103,10 @@ items: items: - name: Overview uid: migration/fx-to-core/inc/overview - - name: Get started - uid: migration/fx-to-core/inc/start - name: System.Web adapters uid: migration/fx-to-core/systemweb-adapters + - name: Get started + uid: migration/fx-to-core/inc/start - name: Remote app setup uid: migration/fx-to-core/inc/remote-app-setup - name: A/B Testing endpoints From 45bf6b1a0fd42c75eb638001745eaaab26b75c1f Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 30 Jun 2025 14:00:41 -0700 Subject: [PATCH 23/61] toc --- aspnetcore/toc.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/aspnetcore/toc.yml b/aspnetcore/toc.yml index 134250c850db..029579a9789d 100644 --- a/aspnetcore/toc.yml +++ b/aspnetcore/toc.yml @@ -2098,6 +2098,8 @@ items: items: - name: Overview uid: migration/fx-to-core/index + - name: Tooling + uid: migration/fx-to-core/tooling - name: Incremental migration displayName: migrate, migration items: @@ -2113,16 +2115,6 @@ items: uid: migration/fx-to-core/inc/ab-testing - name: Blazor support with YARP uid: migration/fx-to-core/inc/blazor - - name: Tooling - uid: migration/fx-to-core/tooling - - name: Example Migration - items: - - name: Overview - uid: migration/fx-to-core/examples/overview - - name: Configuration - uid: migration/fx-to-core/examples/configuration - - name: Identity - uid: migration/fx-to-core/examples/identity - name: Technology Areas items: - name: Overview @@ -2143,6 +2135,14 @@ items: uid: migration/fx-to-core/areas/webapi - name: ClaimsPrincipal.Current uid: migration/fx-to-core/areas/claimsprincipal-current + - name: Example Migration + items: + - name: Overview + uid: migration/fx-to-core/examples/overview + - name: Configuration + uid: migration/fx-to-core/examples/configuration + - name: Identity + uid: migration/fx-to-core/examples/identity - name: API reference href: /dotnet/api/ - name: Contribute From 7f812ff8d1fcebb21b6bd451e3b10c279f57bd00 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 30 Jun 2025 14:22:57 -0700 Subject: [PATCH 24/61] claimsprincipal --- .../areas/claimsprincipal-current.md | 230 +++++++++++++++++- aspnetcore/migration/fx-to-core/areas/misc.md | 18 ++ 2 files changed, 236 insertions(+), 12 deletions(-) diff --git a/aspnetcore/migration/fx-to-core/areas/claimsprincipal-current.md b/aspnetcore/migration/fx-to-core/areas/claimsprincipal-current.md index 6aec6ab71599..525984f95c71 100644 --- a/aspnetcore/migration/fx-to-core/areas/claimsprincipal-current.md +++ b/aspnetcore/migration/fx-to-core/areas/claimsprincipal-current.md @@ -4,20 +4,73 @@ author: mjrousos description: Learn how to migrate away from ClaimsPrincipal.Current to retrieve the current authenticated user's identity and claims in ASP.NET Core. ms.author: wpickett ms.custom: mvc -ms.date: 03/26/2019 +ms.date: 06/30/2025 uid: migration/fx-to-core/areas/claimsprincipal-current --- # Migrate from ClaimsPrincipal.Current -In ASP.NET 4.x projects, it was common to use to retrieve the current authenticated user's identity and claims. In ASP.NET Core, this property is no longer set. Code that was depending on it needs to be updated to get the current authenticated user's identity through a different means. +The current ClaimsPrincipal is a fundamental component of authenticated web applications, providing access to the current user's identity and claims. When migrating from ASP.NET Framework to ASP.NET Core, accessing this presents unique challenges because the two frameworks have different approaches to user context management. -## Context-specific state instead of static state +## Why ClaimsPrincipal migration is complex -When using ASP.NET Core, the values of both `ClaimsPrincipal.Current` and `Thread.CurrentPrincipal` aren't set. These properties both represent static state, which ASP.NET Core generally avoids. Instead, ASP.NET Core uses [dependency injection](xref:fundamentals/dependency-injection) (DI) to provide dependencies such as the current user's identity. Getting the current user's identity from DI is more testable, too, since test identities can be easily injected. +ASP.NET Framework and ASP.NET Core have fundamentally different approaches to accessing the current user: -## Retrieve the current user in an ASP.NET Core app +* **ASP.NET Framework** uses static properties like and with automatic context management. These properties are interchangeable and both provide access to the current user's identity. +* **ASP.NET Core** stores the current user in and avoids static state. -There are several options for retrieving the current authenticated user's `ClaimsPrincipal` in ASP.NET Core in place of `ClaimsPrincipal.Current`: +These differences mean you can't simply continue using static principal properties ( or ) in ASP.NET Core without changes. By default, the static properties aren't set, and code depending on them needs to be updated to get the current authenticated user's identity through different means. + +## Migration strategies overview + +You have two main approaches for handling static principal access during migration: + +1. **Complete rewrite** - Rewrite all static principal access code to use ASP.NET Core's native patterns +2. **System.Web adapters** - Use adapters to enable static access patterns during incremental migration + +For most applications, migrating to ASP.NET Core's native ClaimsPrincipal access provides the best performance and maintainability. However, larger applications or those with extensive static principal usage may benefit from using System.Web adapters during incremental migration. + +## Choose your migration approach + +You have two main options for migrating static principal access from ASP.NET Framework to ASP.NET Core. Your choice depends on your migration timeline, whether you need to run both applications simultaneously, and how much code you're willing to rewrite. + +### Quick decision guide + +**Answer these questions to choose your approach:** + +1. **Are you doing a complete rewrite or incremental migration?** + * Complete rewrite → [Complete rewrite to ASP.NET Core patterns](#complete-rewrite-to-aspnet-core-patterns) + * Incremental migration → Continue to question 2 + +2. **Do you have extensive static principal usage ( or ) across shared libraries?** + * Yes, lots of shared code → [System.Web adapters](#systemweb-adapters) + * No, isolated static principal usage → [Complete rewrite to ASP.NET Core patterns](#complete-rewrite-to-aspnet-core-patterns) + +### Migration approaches comparison + +| Approach | Code Changes | Performance | Shared Libraries | When to Use | +|----------|-------------|-------------|------------------|-------------| +| **[Complete rewrite](#complete-rewrite-to-aspnet-core-patterns)** | High - Rewrite all static principal access | Best | Requires updates | Complete rewrites, performance-critical apps | +| **[System.Web adapters](#systemweb-adapters)** | Low - Keep existing patterns | Good | Works with existing code | Incremental migrations, extensive static access | + +## Complete rewrite to ASP.NET Core patterns + +Choose this approach when you're performing a complete migration or want the best performance and maintainability. + +ASP.NET Core provides several options for retrieving the current authenticated user's `ClaimsPrincipal` without relying on static properties. This approach requires rewriting static principal access code but offers the most benefits in the long term. + +### Complete rewrite pros and cons + +| Pros | Cons | +|------|------| +| Best performance | Requires rewriting all static principal access code | +| More testable (dependency injection) | No automatic migration path | +| No static dependencies | Learning curve for new patterns | +| Native ASP.NET Core implementation | Breaking change from Framework patterns | +| Thread-safe by design | Potential refactoring across shared libraries | + +### ASP.NET Core ClaimsPrincipal access patterns + +There are several options for retrieving the current authenticated user's `ClaimsPrincipal` in ASP.NET Core in place of : * **ControllerBase.User**. MVC controllers can access the current authenticated user with their property. * **HttpContext.User**. Components with access to the current `HttpContext` (middleware, for example) can get the current user's `ClaimsPrincipal` from . @@ -28,13 +81,166 @@ There are several options for retrieving the current authenticated user's `Claim * Get an instance of `IHttpContextAccessor` during startup and store it in a static variable. The instance is made available to code that was previously retrieving the current user from a static property. * Retrieve the current user's `ClaimsPrincipal` using `HttpContextAccessor.HttpContext?.User`. If this code is used outside of the context of an HTTP request, the `HttpContext` is null. -The final option, using an `IHttpContextAccessor` instance stored in a static variable, is contrary to the ASP.NET Core principle of preferring injected dependencies to static dependencies. Plan to eventually retrieve `IHttpContextAccessor` instances from DI instead. A static helper can be a useful bridge, though, when migrating large existing ASP.NET apps that use `ClaimsPrincipal.Current`. +The final option, using an `IHttpContextAccessor` instance stored in a static variable, is contrary to the ASP.NET Core principle of preferring injected dependencies to static dependencies. Plan to eventually retrieve `IHttpContextAccessor` instances from DI instead. A static helper can be a useful bridge, though, when migrating large existing ASP.NET apps that use . + +### Code examples + +Here are examples of migrating common static principal usage patterns: + +**ASP.NET Framework (before):** +```csharp +public class UserService +{ + public string GetCurrentUserId() + { + // Both ClaimsPrincipal.Current and Thread.CurrentPrincipal work interchangeably + return ClaimsPrincipal.Current?.FindFirst(ClaimTypes.NameIdentifier)?.Value; + // or: return Thread.CurrentPrincipal?.Identity?.Name; + } +} +``` + +**ASP.NET Core (after) - Dependency Injection:** +```csharp +public class UserService +{ + private readonly IHttpContextAccessor _httpContextAccessor; + + public UserService(IHttpContextAccessor httpContextAccessor) + { + _httpContextAccessor = httpContextAccessor; + } + + public string GetCurrentUserId() + { + return _httpContextAccessor.HttpContext?.User?.FindFirst(ClaimTypes.NameIdentifier)?.Value; + } +} +``` + +**ASP.NET Core (after) - Pass ClaimsPrincipal as parameter:** +```csharp +public class UserService +{ + public string GetCurrentUserId(ClaimsPrincipal user) + { + return user?.FindFirst(ClaimTypes.NameIdentifier)?.Value; + } +} + +// Usage in controller +public class HomeController : Controller +{ + private readonly UserService _userService; + + public HomeController(UserService userService) + { + _userService = userService; + } + + public IActionResult Index() + { + var userId = _userService.GetCurrentUserId(User); + return View(); + } +} +``` + +### When to choose this approach + +* You can afford to rewrite static principal access code +* Performance is a top priority (in this case, prefer the passing as a parameter option) +* You want to eliminate static dependencies +* You're not sharing code with legacy applications +* You want the most testable and maintainable solution + +## System.Web adapters + +[!INCLUDE[](~/migration/fx-to-core/includes/uses-systemweb-adapters.md)] + +Choose this approach when you need to maintain existing static principal usage patterns during incremental migration, or when you have extensive shared libraries that would be difficult to update. + +The System.Web adapters can enable both and support in ASP.NET Core, allowing you to keep existing code patterns while migrating incrementally. Both properties work interchangeably once adapters are configured. + +### System.Web adapters pros and cons + +| Pros | Cons | +|------|------| +| Minimal code changes required | Performance overhead | +| Works with existing shared libraries | Not thread-safe in all scenarios | +| Enables incremental migration | Requires System.Web adapters dependency | +| Maintains familiar patterns | Should be temporary solution | +| Good for large codebases | Less testable than DI patterns | + +### Setting up static principal support + +To enable static principal support ( and ) with System.Web adapters, endpoints must be annotated with the `SetThreadCurrentPrincipalAttribute` metadata: + +```csharp +// Add to controller or action +[SetThreadCurrentPrincipal] +public class HomeController : Controller +{ + public IActionResult Index() + { + // Both ClaimsPrincipal.Current and Thread.CurrentPrincipal are now available + var user1 = ClaimsPrincipal.Current; + var user2 = Thread.CurrentPrincipal; + return View(); + } +} +``` + +### When to use System.Web adapters + +* You have extensive static principal usage across shared libraries +* You're doing an incremental migration +* You can't afford to rewrite all static principal access code immediately +* You need to maintain compatibility with existing ASP.NET Framework code +* You understand the performance and threading implications + +## Migration considerations + +### Performance implications + +* **Native ASP.NET Core patterns** provide the best performance with no overhead +* **System.Web adapters** introduce some performance overhead but enable gradual migration +* **Static variables** should be avoided as they can cause memory leaks and threading issues + +### Testing considerations + +* **Dependency injection approach** is most testable - you can easily inject mock `IHttpContextAccessor` or pass test `ClaimsPrincipal` objects +* **Static access patterns** are harder to test and may require additional setup in unit tests + +### Security considerations + +* Ensure that `ClaimsPrincipal` access is properly validated in all scenarios +* Be aware of potential null reference exceptions when `HttpContext` is not available +* Consider the security implications of storing user context in static variables + +## Common issues and solutions + +### Issue: Static principal properties are null + +**Problem**: Code that previously worked with static principal properties ( or ) now returns null. + +**Solution**: +* For complete rewrite: Use `HttpContext.User` or inject `IHttpContextAccessor` +* For incremental migration: Enable System.Web adapters with proper configuration + +### Issue: Thread.CurrentPrincipal not working + +**Problem**: is not set in ASP.NET Core. -## Thread.CurrentPrincipal migration +**Solution**: +* Preferred: Refactor to use `HttpContext.User` or dependency injection +* Temporary: Use `SetThreadCurrentPrincipalAttribute` with System.Web adapters -> [!WARNING] -> Using `Thread.CurrentPrincipal` should be avoided in ASP.NET Core. This approach is only provided for incremental migration scenarios and has performance implications. +### Issue: Null reference exceptions -In ASP.NET Framework, and would be set to the current user. This is not available on ASP.NET Core out of the box. Support for this is available with these adapters by adding the `ISetThreadCurrentPrincipal` to the endpoint (available to controllers via the `SetThreadCurrentPrincipalAttribute`). However, it should only be used if the code cannot be refactored to remove usage. +**Problem**: `HttpContext` may be null in certain scenarios (background tasks, etc.). -**Recommendation**: If possible, use the property or instead by passing it through to the call site. If not possible, enable setting the current user and also consider setting the request to be a logical single thread (see [HttpContext threading considerations](xref:migration/fx-to-core/areas/http-context#request-threading-considerations) for details). +**Solution**: Always check for null before accessing user properties: +```csharp +var userId = _httpContextAccessor.HttpContext?.User?.FindFirst(ClaimTypes.NameIdentifier)?.Value; +``` diff --git a/aspnetcore/migration/fx-to-core/areas/misc.md b/aspnetcore/migration/fx-to-core/areas/misc.md index 931f60e9bf00..248d33a8b501 100644 --- a/aspnetcore/migration/fx-to-core/areas/misc.md +++ b/aspnetcore/migration/fx-to-core/areas/misc.md @@ -39,3 +39,21 @@ Simplest way to enable this with similar behavior as ASP.NET Framework would be ```csharp app.UseRequestLocalization(); ``` + +### Threading considerations + +[!INCLUDE[](~/migration/fx-to-core/includes/uses-systemweb-adapters.md)] + +ASP.NET Core does not guarantee thread affinity for requests. If your code requires thread affinity, you must ensure proper synchronization or use the `SingleThreadedRequest` attribute: + +```csharp +[SingleThreadedRequest] +public class LegacyController : Controller +{ + public IActionResult Index() + { + // Some code that requires to be run on a single thread + return View(); + } +} +``` From 9cefae4a531511afa002731a7a1354a502414be9 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 30 Jun 2025 14:26:16 -0700 Subject: [PATCH 25/61] xref --- .../areas/claimsprincipal-current.md | 94 +++++-------------- 1 file changed, 25 insertions(+), 69 deletions(-) diff --git a/aspnetcore/migration/fx-to-core/areas/claimsprincipal-current.md b/aspnetcore/migration/fx-to-core/areas/claimsprincipal-current.md index 525984f95c71..2670feacdfe2 100644 --- a/aspnetcore/migration/fx-to-core/areas/claimsprincipal-current.md +++ b/aspnetcore/migration/fx-to-core/areas/claimsprincipal-current.md @@ -56,7 +56,7 @@ You have two main options for migrating static principal access from ASP.NET Fra Choose this approach when you're performing a complete migration or want the best performance and maintainability. -ASP.NET Core provides several options for retrieving the current authenticated user's `ClaimsPrincipal` without relying on static properties. This approach requires rewriting static principal access code but offers the most benefits in the long term. +ASP.NET Core provides several options for retrieving the current authenticated user's without relying on static properties. This approach requires rewriting static principal access code but offers the most benefits in the long term. ### Complete rewrite pros and cons @@ -70,18 +70,12 @@ ASP.NET Core provides several options for retrieving the current authenticated u ### ASP.NET Core ClaimsPrincipal access patterns -There are several options for retrieving the current authenticated user's `ClaimsPrincipal` in ASP.NET Core in place of : +There are several options for retrieving the current authenticated user's in ASP.NET Core in place of : -* **ControllerBase.User**. MVC controllers can access the current authenticated user with their property. -* **HttpContext.User**. Components with access to the current `HttpContext` (middleware, for example) can get the current user's `ClaimsPrincipal` from . -* **Passed in from caller**. Libraries without access to the current `HttpContext` are often called from controllers or middleware components and can have the current user's identity passed as an argument. -* **IHttpContextAccessor**. The project being migrated to ASP.NET Core may be too large to easily pass the current user's identity to all necessary locations. In such cases, can be used as a workaround. `IHttpContextAccessor` is able to access the current `HttpContext` (if one exists). If DI is being used, see . A short-term solution to getting the current user's identity in code that hasn't yet been updated to work with ASP.NET Core's DI-driven architecture would be: - - * Make `IHttpContextAccessor` available in the DI container by calling [AddHttpContextAccessor](https://github.com/aspnet/Hosting/issues/793) in `Startup.ConfigureServices`. - * Get an instance of `IHttpContextAccessor` during startup and store it in a static variable. The instance is made available to code that was previously retrieving the current user from a static property. - * Retrieve the current user's `ClaimsPrincipal` using `HttpContextAccessor.HttpContext?.User`. If this code is used outside of the context of an HTTP request, the `HttpContext` is null. - -The final option, using an `IHttpContextAccessor` instance stored in a static variable, is contrary to the ASP.NET Core principle of preferring injected dependencies to static dependencies. Plan to eventually retrieve `IHttpContextAccessor` instances from DI instead. A static helper can be a useful bridge, though, when migrating large existing ASP.NET apps that use . +* **** +* **** +* **Passed in from caller**. Libraries without access to the current are often called from controllers or middleware components and can have the current user's identity passed as an argument. +* ****. The project being migrated to ASP.NET Core may be too large to easily pass the current user's identity to all necessary locations. In such cases, can be used as a workaround. This is not ideal as it uses a static accessor behind the scenes. Prefer a more direct option if possible. ### Code examples @@ -100,24 +94,6 @@ public class UserService } ``` -**ASP.NET Core (after) - Dependency Injection:** -```csharp -public class UserService -{ - private readonly IHttpContextAccessor _httpContextAccessor; - - public UserService(IHttpContextAccessor httpContextAccessor) - { - _httpContextAccessor = httpContextAccessor; - } - - public string GetCurrentUserId() - { - return _httpContextAccessor.HttpContext?.User?.FindFirst(ClaimTypes.NameIdentifier)?.Value; - } -} -``` - **ASP.NET Core (after) - Pass ClaimsPrincipal as parameter:** ```csharp public class UserService @@ -146,10 +122,28 @@ public class HomeController : Controller } ``` +**ASP.NET Core (after) - Dependency Injection:** +```csharp +public class UserService +{ + private readonly IHttpContextAccessor _httpContextAccessor; + + public UserService(IHttpContextAccessor httpContextAccessor) + { + _httpContextAccessor = httpContextAccessor; + } + + public string GetCurrentUserId() + { + return _httpContextAccessor.HttpContext?.User?.FindFirst(ClaimTypes.NameIdentifier)?.Value; + } +} +``` + ### When to choose this approach * You can afford to rewrite static principal access code -* Performance is a top priority (in this case, prefer the passing as a parameter option) +* Performance is a top priority (in this case, prefer passing the identity as a parameter over DI) * You want to eliminate static dependencies * You're not sharing code with legacy applications * You want the most testable and maintainable solution @@ -206,41 +200,3 @@ public class HomeController : Controller * **Native ASP.NET Core patterns** provide the best performance with no overhead * **System.Web adapters** introduce some performance overhead but enable gradual migration * **Static variables** should be avoided as they can cause memory leaks and threading issues - -### Testing considerations - -* **Dependency injection approach** is most testable - you can easily inject mock `IHttpContextAccessor` or pass test `ClaimsPrincipal` objects -* **Static access patterns** are harder to test and may require additional setup in unit tests - -### Security considerations - -* Ensure that `ClaimsPrincipal` access is properly validated in all scenarios -* Be aware of potential null reference exceptions when `HttpContext` is not available -* Consider the security implications of storing user context in static variables - -## Common issues and solutions - -### Issue: Static principal properties are null - -**Problem**: Code that previously worked with static principal properties ( or ) now returns null. - -**Solution**: -* For complete rewrite: Use `HttpContext.User` or inject `IHttpContextAccessor` -* For incremental migration: Enable System.Web adapters with proper configuration - -### Issue: Thread.CurrentPrincipal not working - -**Problem**: is not set in ASP.NET Core. - -**Solution**: -* Preferred: Refactor to use `HttpContext.User` or dependency injection -* Temporary: Use `SetThreadCurrentPrincipalAttribute` with System.Web adapters - -### Issue: Null reference exceptions - -**Problem**: `HttpContext` may be null in certain scenarios (background tasks, etc.). - -**Solution**: Always check for null before accessing user properties: -```csharp -var userId = _httpContextAccessor.HttpContext?.User?.FindFirst(ClaimTypes.NameIdentifier)?.Value; -``` From 587ec61f640f69edd1afcfc96f0ff5d8ad39d032 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 30 Jun 2025 14:33:59 -0700 Subject: [PATCH 26/61] update title --- .../migration/fx-to-core/areas/claimsprincipal-current.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/aspnetcore/migration/fx-to-core/areas/claimsprincipal-current.md b/aspnetcore/migration/fx-to-core/areas/claimsprincipal-current.md index 2670feacdfe2..d3a4e8942858 100644 --- a/aspnetcore/migration/fx-to-core/areas/claimsprincipal-current.md +++ b/aspnetcore/migration/fx-to-core/areas/claimsprincipal-current.md @@ -1,17 +1,17 @@ --- -title: Migrate from ClaimsPrincipal.Current +title: Migrate from static ClaimsPrincipal access author: mjrousos -description: Learn how to migrate away from ClaimsPrincipal.Current to retrieve the current authenticated user's identity and claims in ASP.NET Core. +description: Learn how to migrate away from static ClaimsPrincipal access to retrieve the current authenticated user's identity and claims in ASP.NET Core. ms.author: wpickett ms.custom: mvc ms.date: 06/30/2025 uid: migration/fx-to-core/areas/claimsprincipal-current --- -# Migrate from ClaimsPrincipal.Current +# Migrate from static ClaimsPrincipal access The current ClaimsPrincipal is a fundamental component of authenticated web applications, providing access to the current user's identity and claims. When migrating from ASP.NET Framework to ASP.NET Core, accessing this presents unique challenges because the two frameworks have different approaches to user context management. -## Why ClaimsPrincipal migration is complex +## Why static ClaimsPrincipal migration is complex ASP.NET Framework and ASP.NET Core have fundamentally different approaches to accessing the current user: From 6e330bfceaf1b10767669072a8b70e42ca92525d Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 30 Jun 2025 14:35:19 -0700 Subject: [PATCH 27/61] remove --- aspnetcore/migration/fx-to-core/inc/remote-app-setup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md index f604617f68c2..51f0e34fb6c6 100644 --- a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md +++ b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md @@ -17,7 +17,7 @@ Common scenarios this enables: * Fallback to the legacy application with YARP * [Remote app authentication](xref:migration/fx-to-core/areas/authentication#remote-authenticationn) -* [Remote session](xref:migration/fx-to-core/areas/session#remote-app-session-state) features. +* [Remote session](xref:migration/fx-to-core/areas/session#remote-app-session-state) ## Configuration From 606c2bd24c23601800ac5989c7e607aa9ae086e5 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 30 Jun 2025 14:40:54 -0700 Subject: [PATCH 28/61] update remote app setup --- .../fx-to-core/inc/remote-app-setup.md | 41 +++++++++---------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md index 51f0e34fb6c6..35b855932a5a 100644 --- a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md +++ b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md @@ -33,28 +33,23 @@ You need to configure two configuration values in both applications: * `RemoteAppApiKey`: A key (required to be parseable as a [GUID](/dotnet/api/system.guid)) that is shared between the two applications. This should be a GUID value like `12345678-1234-1234-1234-123456789012`. * `RemoteAppUri`: The URI of the remote ASP.NET Framework application (only required in the ASP.NET Core application configuration). This should be the full URL where the ASP.NET Framework app is hosted, such as `https://localhost:44300` or `https://myapp.example.com`. +### ASP.NET Framework + For ASP.NET Framework applications, add these values to your `web.config` in the `` section: +> [!IMPORTANT] +> ASP.NET Framework stores its appSettings in `web.config`. However, they can be retrieved from other sources (such as environment variables) with the use of [configuration Builders](/aspnet/config-builder). This makes sharing configuration values much easier between the local and remote applications in this setup. + +> [!IMPORTANT] +> The ASP.NET Framework application should be hosted with SSL enabled. In the remote app setup for incremental migration, it is not required to have direct access externally. It is recommended to only allow access from the client application via the proxy. + ```xml ``` -For ASP.NET Core applications, add these values to your `appsettings.json`: - -```json -{ - "RemoteAppApiKey": "...", - "RemoteAppUri": "https://localhost:44300" -} -``` - -For ASP.NET Framework applications, it is recommended to use [Configuration Builders](/aspnet/config-builder) to allow injecting values into the application without touching the `web.config`. - -### ASP.NET app configuration - -To set up the ASP.NET app to be able to receive requests from the ASP.NET Core app: +To configure the application to be available to handle the requests from the ASP.NET Core client, set up the following: 1. Install the NuGet package [`Microsoft.AspNetCore.SystemWebAdapters.FrameworkServices`](https://www.nuget.org/packages/Microsoft.AspNetCore.SystemWebAdapters) @@ -74,12 +69,6 @@ To set up the ASP.NET app to be able to receive requests from the ASP.NET Core a } ``` - In the options configuration method passed to the `AddRemoteAppServer` call, an API key must be specified. The API key is: - - * Used to secure the endpoint so that only trusted callers can make requests to it. - * The same API key provided to the ASP.NET Core app when it is configured. - * A string and must be parsable as a [GUID](/dotnet/api/system.guid). Hyphens in the key are optional. - 1. Add the `SystemWebAdapterModule` module to the `web.config` if it wasn't already added by NuGet. This module configuration is required for IIS hosting scenarios. The `SystemWebAdapterModule` module is not added automatically when using SDK style projects for ASP.NET Core. ```diff @@ -89,9 +78,17 @@ To set up the ASP.NET app to be able to receive requests from the ASP.NET Core a +
-``` -### ASP.NET Core app +### ASP.NET Core + +For ASP.NET Core applications, add these values to your `appsettings.json`: + +```json +{ + "RemoteAppApiKey": "...", + "RemoteAppUri": "https://localhost:44300" +} +``` To set up the ASP.NET Core app to be able to send requests to the ASP.NET app, configure the remote app client by calling `AddRemoteAppClient` after registering System.Web adapter services with `AddSystemWebAdapters`. From 82b445bf376e8ce205eeec93f55541ba7e7bdad9 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 30 Jun 2025 14:42:16 -0700 Subject: [PATCH 29/61] add ?displayProperty=nameWithType --- .../migration/fx-to-core/areas/claimsprincipal-current.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aspnetcore/migration/fx-to-core/areas/claimsprincipal-current.md b/aspnetcore/migration/fx-to-core/areas/claimsprincipal-current.md index d3a4e8942858..86e4a51893bb 100644 --- a/aspnetcore/migration/fx-to-core/areas/claimsprincipal-current.md +++ b/aspnetcore/migration/fx-to-core/areas/claimsprincipal-current.md @@ -15,7 +15,7 @@ The current ClaimsPrincipal is a fundamental component of authenticated web appl ASP.NET Framework and ASP.NET Core have fundamentally different approaches to accessing the current user: -* **ASP.NET Framework** uses static properties like and with automatic context management. These properties are interchangeable and both provide access to the current user's identity. +* **ASP.NET Framework** uses static properties like and with automatic context management. These properties are interchangeable and both provide access to the current user's identity. * **ASP.NET Core** stores the current user in and avoids static state. These differences mean you can't simply continue using static principal properties ( or ) in ASP.NET Core without changes. By default, the static properties aren't set, and code depending on them needs to be updated to get the current authenticated user's identity through different means. From bb03021850191eb76602f7838c154e8028f8161c Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 30 Jun 2025 14:43:31 -0700 Subject: [PATCH 30/61] add type --- .../fx-to-core/areas/http-context.md | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/aspnetcore/migration/fx-to-core/areas/http-context.md b/aspnetcore/migration/fx-to-core/areas/http-context.md index 496f84c077fc..281c8f02a0fc 100644 --- a/aspnetcore/migration/fx-to-core/areas/http-context.md +++ b/aspnetcore/migration/fx-to-core/areas/http-context.md @@ -126,11 +126,11 @@ This section shows how to translate the most commonly used properties of ** → **** +* **** → **** [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Items)] -* ***No equivalent*** → **** +* ***No equivalent*** → **** [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Trace)] @@ -138,59 +138,59 @@ This section shows how to translate the most commonly used properties of ** → **** +* **** → **** [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Method)] -* **** → **** +* **** → **** [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Query)] -* **** / **** → **Multiple properties** +* **** / **** → **Multiple properties** [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Url)] Use Request.Scheme, Host, PathBase, Path, QueryString -* **** → **** +* **** → **** [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Secure)] -* **** → **** +* **** → **** [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Host)] -* **** → **** +* **** → **** [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Cookies)] -* **** → **** +* **** → **** [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Route)] -* **** → **** +* **** → **** [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Headers)] -* **** → **** +* **** → **** [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Agent)] -* **** → **** +* **** → **** [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Referrer)] -* **** → **** +* **** → **** [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Type)] -* **** → **** +* **** → **** [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Form)] **Warning**: Read form values only if content type is *x-www-form-urlencoded* or *form-data* -* **** → **** +* **** → **** [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Input)] @@ -198,33 +198,33 @@ This section shows how to translate the most commonly used properties of ** / **** → **** +* **** / **** → **** [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Status)] -* **** / **** → **** +* **** / **** → **** [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_RespType)] -* **** → **** +* **** → **** [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_RespTypeOnly)] -* **** → **** +* **** → **** [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_Output)] -* **** → **See request features** +* **** → **See request features** Serving files is discussed in -* **** → **** +* **** → **** [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_SetHeaders)] Must use callback pattern to set headers before response starts -* **** → **** +* **** → **** [!code-csharp[](sample/Asp.Net.Core/Middleware/HttpContextDemoMiddleware.cs?name=snippet_SetCookies)] From b000cec6e1ff603256e4b936b579e61e9da7caac Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 30 Jun 2025 14:44:55 -0700 Subject: [PATCH 31/61] response patterns --- .../fx-to-core/areas/http-context.md | 28 ++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/aspnetcore/migration/fx-to-core/areas/http-context.md b/aspnetcore/migration/fx-to-core/areas/http-context.md index 281c8f02a0fc..cb7d72f65d8a 100644 --- a/aspnetcore/migration/fx-to-core/areas/http-context.md +++ b/aspnetcore/migration/fx-to-core/areas/http-context.md @@ -230,22 +230,18 @@ This section shows how to translate the most commonly used properties of Date: Mon, 30 Jun 2025 14:59:54 -0700 Subject: [PATCH 32/61] add proxy guidance --- .../migration/fx-to-core/areas/index.md | 5 +- .../fx-to-core/inc/remote-app-setup.md | 54 +++++++++++++++++-- aspnetcore/toc.yml | 2 + 3 files changed, 56 insertions(+), 5 deletions(-) diff --git a/aspnetcore/migration/fx-to-core/areas/index.md b/aspnetcore/migration/fx-to-core/areas/index.md index 118690a5a7ee..0c3f1acbd7b6 100644 --- a/aspnetcore/migration/fx-to-core/areas/index.md +++ b/aspnetcore/migration/fx-to-core/areas/index.md @@ -8,12 +8,15 @@ uid: migration/fx-to-core/areas --- # Technology specific guidance +* [Authentication](authentication.md) +* [ClaimsPrincipal.Current](claimsprincipal-current.md) * [HttpContext](http-context.md) * [HTTP Handlers](http-handlers.md) * [HTTP Modules](http-modules.md) * [Membership](membership.md) +* [Miscellaneous](misc.md) +* [Session State](session.md) * [WebAPI](webapi.md) -* [ClaimsPrincipal.Current](claimsprincipal-current.md) ## Getting help diff --git a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md index 35b855932a5a..369a9957e3a4 100644 --- a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md +++ b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md @@ -15,7 +15,7 @@ In some incremental upgrade scenarios, it's useful for the new ASP.NET Core app Common scenarios this enables: -* Fallback to the legacy application with YARP +* Fallback to the legacy application with [YARP](xref:fundamentals/servers/yarp/yarp-overview) * [Remote app authentication](xref:migration/fx-to-core/areas/authentication#remote-authenticationn) * [Remote session](xref:migration/fx-to-core/areas/session#remote-app-session-state) @@ -35,14 +35,14 @@ You need to configure two configuration values in both applications: ### ASP.NET Framework +> [!IMPORTANT] +> The ASP.NET Framework application should be hosted with SSL enabled. In the remote app setup for incremental migration, it is not required to have direct access externally. It is recommended to only allow access from the client application via the proxy. + For ASP.NET Framework applications, add these values to your `web.config` in the `` section: > [!IMPORTANT] > ASP.NET Framework stores its appSettings in `web.config`. However, they can be retrieved from other sources (such as environment variables) with the use of [configuration Builders](/aspnet/config-builder). This makes sharing configuration values much easier between the local and remote applications in this setup. -> [!IMPORTANT] -> The ASP.NET Framework application should be hosted with SSL enabled. In the remote app setup for incremental migration, it is not required to have direct access externally. It is recommended to only allow access from the client application via the proxy. - ```xml @@ -104,3 +104,49 @@ builder.Services.AddSystemWebAdapters() ``` With both the ASP.NET and ASP.NET Core app updated, extension methods can now be used to set up [remote app authentication](xref:migration/fx-to-core/areas/authentication#remote-authenticationn) or [remote session](xref:migration/fx-to-core/areas/session#remote-app-session-state), as needed. + +## Proxying + +To enable proxying from the ASP.NET Core application to the ASP.NET Framework application, you can set up a fallback route that forwards unmatched requests to the legacy application. This allows for a gradual migration where the ASP.NET Core app handles migrated functionality while falling back to the original app for unmigrated features. + +1. Install the YARP (Yet Another Reverse Proxy) NuGet package following the [latest guidance](~/fundamentals/servers/yarp/getting-started). + +1. Add the required using statements to your `Program.cs`: + + ```csharp + using Microsoft.Extensions.Options; + using Microsoft.AspNetCore.SystemWebAdapters; + ``` + +1. Register the reverse proxy services in your `Program.cs`: + + ```csharp + builder.Services.AddReverseProxy(); + ``` + +1. After building the app and configuring other middleware, add the fallback route mapping: + + ```csharp + var app = builder.Build(); + + // Configure your other middleware here (authentication, routing, etc.) + + // Map the fallback route + app.MapForwarder("/{**catch-all}", app.ServiceProvider.GetRequiredService>().Value.RemoteAppUrl.OriginalString) + + // Ensures this route has the lowest priority (runs last) + .WithOrder(int.MaxValue) + + // Skips remaining middleware when this route matches + .ShortCircuit(); + + app.Run(); + ``` + +With this configuration: + +1. **Local routes take precedence**: If the ASP.NET Core application has a matching route, it will handle the request locally +2. **Fallback to legacy app**: Unmatched requests are automatically forwarded to the ASP.NET Framework application +3. **Middleware optimization**: The `.ShortCircuit()` method prevents unnecessary middleware execution when forwarding requests + +This setup enables a seamless user experience during incremental migration, where users can access both migrated and legacy functionality through a single endpoint. diff --git a/aspnetcore/toc.yml b/aspnetcore/toc.yml index 029579a9789d..9a9c024e8617 100644 --- a/aspnetcore/toc.yml +++ b/aspnetcore/toc.yml @@ -2135,6 +2135,8 @@ items: uid: migration/fx-to-core/areas/webapi - name: ClaimsPrincipal.Current uid: migration/fx-to-core/areas/claimsprincipal-current + - name: Miscellaneous + uid: migration/fx-to-core/areas/misc - name: Example Migration items: - name: Overview From 7dd4df08d8eeb3b0c7986484c80cde519532b086 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 30 Jun 2025 15:02:55 -0700 Subject: [PATCH 33/61] add missing back ticks --- .../migration/fx-to-core/inc/remote-app-setup.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md index 369a9957e3a4..699313745c43 100644 --- a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md +++ b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md @@ -71,13 +71,14 @@ To configure the application to be available to handle the requests from the ASP 1. Add the `SystemWebAdapterModule` module to the `web.config` if it wasn't already added by NuGet. This module configuration is required for IIS hosting scenarios. The `SystemWebAdapterModule` module is not added automatically when using SDK style projects for ASP.NET Core. -```diff - - -+ -+ - - + ```diff + + + + + + + + + ``` ### ASP.NET Core From da1b8cf19a7d93435821f1a0cdfa1adb0fa05954 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 30 Jun 2025 15:05:47 -0700 Subject: [PATCH 34/61] fix link --- aspnetcore/migration/fx-to-core/inc/remote-app-setup.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md index 699313745c43..f0e62e5fa860 100644 --- a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md +++ b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md @@ -15,7 +15,7 @@ In some incremental upgrade scenarios, it's useful for the new ASP.NET Core app Common scenarios this enables: -* Fallback to the legacy application with [YARP](xref:fundamentals/servers/yarp/yarp-overview) +* Fallback to the legacy application with [YARP](~/fundamentals/servers/yarp/yarp-overview.md) * [Remote app authentication](xref:migration/fx-to-core/areas/authentication#remote-authenticationn) * [Remote session](xref:migration/fx-to-core/areas/session#remote-app-session-state) @@ -110,7 +110,7 @@ With both the ASP.NET and ASP.NET Core app updated, extension methods can now be To enable proxying from the ASP.NET Core application to the ASP.NET Framework application, you can set up a fallback route that forwards unmatched requests to the legacy application. This allows for a gradual migration where the ASP.NET Core app handles migrated functionality while falling back to the original app for unmigrated features. -1. Install the YARP (Yet Another Reverse Proxy) NuGet package following the [latest guidance](~/fundamentals/servers/yarp/getting-started). +1. Install the YARP (Yet Another Reverse Proxy) NuGet package following the [latest guidance](~/fundamentals/servers/yarp/getting-started.md). 1. Add the required using statements to your `Program.cs`: From afeb122b9cf2380115ba31f00ef7469d4c77ffcb Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 30 Jun 2025 15:19:49 -0700 Subject: [PATCH 35/61] clean up overview --- aspnetcore/migration/fx-to-core/inc/overview.md | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/aspnetcore/migration/fx-to-core/inc/overview.md b/aspnetcore/migration/fx-to-core/inc/overview.md index 838c08f72682..1b3ba01adda0 100644 --- a/aspnetcore/migration/fx-to-core/inc/overview.md +++ b/aspnetcore/migration/fx-to-core/inc/overview.md @@ -57,20 +57,10 @@ Once the ASP.NET Framework app is no longer needed and deleted: ![final pic](~/migration/fx-to-core/inc/overview/static/final.png) -The Visual Studio extension [.NET Upgrade Assistant](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.upgradeassistant) can help upgrade ASP.NET Framework web apps to ASP.NET Core. For more information see the blog post [Upgrading your .NET projects with Visual Studio](https://devblogs.microsoft.com/dotnet/upgrade-assistant-now-in-visual-studio/). +## Next Steps -## System.Web Adapters - -The `Microsoft.AspNetCore.SystemWebAdapters` namespace is a collection of runtime helpers that facilitate using code written against `System.Web` while moving to ASP.NET Core. There are a few packages that may be used to use features from these adapters: - -* `Microsoft.AspNetCore.SystemWebAdapters`: This package is used in supporting libraries and provide the System.Web APIs you may have taken a dependency on, such as `HttpContext` and others. This package targets .NET Standard 2.0, .NET Framework 4.5+, and .NET 5+. -* `Microsoft.AspNetCore.SystemWebAdapters.FrameworkServices`: This package only targets .NET Framework and is intended to provide services to ASP.NET Framework applications that may need to provide incremental migrations. This is generally not expected to be referenced from libraries, but rather from the applications themselves. -* `Microsoft.AspNetCore.SystemWebAdapters.CoreServices`: This package only targets .NET 6+ and is intended to provide services to ASP.NET Core applications to configure behavior of `System.Web` APIs as well as opting into any behaviors for incremental migration. This is generally not expected to be referenced from libraries, but rather from the applications themselves. -* `Microsoft.AspNetCore.SystemWebAdapters.Abstractions`: This package is a supporting package that provides abstractions for services used by both the ASP.NET Core and ASP.NET Framework application such as session state serialization. - -For examples of scenarios where this is useful, see [the adapters article](xref:migration/fx-to-core/systemweb-adapters). +See the [Getting Started](~/migration/fx-to-core/inc/start.md) guide for how to update an existing application to take advantage of this pattern. ## Additional Resources -* [Example migration of eShop to ASP.NET Core](/dotnet/architecture/porting-existing-aspnet-apps/example-migration-eshop) -* [Video:Tooling for Incremental ASP.NET Core Migrations](https://www.youtube.com/watch?v=P96l0pDNVpM) +* [Migration Tooling](~/migration/fx-to-core/tooling.md) From b4e0a122c5afabeedf88cf5d81aa731ed5427c12 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Tue, 1 Jul 2025 09:02:06 -0700 Subject: [PATCH 36/61] remove advanced auth - not needed --- .../fx-to-core/areas/authentication.md | 32 +------------------ 1 file changed, 1 insertion(+), 31 deletions(-) diff --git a/aspnetcore/migration/fx-to-core/areas/authentication.md b/aspnetcore/migration/fx-to-core/areas/authentication.md index 3dd2d0dc8a13..d1fb116b201c 100644 --- a/aspnetcore/migration/fx-to-core/areas/authentication.md +++ b/aspnetcore/migration/fx-to-core/areas/authentication.md @@ -7,6 +7,7 @@ monikerRange: '>= aspnetcore-6.0' ms.date: 11/9/2022 ms.topic: article uid: migration/fx-to-core/areas/authentication +zone_pivot_groups: migration-remote-app-setup --- # Migrate ASP.NET Framework Authentication to ASP.NET Core @@ -220,37 +221,6 @@ public class HomeController : Controller } ``` -#### Advanced Configuration Options - -In addition to the require boolean, an optional callback may be passed to `AddAuthenticationClient` to modify some other aspects of the remote authentication process's behavior: - -* `RequestHeadersToForward`: This property contains headers that should be forwarded from a request when calling the authenticate API. By default, the only headers forwarded are `Authorization` and `Cookie`. Additional headers can be forwarded by adding them to this list. Alternatively, if the list is cleared (so that no headers are specified), then all headers will be forwarded. that no headers are specified), then all headers will be forwarded. -* `ResponseHeadersToForward`: This property lists response headers that should be propagated back from the authenticate request to the original call that prompted authentication in scenarios where identity is challenged. By default, this includes `Location`, `Set-Cookie`, and `WWW-Authenticate` headers. -* `AuthenticationEndpointPath`: The endpoint on the ASP.NET app where authenticate requests should be made. This defaults to `/systemweb-adapters/authenticate` and must match the endpoint specified in the ASP.NET authentication endpoint configuration. - -Here's an example of configuring these options: - -```csharp -builder.Services.AddSystemWebAdapters() - .AddRemoteAppClient(options => - { - options.RemoteAppUrl = new Uri(builder.Configuration - ["ReverseProxy:Clusters:fallbackCluster:Destinations:fallbackApp:Address"]); - options.ApiKey = builder.Configuration["RemoteAppApiKey"]; - }) - .AddAuthenticationClient(false, options => - { - // Forward additional headers for authentication - options.RequestHeadersToForward.Add("X-Custom-Auth-Header"); - - // Forward additional response headers - options.ResponseHeadersToForward.Add("X-Custom-Response-Header"); - - // Use a custom authentication endpoint path - options.AuthenticationEndpointPath = "/custom-auth-endpoint"; - }); -``` - #### Implementing Custom Authentication Result Processors You can implement custom processors to modify authentication results before they are used: From fe3a210ed5efa78a11c18fe7eaf237f26ebfc57f Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Tue, 1 Jul 2025 08:54:08 -0700 Subject: [PATCH 37/61] add aspire pivots --- .../fx-to-core/areas/authentication.md | 21 ++ .../migration/fx-to-core/areas/session.md | 22 +++ .../migration/fx-to-core/inc/overview.md | 8 +- .../fx-to-core/inc/remote-app-setup.md | 187 ++++++++++++++++++ aspnetcore/zone-pivot-groups.yml | 8 + 5 files changed, 243 insertions(+), 3 deletions(-) diff --git a/aspnetcore/migration/fx-to-core/areas/authentication.md b/aspnetcore/migration/fx-to-core/areas/authentication.md index d1fb116b201c..ba461feb4d02 100644 --- a/aspnetcore/migration/fx-to-core/areas/authentication.md +++ b/aspnetcore/migration/fx-to-core/areas/authentication.md @@ -181,6 +181,8 @@ There are just a few small code changes needed to enable remote authentication i First, follow the [remote app setup](xref:migration/fx-to-core/inc/remote-app-setup) instructions to connect the ASP.NET Core and ASP.NET apps. Then, there are just a couple extra extension methods to call to enable remote app authentication. +:::zone pivot="default" + #### ASP.NET app configuration The ASP.NET app needs to be configured to add the authentication endpoint. Adding the authentication endpoint is done by calling the `AddAuthenticationServer` extension method to set up the HTTP module that watches for requests to the authentication endpoint. Note that remote authentication scenarios typically want to add proxy support as well, so that any authentication related redirects correctly route to the ASP.NET Core app rather than the ASP.NET one. @@ -195,6 +197,25 @@ Next, the ASP.NET Core app needs to be configured to enable the authentication h The boolean that is passed to the `AddAuthenticationClient` call specifies whether remote app authentication should be the default authentication scheme. Passing `true` will cause the user to be authenticated via remote app authentication for all requests, whereas passing `false` means that the user will only be authenticated with remote app authentication if the remote app scheme is specifically requested (with `[Authorize(AuthenticationSchemes = RemoteAppAuthenticationDefaults.AuthenticationScheme)]` on a controller or action method, for example). Passing false for this parameter has the advantage of only making HTTP requests to the original ASP.NET app for authentication for endpoints that require remote app authentication but has the disadvantage of requiring annotating all such endpoints to indicate that they will use remote app auth. +:::zone-end + +:::zone pivot="aspire" +When using Aspire, the configuration will be done via environment variables and are set by the AppHost. To enable remote session, the option must be enabled: + +```csharp +... + +var coreApp = builder.AddProject("core") + .WithHttpHealthCheck() + .WaitFor(frameworkApp) + .WithIncrementalMigrationFallback(frameworkApp, options => options.RemoteAuthentication = RemoteAuthentication.DefaultScheme); + +... +``` + +Once this is done, it will be automatically hooked up in both the framework and core applications. +:::zone-end + #### Using Remote Authentication with Specific Endpoints When you set the default scheme to `false`, you can specify remote authentication for specific controllers or actions: diff --git a/aspnetcore/migration/fx-to-core/areas/session.md b/aspnetcore/migration/fx-to-core/areas/session.md index 528d42452435..965a9a36b02c 100644 --- a/aspnetcore/migration/fx-to-core/areas/session.md +++ b/aspnetcore/migration/fx-to-core/areas/session.md @@ -7,6 +7,7 @@ monikerRange: '>= aspnetcore-6.0' ms.date: 11/9/2022 ms.topic: article uid: migration/fx-to-core/areas/session +zone_pivot_groups: migration-remote-app-setup --- # Migrate ASP.NET Framework Session to ASP.NET Core @@ -178,6 +179,7 @@ Out of the box, there is a simple JSON serializer that allows each session key t ### Application configuration +:::zone pivot="default" **ASP.NET Core configuration:** Call `AddRemoteAppSession` and `AddJsonSessionSerializer` to register known session item types: @@ -200,6 +202,26 @@ Add this change to `Global.asax.cs`: :::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/remote/Global.asax.cs"::: +:::zone-end + +:::zone pivot="aspire" +When using Aspire, the configuration will be done via environment variables and are set by the AppHost. To enable remote session, the option must be enabled: + +```csharp +... + +var coreApp = builder.AddProject("core") + .WithHttpHealthCheck() + .WaitFor(frameworkApp) + .WithIncrementalMigrationFallback(frameworkApp, options => options.RemoteSession = RemoteSession.Enabled); + +... +``` + +Once this is done, it will be automatically hooked up in both the framework and core applications. + +:::zone-end + ### Communication protocol #### Readonly sessions diff --git a/aspnetcore/migration/fx-to-core/inc/overview.md b/aspnetcore/migration/fx-to-core/inc/overview.md index 1b3ba01adda0..6d7eb8d48f0d 100644 --- a/aspnetcore/migration/fx-to-core/inc/overview.md +++ b/aspnetcore/migration/fx-to-core/inc/overview.md @@ -57,10 +57,12 @@ Once the ASP.NET Framework app is no longer needed and deleted: ![final pic](~/migration/fx-to-core/inc/overview/static/final.png) -## Next Steps +The Visual Studio extension [.NET Upgrade Assistant](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.upgradeassistant) can help upgrade ASP.NET Framework web apps to ASP.NET Core. For more information see the blog post [Upgrading your .NET projects with Visual Studio](https://devblogs.microsoft.com/dotnet/upgrade-assistant-now-in-visual-studio/). -See the [Getting Started](~/migration/fx-to-core/inc/start.md) guide for how to update an existing application to take advantage of this pattern. +For guidance around usage, see the [usage guidance article](xref:migration/fx-to-core/inc/usage_guidance). ## Additional Resources -* [Migration Tooling](~/migration/fx-to-core/tooling.md) +* [Example migration of eShop to ASP.NET Core](/dotnet/architecture/porting-existing-aspnet-apps/example-migration-eshop) +* [Video:Tooling for Incremental ASP.NET Core Migrations](https://www.youtube.com/watch?v=P96l0pDNVpM) +* diff --git a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md index f0e62e5fa860..a8e6a89cb45b 100644 --- a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md +++ b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md @@ -7,6 +7,7 @@ monikerRange: '>= aspnetcore-6.0' ms.date: 11/9/2022 ms.topic: article uid: migration/fx-to-core/inc/remote-app-setup +zone_pivot_groups: migration-remote-app-setup --- # Remote app setup @@ -26,6 +27,8 @@ Common scenarios this enables: > > The virtual directory setup is used for route generation, authorization, and other services within the system. At this point, no reliable method has been found to enable different virtual directories due to how ASP.NET Framework works. +:::zone pivot="manual" + To enable the ASP.NET Core app to communicate with the ASP.NET app, it's necessary to make a couple small changes to each app. You need to configure two configuration values in both applications: @@ -144,6 +147,190 @@ To enable proxying from the ASP.NET Core application to the ASP.NET Framework ap app.Run(); ``` +:::zone-end + +:::zone pivot="aspire" + +> [!NOTE] +> This is still in preview and not available on NuGet.org, so you must configure your NuGet config to pull libraries from the .NET Libraries daily feed: +> +> ```xml +> +> +> +> +> +> +> +> +> +> ``` + +## Setup Aspire orchestration + +1. Add Aspire orchestration for the ASP.NET Framework application +1. Add a new ASP.NET Core application to the solution and add it to your Aspire orchestration +1. Add the following Aspire integrations to your app host: + * `Aspire.Hosting.IncrementalMigration` + * `C3D.Extensions.Aspire.IISExpress` +1. Configure IIS Express to locally host your framework application and configure incremental migration fallback: + + ```csharp + var builder = DistributedApplication.CreateBuilder(args); + + var frameworkApp = builder.AddIISExpress("iis") + .AddSiteProject("framework") + .WithDefaultIISExpressEndpoints() + .WithOtlpExporter() + .WithHttpHealthCheck(path: "/framework"); + + var coreApp = builder.AddProject("core") + .WithHttpHealthCheck() + .WaitFor(frameworkApp) + .WithIncrementalMigrationFallback(frameworkApp, options => options.RemoteSession = RemoteSession.Enabled); + + builder.Build().Run(); + ``` +1. Configure the options of the incremental migration fallback for the scenarios you want to support. + +## Configure ServiceDefaults to support ASP.NET Framework + +1. Add the package `Aspire.Microsoft.AspNetCore.SystemWebAdapters` to your application. +1. Update the ServiceDefaults project to support .NET Framework. This is based off of the default ServiceDefaults and may different if you have customized anything. + * Update the target framework to multitarget: + ```diff + - net9.0 + + net9.0;net48 + ``` + * Update the PackageReferences to account for the different frameworks: + ```xml + + + + + + + + + + + + + + + + + + + + + + + ``` + * In the Extensions.cs file, you'll need to conditionally exclude the ServiceDiscovery APIs as those are currently not supported on .NET Framework: + ```diff + + #if NET + builder.Services.AddServiceDiscovery(); + + #endif + + builder.Services.ConfigureHttpClientDefaults(http => + { + // Turn on resilience by default + http.AddStandardResilienceHandler(); + + + #if NET + // Turn on service discovery by default + http.AddServiceDiscovery(); + + #endif + }); + ``` + * To enable telemetry, update the metrics and tracing registrations: + + ```diff + builder.Services.AddOpenTelemetry() + .WithMetrics(metrics => + { + metrics + + #if NET + .AddAspNetCoreInstrumentation() + + #else + + .AddAspNetInstrumentation() + + #endif + .AddSqlClientInstrumentation() + .AddHttpClientInstrumentation() + .AddRuntimeInstrumentation(); + }) + .WithTracing(tracing => + { + tracing.AddSource(builder.Environment.ApplicationName) + + #if NET + .AddAspNetCoreInstrumentation() + + #else + + .AddAspNetInstrumentation() + + #endif + .AddSqlClientInstrumentation() + .AddHttpClientInstrumentation(); + }); + ``` + * Disable the default endpoints as that only applies for ASP.NET Core: + + ```diff + + #if NET + public static WebApplication MapDefaultEndpoints(this WebApplication app) + { + // Default endpoint registrations + } + + #endif + ``` + +## Configure ASP.NET Framework Application + +1. Reference the ServiceDefaults project +1. Add the configuration code to the `Application_Start` method in your `Global.asax.cs` file: + + ```CSharp + protected void Application_Start() + { + HttpApplicationHost.RegisterHost(builder => + { + builder.AddServiceDefaults(); + builder.AddSystemWebAdapters(); + }); + } + ``` + +## Configure ASP.NET Core Application + +1. Reference the ServiceDefaults project +1. Add the System.Web adapters in Programs.cs: + + ```diff + var builder = WebApplication.CreateBuilder(); + + builder.AddServiceDefaults(); + + builder.AddSystemWebAdapters(); + + ... + + var app = builder.Build(); + + ... + + + // Must be placed after routing if manually added + + app.UseSystemWebAdapters(); + + ... + + + app.MapRemoteAppFallback() + + + + // Optional, but recommended unless middleware is needed + + .ShortCircuit(); + + app.Run(); + ``` + +:::zone-end + With this configuration: 1. **Local routes take precedence**: If the ASP.NET Core application has a matching route, it will handle the request locally diff --git a/aspnetcore/zone-pivot-groups.yml b/aspnetcore/zone-pivot-groups.yml index 88d0a36b0be4..8bd3c582279f 100644 --- a/aspnetcore/zone-pivot-groups.yml +++ b/aspnetcore/zone-pivot-groups.yml @@ -118,3 +118,11 @@ groups: title: MSTest - id: nunit title: NUnit +- id: migration-remote-app-setup + title: Remote app setup + prompt: Choose how to configure remote app + pivots: + - id: manual + title: Manually + - id: aspire + title: Aspire \ No newline at end of file From fb9ed9251b213d5117491409018eb5663805be43 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Tue, 1 Jul 2025 09:06:45 -0700 Subject: [PATCH 38/61] add windows requirement --- aspnetcore/migration/fx-to-core/inc/remote-app-setup.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md index a8e6a89cb45b..60eeca426cb9 100644 --- a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md +++ b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md @@ -170,6 +170,11 @@ To enable proxying from the ASP.NET Core application to the ASP.NET Framework ap 1. Add Aspire orchestration for the ASP.NET Framework application 1. Add a new ASP.NET Core application to the solution and add it to your Aspire orchestration +1. Update the AppHost to target Windows as IIS integration requires that: + ```diff + - net9.0 + + net9.0-windows + ``` 1. Add the following Aspire integrations to your app host: * `Aspire.Hosting.IncrementalMigration` * `C3D.Extensions.Aspire.IISExpress` From 41f9304fac2e570c0e79e34a1cfd8f64936c5bad Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Tue, 1 Jul 2025 09:34:15 -0700 Subject: [PATCH 39/61] warnings --- aspnetcore/migration/fx-to-core/areas/authentication.md | 2 +- aspnetcore/migration/fx-to-core/areas/session.md | 2 +- aspnetcore/migration/fx-to-core/inc/overview.md | 8 +++----- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/aspnetcore/migration/fx-to-core/areas/authentication.md b/aspnetcore/migration/fx-to-core/areas/authentication.md index ba461feb4d02..b0b203947bba 100644 --- a/aspnetcore/migration/fx-to-core/areas/authentication.md +++ b/aspnetcore/migration/fx-to-core/areas/authentication.md @@ -181,7 +181,7 @@ There are just a few small code changes needed to enable remote authentication i First, follow the [remote app setup](xref:migration/fx-to-core/inc/remote-app-setup) instructions to connect the ASP.NET Core and ASP.NET apps. Then, there are just a couple extra extension methods to call to enable remote app authentication. -:::zone pivot="default" +:::zone pivot="manual" #### ASP.NET app configuration diff --git a/aspnetcore/migration/fx-to-core/areas/session.md b/aspnetcore/migration/fx-to-core/areas/session.md index 965a9a36b02c..d6b2d8cbdfae 100644 --- a/aspnetcore/migration/fx-to-core/areas/session.md +++ b/aspnetcore/migration/fx-to-core/areas/session.md @@ -179,7 +179,7 @@ Out of the box, there is a simple JSON serializer that allows each session key t ### Application configuration -:::zone pivot="default" +:::zone pivot="manual" **ASP.NET Core configuration:** Call `AddRemoteAppSession` and `AddJsonSessionSerializer` to register known session item types: diff --git a/aspnetcore/migration/fx-to-core/inc/overview.md b/aspnetcore/migration/fx-to-core/inc/overview.md index 6d7eb8d48f0d..1b3ba01adda0 100644 --- a/aspnetcore/migration/fx-to-core/inc/overview.md +++ b/aspnetcore/migration/fx-to-core/inc/overview.md @@ -57,12 +57,10 @@ Once the ASP.NET Framework app is no longer needed and deleted: ![final pic](~/migration/fx-to-core/inc/overview/static/final.png) -The Visual Studio extension [.NET Upgrade Assistant](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.upgradeassistant) can help upgrade ASP.NET Framework web apps to ASP.NET Core. For more information see the blog post [Upgrading your .NET projects with Visual Studio](https://devblogs.microsoft.com/dotnet/upgrade-assistant-now-in-visual-studio/). +## Next Steps -For guidance around usage, see the [usage guidance article](xref:migration/fx-to-core/inc/usage_guidance). +See the [Getting Started](~/migration/fx-to-core/inc/start.md) guide for how to update an existing application to take advantage of this pattern. ## Additional Resources -* [Example migration of eShop to ASP.NET Core](/dotnet/architecture/porting-existing-aspnet-apps/example-migration-eshop) -* [Video:Tooling for Incremental ASP.NET Core Migrations](https://www.youtube.com/watch?v=P96l0pDNVpM) -* +* [Migration Tooling](~/migration/fx-to-core/tooling.md) From fb33ebab75052c8c1f6aa3a45cf4eb4e2f1d40cc Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Tue, 1 Jul 2025 09:34:47 -0700 Subject: [PATCH 40/61] Revert aspire stuff --- .../fx-to-core/areas/authentication.md | 21 -- .../migration/fx-to-core/areas/session.md | 22 -- .../fx-to-core/inc/remote-app-setup.md | 192 ------------------ aspnetcore/zone-pivot-groups.yml | 8 - 4 files changed, 243 deletions(-) diff --git a/aspnetcore/migration/fx-to-core/areas/authentication.md b/aspnetcore/migration/fx-to-core/areas/authentication.md index b0b203947bba..d1fb116b201c 100644 --- a/aspnetcore/migration/fx-to-core/areas/authentication.md +++ b/aspnetcore/migration/fx-to-core/areas/authentication.md @@ -181,8 +181,6 @@ There are just a few small code changes needed to enable remote authentication i First, follow the [remote app setup](xref:migration/fx-to-core/inc/remote-app-setup) instructions to connect the ASP.NET Core and ASP.NET apps. Then, there are just a couple extra extension methods to call to enable remote app authentication. -:::zone pivot="manual" - #### ASP.NET app configuration The ASP.NET app needs to be configured to add the authentication endpoint. Adding the authentication endpoint is done by calling the `AddAuthenticationServer` extension method to set up the HTTP module that watches for requests to the authentication endpoint. Note that remote authentication scenarios typically want to add proxy support as well, so that any authentication related redirects correctly route to the ASP.NET Core app rather than the ASP.NET one. @@ -197,25 +195,6 @@ Next, the ASP.NET Core app needs to be configured to enable the authentication h The boolean that is passed to the `AddAuthenticationClient` call specifies whether remote app authentication should be the default authentication scheme. Passing `true` will cause the user to be authenticated via remote app authentication for all requests, whereas passing `false` means that the user will only be authenticated with remote app authentication if the remote app scheme is specifically requested (with `[Authorize(AuthenticationSchemes = RemoteAppAuthenticationDefaults.AuthenticationScheme)]` on a controller or action method, for example). Passing false for this parameter has the advantage of only making HTTP requests to the original ASP.NET app for authentication for endpoints that require remote app authentication but has the disadvantage of requiring annotating all such endpoints to indicate that they will use remote app auth. -:::zone-end - -:::zone pivot="aspire" -When using Aspire, the configuration will be done via environment variables and are set by the AppHost. To enable remote session, the option must be enabled: - -```csharp -... - -var coreApp = builder.AddProject("core") - .WithHttpHealthCheck() - .WaitFor(frameworkApp) - .WithIncrementalMigrationFallback(frameworkApp, options => options.RemoteAuthentication = RemoteAuthentication.DefaultScheme); - -... -``` - -Once this is done, it will be automatically hooked up in both the framework and core applications. -:::zone-end - #### Using Remote Authentication with Specific Endpoints When you set the default scheme to `false`, you can specify remote authentication for specific controllers or actions: diff --git a/aspnetcore/migration/fx-to-core/areas/session.md b/aspnetcore/migration/fx-to-core/areas/session.md index d6b2d8cbdfae..528d42452435 100644 --- a/aspnetcore/migration/fx-to-core/areas/session.md +++ b/aspnetcore/migration/fx-to-core/areas/session.md @@ -7,7 +7,6 @@ monikerRange: '>= aspnetcore-6.0' ms.date: 11/9/2022 ms.topic: article uid: migration/fx-to-core/areas/session -zone_pivot_groups: migration-remote-app-setup --- # Migrate ASP.NET Framework Session to ASP.NET Core @@ -179,7 +178,6 @@ Out of the box, there is a simple JSON serializer that allows each session key t ### Application configuration -:::zone pivot="manual" **ASP.NET Core configuration:** Call `AddRemoteAppSession` and `AddJsonSessionSerializer` to register known session item types: @@ -202,26 +200,6 @@ Add this change to `Global.asax.cs`: :::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/remote/Global.asax.cs"::: -:::zone-end - -:::zone pivot="aspire" -When using Aspire, the configuration will be done via environment variables and are set by the AppHost. To enable remote session, the option must be enabled: - -```csharp -... - -var coreApp = builder.AddProject("core") - .WithHttpHealthCheck() - .WaitFor(frameworkApp) - .WithIncrementalMigrationFallback(frameworkApp, options => options.RemoteSession = RemoteSession.Enabled); - -... -``` - -Once this is done, it will be automatically hooked up in both the framework and core applications. - -:::zone-end - ### Communication protocol #### Readonly sessions diff --git a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md index 60eeca426cb9..f0e62e5fa860 100644 --- a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md +++ b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md @@ -7,7 +7,6 @@ monikerRange: '>= aspnetcore-6.0' ms.date: 11/9/2022 ms.topic: article uid: migration/fx-to-core/inc/remote-app-setup -zone_pivot_groups: migration-remote-app-setup --- # Remote app setup @@ -27,8 +26,6 @@ Common scenarios this enables: > > The virtual directory setup is used for route generation, authorization, and other services within the system. At this point, no reliable method has been found to enable different virtual directories due to how ASP.NET Framework works. -:::zone pivot="manual" - To enable the ASP.NET Core app to communicate with the ASP.NET app, it's necessary to make a couple small changes to each app. You need to configure two configuration values in both applications: @@ -147,195 +144,6 @@ To enable proxying from the ASP.NET Core application to the ASP.NET Framework ap app.Run(); ``` -:::zone-end - -:::zone pivot="aspire" - -> [!NOTE] -> This is still in preview and not available on NuGet.org, so you must configure your NuGet config to pull libraries from the .NET Libraries daily feed: -> -> ```xml -> -> -> -> -> -> -> -> -> -> ``` - -## Setup Aspire orchestration - -1. Add Aspire orchestration for the ASP.NET Framework application -1. Add a new ASP.NET Core application to the solution and add it to your Aspire orchestration -1. Update the AppHost to target Windows as IIS integration requires that: - ```diff - - net9.0 - + net9.0-windows - ``` -1. Add the following Aspire integrations to your app host: - * `Aspire.Hosting.IncrementalMigration` - * `C3D.Extensions.Aspire.IISExpress` -1. Configure IIS Express to locally host your framework application and configure incremental migration fallback: - - ```csharp - var builder = DistributedApplication.CreateBuilder(args); - - var frameworkApp = builder.AddIISExpress("iis") - .AddSiteProject("framework") - .WithDefaultIISExpressEndpoints() - .WithOtlpExporter() - .WithHttpHealthCheck(path: "/framework"); - - var coreApp = builder.AddProject("core") - .WithHttpHealthCheck() - .WaitFor(frameworkApp) - .WithIncrementalMigrationFallback(frameworkApp, options => options.RemoteSession = RemoteSession.Enabled); - - builder.Build().Run(); - ``` -1. Configure the options of the incremental migration fallback for the scenarios you want to support. - -## Configure ServiceDefaults to support ASP.NET Framework - -1. Add the package `Aspire.Microsoft.AspNetCore.SystemWebAdapters` to your application. -1. Update the ServiceDefaults project to support .NET Framework. This is based off of the default ServiceDefaults and may different if you have customized anything. - * Update the target framework to multitarget: - ```diff - - net9.0 - + net9.0;net48 - ``` - * Update the PackageReferences to account for the different frameworks: - ```xml - - - - - - - - - - - - - - - - - - - - - - - ``` - * In the Extensions.cs file, you'll need to conditionally exclude the ServiceDiscovery APIs as those are currently not supported on .NET Framework: - ```diff - + #if NET - builder.Services.AddServiceDiscovery(); - + #endif - - builder.Services.ConfigureHttpClientDefaults(http => - { - // Turn on resilience by default - http.AddStandardResilienceHandler(); - - + #if NET - // Turn on service discovery by default - http.AddServiceDiscovery(); - + #endif - }); - ``` - * To enable telemetry, update the metrics and tracing registrations: - - ```diff - builder.Services.AddOpenTelemetry() - .WithMetrics(metrics => - { - metrics - + #if NET - .AddAspNetCoreInstrumentation() - + #else - + .AddAspNetInstrumentation() - + #endif - .AddSqlClientInstrumentation() - .AddHttpClientInstrumentation() - .AddRuntimeInstrumentation(); - }) - .WithTracing(tracing => - { - tracing.AddSource(builder.Environment.ApplicationName) - + #if NET - .AddAspNetCoreInstrumentation() - + #else - + .AddAspNetInstrumentation() - + #endif - .AddSqlClientInstrumentation() - .AddHttpClientInstrumentation(); - }); - ``` - * Disable the default endpoints as that only applies for ASP.NET Core: - - ```diff - + #if NET - public static WebApplication MapDefaultEndpoints(this WebApplication app) - { - // Default endpoint registrations - } - + #endif - ``` - -## Configure ASP.NET Framework Application - -1. Reference the ServiceDefaults project -1. Add the configuration code to the `Application_Start` method in your `Global.asax.cs` file: - - ```CSharp - protected void Application_Start() - { - HttpApplicationHost.RegisterHost(builder => - { - builder.AddServiceDefaults(); - builder.AddSystemWebAdapters(); - }); - } - ``` - -## Configure ASP.NET Core Application - -1. Reference the ServiceDefaults project -1. Add the System.Web adapters in Programs.cs: - - ```diff - var builder = WebApplication.CreateBuilder(); - - builder.AddServiceDefaults(); - + builder.AddSystemWebAdapters(); - - ... - - var app = builder.Build(); - - ... - - + // Must be placed after routing if manually added - + app.UseSystemWebAdapters(); - - ... - - + app.MapRemoteAppFallback() - + - + // Optional, but recommended unless middleware is needed - + .ShortCircuit(); - - app.Run(); - ``` - -:::zone-end - With this configuration: 1. **Local routes take precedence**: If the ASP.NET Core application has a matching route, it will handle the request locally diff --git a/aspnetcore/zone-pivot-groups.yml b/aspnetcore/zone-pivot-groups.yml index 8bd3c582279f..88d0a36b0be4 100644 --- a/aspnetcore/zone-pivot-groups.yml +++ b/aspnetcore/zone-pivot-groups.yml @@ -118,11 +118,3 @@ groups: title: MSTest - id: nunit title: NUnit -- id: migration-remote-app-setup - title: Remote app setup - prompt: Choose how to configure remote app - pivots: - - id: manual - title: Manually - - id: aspire - title: Aspire \ No newline at end of file From 37b6d46e518e307876104e5bdfa4888dccb88004 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Tue, 1 Jul 2025 09:35:44 -0700 Subject: [PATCH 41/61] Add documentation for using incremental setup with Aspire --- .../fx-to-core/areas/authentication.md | 21 ++ .../migration/fx-to-core/areas/session.md | 22 ++ .../fx-to-core/inc/remote-app-setup.md | 192 ++++++++++++++++++ aspnetcore/zone-pivot-groups.yml | 8 + 4 files changed, 243 insertions(+) diff --git a/aspnetcore/migration/fx-to-core/areas/authentication.md b/aspnetcore/migration/fx-to-core/areas/authentication.md index d1fb116b201c..b0b203947bba 100644 --- a/aspnetcore/migration/fx-to-core/areas/authentication.md +++ b/aspnetcore/migration/fx-to-core/areas/authentication.md @@ -181,6 +181,8 @@ There are just a few small code changes needed to enable remote authentication i First, follow the [remote app setup](xref:migration/fx-to-core/inc/remote-app-setup) instructions to connect the ASP.NET Core and ASP.NET apps. Then, there are just a couple extra extension methods to call to enable remote app authentication. +:::zone pivot="manual" + #### ASP.NET app configuration The ASP.NET app needs to be configured to add the authentication endpoint. Adding the authentication endpoint is done by calling the `AddAuthenticationServer` extension method to set up the HTTP module that watches for requests to the authentication endpoint. Note that remote authentication scenarios typically want to add proxy support as well, so that any authentication related redirects correctly route to the ASP.NET Core app rather than the ASP.NET one. @@ -195,6 +197,25 @@ Next, the ASP.NET Core app needs to be configured to enable the authentication h The boolean that is passed to the `AddAuthenticationClient` call specifies whether remote app authentication should be the default authentication scheme. Passing `true` will cause the user to be authenticated via remote app authentication for all requests, whereas passing `false` means that the user will only be authenticated with remote app authentication if the remote app scheme is specifically requested (with `[Authorize(AuthenticationSchemes = RemoteAppAuthenticationDefaults.AuthenticationScheme)]` on a controller or action method, for example). Passing false for this parameter has the advantage of only making HTTP requests to the original ASP.NET app for authentication for endpoints that require remote app authentication but has the disadvantage of requiring annotating all such endpoints to indicate that they will use remote app auth. +:::zone-end + +:::zone pivot="aspire" +When using Aspire, the configuration will be done via environment variables and are set by the AppHost. To enable remote session, the option must be enabled: + +```csharp +... + +var coreApp = builder.AddProject("core") + .WithHttpHealthCheck() + .WaitFor(frameworkApp) + .WithIncrementalMigrationFallback(frameworkApp, options => options.RemoteAuthentication = RemoteAuthentication.DefaultScheme); + +... +``` + +Once this is done, it will be automatically hooked up in both the framework and core applications. +:::zone-end + #### Using Remote Authentication with Specific Endpoints When you set the default scheme to `false`, you can specify remote authentication for specific controllers or actions: diff --git a/aspnetcore/migration/fx-to-core/areas/session.md b/aspnetcore/migration/fx-to-core/areas/session.md index 528d42452435..d6b2d8cbdfae 100644 --- a/aspnetcore/migration/fx-to-core/areas/session.md +++ b/aspnetcore/migration/fx-to-core/areas/session.md @@ -7,6 +7,7 @@ monikerRange: '>= aspnetcore-6.0' ms.date: 11/9/2022 ms.topic: article uid: migration/fx-to-core/areas/session +zone_pivot_groups: migration-remote-app-setup --- # Migrate ASP.NET Framework Session to ASP.NET Core @@ -178,6 +179,7 @@ Out of the box, there is a simple JSON serializer that allows each session key t ### Application configuration +:::zone pivot="manual" **ASP.NET Core configuration:** Call `AddRemoteAppSession` and `AddJsonSessionSerializer` to register known session item types: @@ -200,6 +202,26 @@ Add this change to `Global.asax.cs`: :::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/remote/Global.asax.cs"::: +:::zone-end + +:::zone pivot="aspire" +When using Aspire, the configuration will be done via environment variables and are set by the AppHost. To enable remote session, the option must be enabled: + +```csharp +... + +var coreApp = builder.AddProject("core") + .WithHttpHealthCheck() + .WaitFor(frameworkApp) + .WithIncrementalMigrationFallback(frameworkApp, options => options.RemoteSession = RemoteSession.Enabled); + +... +``` + +Once this is done, it will be automatically hooked up in both the framework and core applications. + +:::zone-end + ### Communication protocol #### Readonly sessions diff --git a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md index f0e62e5fa860..60eeca426cb9 100644 --- a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md +++ b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md @@ -7,6 +7,7 @@ monikerRange: '>= aspnetcore-6.0' ms.date: 11/9/2022 ms.topic: article uid: migration/fx-to-core/inc/remote-app-setup +zone_pivot_groups: migration-remote-app-setup --- # Remote app setup @@ -26,6 +27,8 @@ Common scenarios this enables: > > The virtual directory setup is used for route generation, authorization, and other services within the system. At this point, no reliable method has been found to enable different virtual directories due to how ASP.NET Framework works. +:::zone pivot="manual" + To enable the ASP.NET Core app to communicate with the ASP.NET app, it's necessary to make a couple small changes to each app. You need to configure two configuration values in both applications: @@ -144,6 +147,195 @@ To enable proxying from the ASP.NET Core application to the ASP.NET Framework ap app.Run(); ``` +:::zone-end + +:::zone pivot="aspire" + +> [!NOTE] +> This is still in preview and not available on NuGet.org, so you must configure your NuGet config to pull libraries from the .NET Libraries daily feed: +> +> ```xml +> +> +> +> +> +> +> +> +> +> ``` + +## Setup Aspire orchestration + +1. Add Aspire orchestration for the ASP.NET Framework application +1. Add a new ASP.NET Core application to the solution and add it to your Aspire orchestration +1. Update the AppHost to target Windows as IIS integration requires that: + ```diff + - net9.0 + + net9.0-windows + ``` +1. Add the following Aspire integrations to your app host: + * `Aspire.Hosting.IncrementalMigration` + * `C3D.Extensions.Aspire.IISExpress` +1. Configure IIS Express to locally host your framework application and configure incremental migration fallback: + + ```csharp + var builder = DistributedApplication.CreateBuilder(args); + + var frameworkApp = builder.AddIISExpress("iis") + .AddSiteProject("framework") + .WithDefaultIISExpressEndpoints() + .WithOtlpExporter() + .WithHttpHealthCheck(path: "/framework"); + + var coreApp = builder.AddProject("core") + .WithHttpHealthCheck() + .WaitFor(frameworkApp) + .WithIncrementalMigrationFallback(frameworkApp, options => options.RemoteSession = RemoteSession.Enabled); + + builder.Build().Run(); + ``` +1. Configure the options of the incremental migration fallback for the scenarios you want to support. + +## Configure ServiceDefaults to support ASP.NET Framework + +1. Add the package `Aspire.Microsoft.AspNetCore.SystemWebAdapters` to your application. +1. Update the ServiceDefaults project to support .NET Framework. This is based off of the default ServiceDefaults and may different if you have customized anything. + * Update the target framework to multitarget: + ```diff + - net9.0 + + net9.0;net48 + ``` + * Update the PackageReferences to account for the different frameworks: + ```xml + + + + + + + + + + + + + + + + + + + + + + + ``` + * In the Extensions.cs file, you'll need to conditionally exclude the ServiceDiscovery APIs as those are currently not supported on .NET Framework: + ```diff + + #if NET + builder.Services.AddServiceDiscovery(); + + #endif + + builder.Services.ConfigureHttpClientDefaults(http => + { + // Turn on resilience by default + http.AddStandardResilienceHandler(); + + + #if NET + // Turn on service discovery by default + http.AddServiceDiscovery(); + + #endif + }); + ``` + * To enable telemetry, update the metrics and tracing registrations: + + ```diff + builder.Services.AddOpenTelemetry() + .WithMetrics(metrics => + { + metrics + + #if NET + .AddAspNetCoreInstrumentation() + + #else + + .AddAspNetInstrumentation() + + #endif + .AddSqlClientInstrumentation() + .AddHttpClientInstrumentation() + .AddRuntimeInstrumentation(); + }) + .WithTracing(tracing => + { + tracing.AddSource(builder.Environment.ApplicationName) + + #if NET + .AddAspNetCoreInstrumentation() + + #else + + .AddAspNetInstrumentation() + + #endif + .AddSqlClientInstrumentation() + .AddHttpClientInstrumentation(); + }); + ``` + * Disable the default endpoints as that only applies for ASP.NET Core: + + ```diff + + #if NET + public static WebApplication MapDefaultEndpoints(this WebApplication app) + { + // Default endpoint registrations + } + + #endif + ``` + +## Configure ASP.NET Framework Application + +1. Reference the ServiceDefaults project +1. Add the configuration code to the `Application_Start` method in your `Global.asax.cs` file: + + ```CSharp + protected void Application_Start() + { + HttpApplicationHost.RegisterHost(builder => + { + builder.AddServiceDefaults(); + builder.AddSystemWebAdapters(); + }); + } + ``` + +## Configure ASP.NET Core Application + +1. Reference the ServiceDefaults project +1. Add the System.Web adapters in Programs.cs: + + ```diff + var builder = WebApplication.CreateBuilder(); + + builder.AddServiceDefaults(); + + builder.AddSystemWebAdapters(); + + ... + + var app = builder.Build(); + + ... + + + // Must be placed after routing if manually added + + app.UseSystemWebAdapters(); + + ... + + + app.MapRemoteAppFallback() + + + + // Optional, but recommended unless middleware is needed + + .ShortCircuit(); + + app.Run(); + ``` + +:::zone-end + With this configuration: 1. **Local routes take precedence**: If the ASP.NET Core application has a matching route, it will handle the request locally diff --git a/aspnetcore/zone-pivot-groups.yml b/aspnetcore/zone-pivot-groups.yml index 88d0a36b0be4..8bd3c582279f 100644 --- a/aspnetcore/zone-pivot-groups.yml +++ b/aspnetcore/zone-pivot-groups.yml @@ -118,3 +118,11 @@ groups: title: MSTest - id: nunit title: NUnit +- id: migration-remote-app-setup + title: Remote app setup + prompt: Choose how to configure remote app + pivots: + - id: manual + title: Manually + - id: aspire + title: Aspire \ No newline at end of file From fb16904b6cf13aee1648f07e166ed96fc590fde2 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Tue, 1 Jul 2025 09:46:47 -0700 Subject: [PATCH 42/61] move enable session --- .../migration/fx-to-core/areas/session.md | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/aspnetcore/migration/fx-to-core/areas/session.md b/aspnetcore/migration/fx-to-core/areas/session.md index d6b2d8cbdfae..8dd7ebde12bd 100644 --- a/aspnetcore/migration/fx-to-core/areas/session.md +++ b/aspnetcore/migration/fx-to-core/areas/session.md @@ -186,16 +186,6 @@ Call `AddRemoteAppSession` and `AddJsonSessionSerializer` to register known sess :::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/remote/Program.cs" id="snippet_Configuration" ::: -Session support requires explicit activation. Configure it per-route using ASP.NET Core metadata. - -#### Option 1: Annotate controllers - -:::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/remote/SomeController.cs" id="snippet_Controller" ::: - -#### Option 2: Enable globally for all endpoints - -:::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/remote/Program.cs" id="snippet_RequireSystemWebAdapterSession" ::: - **ASP.NET Framework configuration:** Add this change to `Global.asax.cs`: @@ -218,10 +208,21 @@ var coreApp = builder.AddProject("core") ... ``` -Once this is done, it will be automatically hooked up in both the framework and core applications. - :::zone-end +### Enable session + +Session support requires explicit activation. Configure it per-route using ASP.NET Core metadata. + +#### Option 1: Annotate controllers + +:::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/remote/SomeController.cs" id="snippet_Controller" ::: + +#### Option 2: Enable globally for all endpoints + +:::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/remote/Program.cs" id="snippet_RequireSystemWebAdapterSession" ::: + + ### Communication protocol #### Readonly sessions From 3b576a4fcd63d3f35fce1d4c713d0aecd25a0d6f Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Tue, 1 Jul 2025 09:47:08 -0700 Subject: [PATCH 43/61] fix whitespace --- aspnetcore/migration/fx-to-core/inc/remote-app-setup.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md index 60eeca426cb9..dcadcfadc6f8 100644 --- a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md +++ b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md @@ -259,7 +259,7 @@ To enable proxying from the ASP.NET Core application to the ASP.NET Framework ap + #if NET .AddAspNetCoreInstrumentation() + #else - + .AddAspNetInstrumentation() + + .AddAspNetInstrumentation() + #endif .AddSqlClientInstrumentation() .AddHttpClientInstrumentation() @@ -271,7 +271,7 @@ To enable proxying from the ASP.NET Core application to the ASP.NET Framework ap + #if NET .AddAspNetCoreInstrumentation() + #else - + .AddAspNetInstrumentation() + + .AddAspNetInstrumentation() + #endif .AddSqlClientInstrumentation() .AddHttpClientInstrumentation(); From c1f94155b9e9fbf2725b8562fdeb5f128b40d5ce Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Tue, 1 Jul 2025 09:52:14 -0700 Subject: [PATCH 44/61] update sesison --- .../migration/fx-to-core/areas/session.md | 18 +----------- .../session/samples/remote/Global.asax.cs | 28 +++++++++++-------- .../areas/session/samples/remote/Program.cs | 12 +++++++- 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/aspnetcore/migration/fx-to-core/areas/session.md b/aspnetcore/migration/fx-to-core/areas/session.md index 8dd7ebde12bd..3606383f0365 100644 --- a/aspnetcore/migration/fx-to-core/areas/session.md +++ b/aspnetcore/migration/fx-to-core/areas/session.md @@ -73,22 +73,6 @@ The [System.Web adapters](~/migration/fx-to-core/inc/systemweb-adapters.md) enab * `Microsoft.AspNetCore.SystemWebAdapters.ISessionManager`: Accepts an and session metadata, returns an `ISessionState` object * `Microsoft.AspNetCore.SystemWebAdapters.ISessionState`: Describes session object state and backs the type -### Shared session state requirements - -> [!NOTE] -> To use session state with System.Web adapters, endpoints must explicitly opt-in via metadata implementing `ISessionMetadata`. - -In order to support , endpoints must opt-into it via metadata implementing `ISessionMetadata`. - -**Recommendation**: To enable this on all MVC endpoints, there is an extension method that can be used as follows: - -```cs -app.MapDefaultControllerRoute() - .RequireSystemWebAdapterSession(); -``` - -This also requires some implementation of a session store. For details of options here, see the sections below on different session approaches. - ## Built-in ASP.NET Core session state Choose this approach when you're performing a complete migration and can rewrite session-related code to use ASP.NET Core's native session implementation. @@ -184,7 +168,7 @@ Out of the box, there is a simple JSON serializer that allows each session key t Call `AddRemoteAppSession` and `AddJsonSessionSerializer` to register known session item types: -:::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/remote/Program.cs" id="snippet_Configuration" ::: +:::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/remote/Program.cs" id="snippet_RemoteConfiguration" ::: **ASP.NET Framework configuration:** diff --git a/aspnetcore/migration/fx-to-core/areas/session/samples/remote/Global.asax.cs b/aspnetcore/migration/fx-to-core/areas/session/samples/remote/Global.asax.cs index 5f12acd75eb4..808a8b950058 100644 --- a/aspnetcore/migration/fx-to-core/areas/session/samples/remote/Global.asax.cs +++ b/aspnetcore/migration/fx-to-core/areas/session/samples/remote/Global.asax.cs @@ -1,11 +1,17 @@ -SystemWebAdapterConfiguration.AddSystemWebAdapters(this) - .AddJsonSessionSerializer(options => - { - // Serialization/deserialization requires each session key to be registered to a type - options.RegisterKey("test-value"); - options.RegisterKey("SampleSessionItem"); - }) - // Provide a strong API key that will be used to authenticate the request on the remote app for querying the session - // ApiKey is a string representing a GUID - .AddRemoteAppServer(options => options.ApiKey = ConfigurationManager.AppSettings["RemoteAppApiKey"]) - .AddSessionServer(); \ No newline at end of file +public class Global : HttpApplication +{ + protected void Application_Start() + { + SystemWebAdapterConfiguration.AddSystemWebAdapters(this) + .AddJsonSessionSerializer(options => + { + // Serialization/deserialization requires each session key to be registered to a type + options.RegisterKey("test-value"); + options.RegisterKey("SampleSessionItem"); + }) + // Provide a strong API key that will be used to authenticate the request on the remote app for querying the session + // ApiKey is a string representing a GUID + .AddRemoteAppServer(options => options.ApiKey = ConfigurationManager.AppSettings["RemoteAppApiKey"]) + .AddSessionServer(); + } +} \ No newline at end of file diff --git a/aspnetcore/migration/fx-to-core/areas/session/samples/remote/Program.cs b/aspnetcore/migration/fx-to-core/areas/session/samples/remote/Program.cs index db9c7941791c..1131e7241717 100644 --- a/aspnetcore/migration/fx-to-core/areas/session/samples/remote/Program.cs +++ b/aspnetcore/migration/fx-to-core/areas/session/samples/remote/Program.cs @@ -8,7 +8,7 @@ }); // -// +// builder.Services.AddSystemWebAdapters() .AddJsonSessionSerializer(options => { @@ -25,6 +25,16 @@ options.ApiKey = builder.Configuration["RemoteAppApiKey"]; }) .AddSessionClient(); +// + +// +builder.Services.AddSystemWebAdapters() + .AddJsonSessionSerializer(options => + { + // Serialization/deserialization requires each session key to be registered to a type + options.RegisterKey("test-value"); + options.RegisterKey("SampleSessionItem"); + }); // var app = builder.Build(); From 5597f8758ff503226abf1b5686cb56f5d4525928 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Tue, 1 Jul 2025 11:19:31 -0700 Subject: [PATCH 45/61] fix up sample --- aspnetcore/migration/fx-to-core/areas/session.md | 2 +- aspnetcore/migration/fx-to-core/inc/remote-app-setup.md | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/aspnetcore/migration/fx-to-core/areas/session.md b/aspnetcore/migration/fx-to-core/areas/session.md index 3606383f0365..411ff3a520da 100644 --- a/aspnetcore/migration/fx-to-core/areas/session.md +++ b/aspnetcore/migration/fx-to-core/areas/session.md @@ -159,7 +159,7 @@ Out of the box, there is a simple JSON serializer that allows each session key t * `RegisterKey(string)` - Registers a session key to a known type. This registration is required for correct serialization/deserialization. Missing registrations cause errors and prevent session access. -:::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/remote/Program.cs" id="snippet_Serialization" ::: +:::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/serialization/Program.cs" id="snippet_Serialization" ::: ### Application configuration diff --git a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md index dcadcfadc6f8..0d2f007783f4 100644 --- a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md +++ b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md @@ -223,8 +223,6 @@ To enable proxying from the ASP.NET Core application to the ASP.NET Framework ap - - From 6cb428cd75150b394cdad1660ea25ea33d65a259 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Tue, 1 Jul 2025 11:34:23 -0700 Subject: [PATCH 46/61] more session --- .../areas/include/enable-session.md | 11 +++++++ .../migration/fx-to-core/areas/session.md | 29 ++++++++----------- .../samples/serialization/Program_Custom.cs | 26 +++++++++++++++++ 3 files changed, 49 insertions(+), 17 deletions(-) create mode 100644 aspnetcore/migration/fx-to-core/areas/include/enable-session.md create mode 100644 aspnetcore/migration/fx-to-core/areas/session/samples/serialization/Program_Custom.cs diff --git a/aspnetcore/migration/fx-to-core/areas/include/enable-session.md b/aspnetcore/migration/fx-to-core/areas/include/enable-session.md new file mode 100644 index 000000000000..124e46cb07e1 --- /dev/null +++ b/aspnetcore/migration/fx-to-core/areas/include/enable-session.md @@ -0,0 +1,11 @@ +### Enable session + +Session support requires explicit activation. Configure it per-route using ASP.NET Core metadata. + +#### Option 1: Annotate controllers + +:::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/remote/SomeController.cs" id="snippet_Controller" ::: + +#### Option 2: Enable globally for all endpoints + +:::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/remote/Program.cs" id="snippet_RequireSystemWebAdapterSession" ::: diff --git a/aspnetcore/migration/fx-to-core/areas/session.md b/aspnetcore/migration/fx-to-core/areas/session.md index 411ff3a520da..8703c682415d 100644 --- a/aspnetcore/migration/fx-to-core/areas/session.md +++ b/aspnetcore/migration/fx-to-core/areas/session.md @@ -133,6 +133,8 @@ Your Framework application requires no changes. For more information, see the [wrapped session state sample app](https://github.com/dotnet/systemweb-adapters/blob/main/samples/SessionLocal/SessionLocalCore/Program.cs) +[!INCLUDE[](~/migration/fx-to-core/areas/includes/enable-session.md)] + ## Remote app session state [!INCLUDE[](~/migration/fx-to-core/includes/uses-systemweb-adapters.md)] @@ -149,11 +151,7 @@ Complete the [remote app setup](xref:migration/fx-to-core/inc/remote-app-setup) The object requires serialization for remote app session state. -In order to serialize session state, a serializer for the state object must be registered: - -:::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/remote/Program.cs" id="snippet_Serialization" ::: - -In ASP.NET Core, [BinaryFormatter](/dotnet/api/system.runtime.serialization.formatters.binary.binaryformatter) was used to automatically serialize session value contents. In order to serialize these with for use with the System.Web adapters, the serialization must be explicitly configured using `ISessionKeySerializer` implementations. +In ASP.NET Framework, [BinaryFormatter](/dotnet/api/system.runtime.serialization.formatters.binary.binaryformatter) was used to automatically serialize session value contents. In order to serialize these with for use with the System.Web adapters, the serialization must be explicitly configured using `ISessionKeySerializer` implementations. Out of the box, there is a simple JSON serializer that allows each session key to be registered to a known type using `JsonSessionSerializerOptions`: @@ -161,6 +159,14 @@ Out of the box, there is a simple JSON serializer that allows each session key t :::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/serialization/Program.cs" id="snippet_Serialization" ::: +If more customization is needed, then `ISessionKeySerializer` can be implemented: + +:::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/serialization/Program_Custom.cs" id="snippet_Serialization" ::: +:::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/serialization/Program_Custom.cs" id="snippet_CustomSerializer" ::: + +> [!NOTE] +> When using the `AddJsonSessionSerializer` registration pattern, there is no need to call `AddSessionSerializer` as it will automatically be added. If you only want to use a customimplementation, then you must manually add it. + ### Application configuration :::zone pivot="manual" @@ -194,18 +200,7 @@ var coreApp = builder.AddProject("core") :::zone-end -### Enable session - -Session support requires explicit activation. Configure it per-route using ASP.NET Core metadata. - -#### Option 1: Annotate controllers - -:::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/remote/SomeController.cs" id="snippet_Controller" ::: - -#### Option 2: Enable globally for all endpoints - -:::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/remote/Program.cs" id="snippet_RequireSystemWebAdapterSession" ::: - +[!INCLUDE[](~/migration/fx-to-core/areas/includes/enable-session.md)] ### Communication protocol diff --git a/aspnetcore/migration/fx-to-core/areas/session/samples/serialization/Program_Custom.cs b/aspnetcore/migration/fx-to-core/areas/session/samples/serialization/Program_Custom.cs new file mode 100644 index 000000000000..085ac6903e5f --- /dev/null +++ b/aspnetcore/migration/fx-to-core/areas/session/samples/serialization/Program_Custom.cs @@ -0,0 +1,26 @@ +var builder = WebApplication.CreateBuilder(args); + +// +builder.Services.AddSystemWebAdapters() + .AddSessionSerializer(); + +builder.Services.AddSingleton(); +// + +var app = builder.Build(); +app.Run(); + +// +sealed class CustomSessionKeySerializer : ISessionKeySerializer +{ + public bool TryDeserialize(string key, byte[] bytes, out object? obj) + { + // Custom deserialization logic + } + + public bool TrySerialize(string key, object? value, out byte[] bytes) + { + // Custom serialization logic + } +} +// \ No newline at end of file From dfd2c39ddf38ce0f0f6ccf5f4f11b036a1136ea0 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Tue, 1 Jul 2025 11:39:08 -0700 Subject: [PATCH 47/61] move to includes --- .../fx-to-core/areas/{include => includes}/enable-session.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename aspnetcore/migration/fx-to-core/areas/{include => includes}/enable-session.md (100%) diff --git a/aspnetcore/migration/fx-to-core/areas/include/enable-session.md b/aspnetcore/migration/fx-to-core/areas/includes/enable-session.md similarity index 100% rename from aspnetcore/migration/fx-to-core/areas/include/enable-session.md rename to aspnetcore/migration/fx-to-core/areas/includes/enable-session.md From 907bbc7de9bb1fafc8baa6e7a10389faa1831bb8 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Tue, 1 Jul 2025 11:42:49 -0700 Subject: [PATCH 48/61] remove path --- aspnetcore/migration/fx-to-core/inc/remote-app-setup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md index 0d2f007783f4..bd3a4058872a 100644 --- a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md +++ b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md @@ -187,7 +187,7 @@ To enable proxying from the ASP.NET Core application to the ASP.NET Framework ap .AddSiteProject("framework") .WithDefaultIISExpressEndpoints() .WithOtlpExporter() - .WithHttpHealthCheck(path: "/framework"); + .WithHttpHealthCheck(); var coreApp = builder.AddProject("core") .WithHttpHealthCheck() From d368de055499b7eeb5b168e74b6eb416f1b94283 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Tue, 1 Jul 2025 11:45:46 -0700 Subject: [PATCH 49/61] reword --- .../migration/fx-to-core/areas/includes/enable-session.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/aspnetcore/migration/fx-to-core/areas/includes/enable-session.md b/aspnetcore/migration/fx-to-core/areas/includes/enable-session.md index 124e46cb07e1..83a53f726fa7 100644 --- a/aspnetcore/migration/fx-to-core/areas/includes/enable-session.md +++ b/aspnetcore/migration/fx-to-core/areas/includes/enable-session.md @@ -1,11 +1,11 @@ -### Enable session +**Enable session** -Session support requires explicit activation. Configure it per-route using ASP.NET Core metadata. +Session support requires explicit activation. Configure it per-route or globally using ASP.NET Core metadata: -#### Option 1: Annotate controllers +* Annotate controllers :::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/remote/SomeController.cs" id="snippet_Controller" ::: -#### Option 2: Enable globally for all endpoints +* Enable globally for all endpoints :::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/remote/Program.cs" id="snippet_RequireSystemWebAdapterSession" ::: From 4a0fab0f758c40bf9dfbcf6d01d7d2c262742b9f Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Tue, 1 Jul 2025 11:49:56 -0700 Subject: [PATCH 50/61] move --- .../areas/includes/enable-session.md | 11 ---- .../migration/fx-to-core/areas/session.md | 60 +++++++++++-------- 2 files changed, 35 insertions(+), 36 deletions(-) delete mode 100644 aspnetcore/migration/fx-to-core/areas/includes/enable-session.md diff --git a/aspnetcore/migration/fx-to-core/areas/includes/enable-session.md b/aspnetcore/migration/fx-to-core/areas/includes/enable-session.md deleted file mode 100644 index 83a53f726fa7..000000000000 --- a/aspnetcore/migration/fx-to-core/areas/includes/enable-session.md +++ /dev/null @@ -1,11 +0,0 @@ -**Enable session** - -Session support requires explicit activation. Configure it per-route or globally using ASP.NET Core metadata: - -* Annotate controllers - -:::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/remote/SomeController.cs" id="snippet_Controller" ::: - -* Enable globally for all endpoints - -:::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/remote/Program.cs" id="snippet_RequireSystemWebAdapterSession" ::: diff --git a/aspnetcore/migration/fx-to-core/areas/session.md b/aspnetcore/migration/fx-to-core/areas/session.md index 8703c682415d..25e69633cc6b 100644 --- a/aspnetcore/migration/fx-to-core/areas/session.md +++ b/aspnetcore/migration/fx-to-core/areas/session.md @@ -117,10 +117,44 @@ When migrating to built-in ASP.NET Core session: * You're not sharing session data with legacy applications * You want to eliminate System.Web dependencies completely -## Wrapped ASP.NET Core session state +## System.Web Adapter Session [!INCLUDE[](~/migration/fx-to-core/includes/uses-systemweb-adapters.md)] +### Serialization configuration + +The object requires serialization for remote app session state. + +In ASP.NET Framework, [BinaryFormatter](/dotnet/api/system.runtime.serialization.formatters.binary.binaryformatter) was used to automatically serialize session value contents. In order to serialize these with for use with the System.Web adapters, the serialization must be explicitly configured using `ISessionKeySerializer` implementations. + +Out of the box, there is a simple JSON serializer that allows each session key to be registered to a known type using `JsonSessionSerializerOptions`: + +* `RegisterKey(string)` - Registers a session key to a known type. This registration is required for correct serialization/deserialization. Missing registrations cause errors and prevent session access. + +:::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/serialization/Program.cs" id="snippet_Serialization" ::: + +If more customization is needed, then `ISessionKeySerializer` can be implemented: + +:::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/serialization/Program_Custom.cs" id="snippet_Serialization" ::: +:::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/serialization/Program_Custom.cs" id="snippet_CustomSerializer" ::: + +> [!NOTE] +> When using the `AddJsonSessionSerializer` registration pattern, there is no need to call `AddSessionSerializer` as it will automatically be added. If you only want to use a customimplementation, then you must manually add it. + +### Enable session + +Session support requires explicit activation. Configure it per-route or globally using ASP.NET Core metadata: + +* Annotate controllers + +:::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/remote/SomeController.cs" id="snippet_Controller" ::: + +* Enable globally for all endpoints + +:::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/remote/Program.cs" id="snippet_RequireSystemWebAdapterSession" ::: + +## Wrapped ASP.NET Core session state + Choose this approach when your migrated components don't need to share session data with your legacy application. The `Microsoft.Extensions.DependencyInjection.WrappedSessionExtensions.AddWrappedAspNetCoreSession` extension method adds a wraps ASP.NET Core session to work with the adapters. It uses the same backing store as while providing strongly-typed access. @@ -133,8 +167,6 @@ Your Framework application requires no changes. For more information, see the [wrapped session state sample app](https://github.com/dotnet/systemweb-adapters/blob/main/samples/SessionLocal/SessionLocalCore/Program.cs) -[!INCLUDE[](~/migration/fx-to-core/areas/includes/enable-session.md)] - ## Remote app session state [!INCLUDE[](~/migration/fx-to-core/includes/uses-systemweb-adapters.md)] @@ -147,26 +179,6 @@ Remote app session enables communication between applications to retrieve and se Complete the [remote app setup](xref:migration/fx-to-core/inc/remote-app-setup) instructions to connect your ASP.NET Core and ASP.NET Framework applications. -### Serialization configuration - -The object requires serialization for remote app session state. - -In ASP.NET Framework, [BinaryFormatter](/dotnet/api/system.runtime.serialization.formatters.binary.binaryformatter) was used to automatically serialize session value contents. In order to serialize these with for use with the System.Web adapters, the serialization must be explicitly configured using `ISessionKeySerializer` implementations. - -Out of the box, there is a simple JSON serializer that allows each session key to be registered to a known type using `JsonSessionSerializerOptions`: - -* `RegisterKey(string)` - Registers a session key to a known type. This registration is required for correct serialization/deserialization. Missing registrations cause errors and prevent session access. - -:::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/serialization/Program.cs" id="snippet_Serialization" ::: - -If more customization is needed, then `ISessionKeySerializer` can be implemented: - -:::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/serialization/Program_Custom.cs" id="snippet_Serialization" ::: -:::code language="csharp" source="~/migration/fx-to-core/areas/session/samples/serialization/Program_Custom.cs" id="snippet_CustomSerializer" ::: - -> [!NOTE] -> When using the `AddJsonSessionSerializer` registration pattern, there is no need to call `AddSessionSerializer` as it will automatically be added. If you only want to use a customimplementation, then you must manually add it. - ### Application configuration :::zone pivot="manual" @@ -200,8 +212,6 @@ var coreApp = builder.AddProject("core") :::zone-end -[!INCLUDE[](~/migration/fx-to-core/areas/includes/enable-session.md)] - ### Communication protocol #### Readonly sessions From fbfb55f1d64ac61d7000474683258e5bde88a063 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Tue, 1 Jul 2025 11:57:10 -0700 Subject: [PATCH 51/61] better headers --- .../fx-to-core/inc/remote-app-setup.md | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md index bd3a4058872a..6fe1ac069ed4 100644 --- a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md +++ b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md @@ -12,6 +12,11 @@ zone_pivot_groups: migration-remote-app-setup # Remote app setup +> [!IMPORTANT] +> Framework and Core applications must use identical virtual directory layouts. +> +> The virtual directory setup is used for route generation, authorization, and other services within the system. At this point, no reliable method has been found to enable different virtual directories due to how ASP.NET Framework works. + In some incremental upgrade scenarios, it's useful for the new ASP.NET Core app to be able to communicate with the original ASP.NET app. Common scenarios this enables: @@ -20,15 +25,10 @@ Common scenarios this enables: * [Remote app authentication](xref:migration/fx-to-core/areas/authentication#remote-authenticationn) * [Remote session](xref:migration/fx-to-core/areas/session#remote-app-session-state) -## Configuration - -> [!IMPORTANT] -> Framework and Core applications must use identical virtual directory layouts. -> -> The virtual directory setup is used for route generation, authorization, and other services within the system. At this point, no reliable method has been found to enable different virtual directories due to how ASP.NET Framework works. - :::zone pivot="manual" +## Manual Configuration + To enable the ASP.NET Core app to communicate with the ASP.NET app, it's necessary to make a couple small changes to each app. You need to configure two configuration values in both applications: @@ -151,7 +151,9 @@ To enable proxying from the ASP.NET Core application to the ASP.NET Framework ap :::zone pivot="aspire" -> [!NOTE] +## Setup Aspire orchestration + +> [!WARNING] > This is still in preview and not available on NuGet.org, so you must configure your NuGet config to pull libraries from the .NET Libraries daily feed: > > ```xml @@ -166,8 +168,6 @@ To enable proxying from the ASP.NET Core application to the ASP.NET Framework ap > > ``` -## Setup Aspire orchestration - 1. Add Aspire orchestration for the ASP.NET Framework application 1. Add a new ASP.NET Core application to the solution and add it to your Aspire orchestration 1. Update the AppHost to target Windows as IIS integration requires that: From fcbb991878a7dcf4beb00e6a331e79d3e37326f0 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Tue, 1 Jul 2025 12:00:26 -0700 Subject: [PATCH 52/61] better manual steps --- aspnetcore/migration/fx-to-core/inc/remote-app-setup.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md index 6fe1ac069ed4..43f3253d2f43 100644 --- a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md +++ b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md @@ -27,7 +27,7 @@ Common scenarios this enables: :::zone pivot="manual" -## Manual Configuration +## Configuration Values To enable the ASP.NET Core app to communicate with the ASP.NET app, it's necessary to make a couple small changes to each app. @@ -36,7 +36,7 @@ You need to configure two configuration values in both applications: * `RemoteAppApiKey`: A key (required to be parseable as a [GUID](/dotnet/api/system.guid)) that is shared between the two applications. This should be a GUID value like `12345678-1234-1234-1234-123456789012`. * `RemoteAppUri`: The URI of the remote ASP.NET Framework application (only required in the ASP.NET Core application configuration). This should be the full URL where the ASP.NET Framework app is hosted, such as `https://localhost:44300` or `https://myapp.example.com`. -### ASP.NET Framework +## Configure ASP.NET Framework Application > [!IMPORTANT] > The ASP.NET Framework application should be hosted with SSL enabled. In the remote app setup for incremental migration, it is not required to have direct access externally. It is recommended to only allow access from the client application via the proxy. @@ -83,7 +83,7 @@ To configure the application to be available to handle the requests from the ASP ``` -### ASP.NET Core +## Configure ASP.NET Core Application For ASP.NET Core applications, add these values to your `appsettings.json`: @@ -109,7 +109,7 @@ builder.Services.AddSystemWebAdapters() With both the ASP.NET and ASP.NET Core app updated, extension methods can now be used to set up [remote app authentication](xref:migration/fx-to-core/areas/authentication#remote-authenticationn) or [remote session](xref:migration/fx-to-core/areas/session#remote-app-session-state), as needed. -## Proxying +### Enable proxying To enable proxying from the ASP.NET Core application to the ASP.NET Framework application, you can set up a fallback route that forwards unmatched requests to the legacy application. This allows for a gradual migration where the ASP.NET Core app handles migrated functionality while falling back to the original app for unmigrated features. From f95e303b3c4cea3065f5cf053a0e1a79b026e4a2 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Tue, 1 Jul 2025 12:10:17 -0700 Subject: [PATCH 53/61] add incremental pivot --- aspnetcore/migration/fx-to-core/index.md | 23 ++++++++++++++--------- aspnetcore/zone-pivot-groups.yml | 10 +++++++++- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/aspnetcore/migration/fx-to-core/index.md b/aspnetcore/migration/fx-to-core/index.md index 20a00d4fd904..2ede6c7ba4f4 100644 --- a/aspnetcore/migration/fx-to-core/index.md +++ b/aspnetcore/migration/fx-to-core/index.md @@ -5,6 +5,7 @@ description: Your complete guide to migrating ASP.NET Framework applications to ms.author: riande ms.date: 06/20/2025 uid: migration/fx-to-core/index +zone_pivot_groups: fx-to-core-migration --- # Migrate from ASP.NET Framework to ASP.NET Core @@ -24,25 +25,29 @@ Your ASP.NET Framework application can successfully move to ASP.NET Core. The ke Most non-trivial ASP.NET Framework applications should use incremental migration. This approach: -- **Keeps your current app running** while you migrate piece by piece -- **Reduces risk** by moving functionality gradually -- **Delivers value faster** with immediate deployment of migrated components -- **Uses proven tools** like YARP proxy and System.Web adapters +* **Keeps your current app running** while you migrate piece by piece +* **Reduces risk** by moving functionality gradually +* **Delivers value faster** with immediate deployment of migrated components +* **Uses proven tools** like YARP proxy and System.Web adapters +:::zone pivot="incremental" **→ [Start your incremental migration](xref:migration/fx-to-core/inc/overview)** +:::zone-end ## Migration tools and resources ### Automated assistance -- **[.NET Upgrade Assistant](https://dotnet.microsoft.com/platform/upgrade-assistant)** - Command-line tool for initial project conversion -- **[Visual Studio Extension](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.upgradeassistant)** - GUI-based upgrade assistance + +* **[.NET Upgrade Assistant](https://dotnet.microsoft.com/platform/upgrade-assistant)** - Command-line tool for initial project conversion +* **[Visual Studio Extension](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.upgradeassistant)** - GUI-based upgrade assistance ### Comprehensive guides -- **[Porting ASP.NET Apps eBook](https://aka.ms/aspnet-porting-ebook)** - Complete reference guide -- **[eShop Migration Example](/dotnet/architecture/porting-existing-aspnet-apps/example-migration-eshop)** - Real-world case study + +* **[Porting ASP.NET Apps eBook](https://aka.ms/aspnet-porting-ebook)** - Complete reference guide +* **[eShop Migration Example](/dotnet/architecture/porting-existing-aspnet-apps/example-migration-eshop)** - Real-world case study ## Changes to technology areas Before you begin, review the [technical differences between ASP.NET Framework and ASP.NET Core](xref:migration/fx-to-core/areas) to understand key changes that may affect your migration. -:::moniker-end \ No newline at end of file +:::moniker-end diff --git a/aspnetcore/zone-pivot-groups.yml b/aspnetcore/zone-pivot-groups.yml index 8bd3c582279f..e96bc9c47353 100644 --- a/aspnetcore/zone-pivot-groups.yml +++ b/aspnetcore/zone-pivot-groups.yml @@ -125,4 +125,12 @@ groups: - id: manual title: Manually - id: aspire - title: Aspire \ No newline at end of file + title: Aspire +- id: fx-to-core-migration + title: Migration Approach + prompt: Choose migration approach + pivots: + - id: incremental + title: Incremental + - id: inplace + title: In Place \ No newline at end of file From ce354a8394cad58ee33e837a20b10d300dc17887 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Tue, 1 Jul 2025 12:12:54 -0700 Subject: [PATCH 54/61] Revert "add incremental pivot" This reverts commit f95e303b3c4cea3065f5cf053a0e1a79b026e4a2. --- aspnetcore/migration/fx-to-core/index.md | 23 +++++++++-------------- aspnetcore/zone-pivot-groups.yml | 10 +--------- 2 files changed, 10 insertions(+), 23 deletions(-) diff --git a/aspnetcore/migration/fx-to-core/index.md b/aspnetcore/migration/fx-to-core/index.md index 2ede6c7ba4f4..20a00d4fd904 100644 --- a/aspnetcore/migration/fx-to-core/index.md +++ b/aspnetcore/migration/fx-to-core/index.md @@ -5,7 +5,6 @@ description: Your complete guide to migrating ASP.NET Framework applications to ms.author: riande ms.date: 06/20/2025 uid: migration/fx-to-core/index -zone_pivot_groups: fx-to-core-migration --- # Migrate from ASP.NET Framework to ASP.NET Core @@ -25,29 +24,25 @@ Your ASP.NET Framework application can successfully move to ASP.NET Core. The ke Most non-trivial ASP.NET Framework applications should use incremental migration. This approach: -* **Keeps your current app running** while you migrate piece by piece -* **Reduces risk** by moving functionality gradually -* **Delivers value faster** with immediate deployment of migrated components -* **Uses proven tools** like YARP proxy and System.Web adapters +- **Keeps your current app running** while you migrate piece by piece +- **Reduces risk** by moving functionality gradually +- **Delivers value faster** with immediate deployment of migrated components +- **Uses proven tools** like YARP proxy and System.Web adapters -:::zone pivot="incremental" **→ [Start your incremental migration](xref:migration/fx-to-core/inc/overview)** -:::zone-end ## Migration tools and resources ### Automated assistance - -* **[.NET Upgrade Assistant](https://dotnet.microsoft.com/platform/upgrade-assistant)** - Command-line tool for initial project conversion -* **[Visual Studio Extension](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.upgradeassistant)** - GUI-based upgrade assistance +- **[.NET Upgrade Assistant](https://dotnet.microsoft.com/platform/upgrade-assistant)** - Command-line tool for initial project conversion +- **[Visual Studio Extension](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.upgradeassistant)** - GUI-based upgrade assistance ### Comprehensive guides - -* **[Porting ASP.NET Apps eBook](https://aka.ms/aspnet-porting-ebook)** - Complete reference guide -* **[eShop Migration Example](/dotnet/architecture/porting-existing-aspnet-apps/example-migration-eshop)** - Real-world case study +- **[Porting ASP.NET Apps eBook](https://aka.ms/aspnet-porting-ebook)** - Complete reference guide +- **[eShop Migration Example](/dotnet/architecture/porting-existing-aspnet-apps/example-migration-eshop)** - Real-world case study ## Changes to technology areas Before you begin, review the [technical differences between ASP.NET Framework and ASP.NET Core](xref:migration/fx-to-core/areas) to understand key changes that may affect your migration. -:::moniker-end +:::moniker-end \ No newline at end of file diff --git a/aspnetcore/zone-pivot-groups.yml b/aspnetcore/zone-pivot-groups.yml index e96bc9c47353..8bd3c582279f 100644 --- a/aspnetcore/zone-pivot-groups.yml +++ b/aspnetcore/zone-pivot-groups.yml @@ -125,12 +125,4 @@ groups: - id: manual title: Manually - id: aspire - title: Aspire -- id: fx-to-core-migration - title: Migration Approach - prompt: Choose migration approach - pivots: - - id: incremental - title: Incremental - - id: inplace - title: In Place \ No newline at end of file + title: Aspire \ No newline at end of file From 31a847ecd7557c90fdba17db0b8bb5d9ee80e638 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Tue, 1 Jul 2025 13:11:36 -0700 Subject: [PATCH 55/61] add version --- aspnetcore/migration/fx-to-core/inc/remote-app-setup.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md index 43f3253d2f43..da6a0a354338 100644 --- a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md +++ b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md @@ -7,7 +7,6 @@ monikerRange: '>= aspnetcore-6.0' ms.date: 11/9/2022 ms.topic: article uid: migration/fx-to-core/inc/remote-app-setup -zone_pivot_groups: migration-remote-app-setup --- # Remote app setup @@ -25,8 +24,6 @@ Common scenarios this enables: * [Remote app authentication](xref:migration/fx-to-core/areas/authentication#remote-authenticationn) * [Remote session](xref:migration/fx-to-core/areas/session#remote-app-session-state) -:::zone pivot="manual" - ## Configuration Values To enable the ASP.NET Core app to communicate with the ASP.NET app, it's necessary to make a couple small changes to each app. @@ -166,6 +163,8 @@ To enable proxying from the ASP.NET Core application to the ASP.NET Framework ap > > > +> +> This requires v2.0.1-preview1.25351.3 of the System.Web adapters or later. > ``` 1. Add Aspire orchestration for the ASP.NET Framework application From 33166b41b6a175e5e9867bb83e10dd1c22281c66 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Tue, 1 Jul 2025 13:19:59 -0700 Subject: [PATCH 56/61] fix ordering --- aspnetcore/migration/fx-to-core/inc/remote-app-setup.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md index da6a0a354338..47f9fba996a0 100644 --- a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md +++ b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md @@ -7,6 +7,7 @@ monikerRange: '>= aspnetcore-6.0' ms.date: 11/9/2022 ms.topic: article uid: migration/fx-to-core/inc/remote-app-setup +zone_pivot_groups: migration-remote-app-setup --- # Remote app setup @@ -24,6 +25,8 @@ Common scenarios this enables: * [Remote app authentication](xref:migration/fx-to-core/areas/authentication#remote-authenticationn) * [Remote session](xref:migration/fx-to-core/areas/session#remote-app-session-state) +:::zone pivot="manual" + ## Configuration Values To enable the ASP.NET Core app to communicate with the ASP.NET app, it's necessary to make a couple small changes to each app. @@ -163,9 +166,9 @@ To enable proxying from the ASP.NET Core application to the ASP.NET Framework ap > > > -> -> This requires v2.0.1-preview1.25351.3 of the System.Web adapters or later. > ``` +> +> **NOTE**: This requires v2.0.1-preview1.25351.3 of the System.Web adapters or later. 1. Add Aspire orchestration for the ASP.NET Framework application 1. Add a new ASP.NET Core application to the solution and add it to your Aspire orchestration From 8e7f0781acbc3e792eee442992791cd7e10e61a2 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Tue, 1 Jul 2025 14:42:15 -0700 Subject: [PATCH 57/61] version --- aspnetcore/migration/fx-to-core/inc/remote-app-setup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md index 47f9fba996a0..738870f3a6fe 100644 --- a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md +++ b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md @@ -168,7 +168,7 @@ To enable proxying from the ASP.NET Core application to the ASP.NET Framework ap > > ``` > -> **NOTE**: This requires v2.0.1-preview1.25351.3 of the System.Web adapters or later. +> **NOTE**: This requires v2.0.1-preview1.25351.5 of the System.Web adapters or later. 1. Add Aspire orchestration for the ASP.NET Framework application 1. Add a new ASP.NET Core application to the solution and add it to your Aspire orchestration From f1b134b808c33aecc9346151a87d07a7c18011d8 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 14 Jul 2025 10:49:12 -0700 Subject: [PATCH 58/61] updates per feedback --- .../fx-to-core/areas/http-handlers.md | 73 +------------------ .../migration/fx-to-core/areas/session.md | 2 +- .../migration/fx-to-core/inc/overview.md | 5 +- .../fx-to-core/inc/remote-app-setup.md | 5 +- aspnetcore/migration/fx-to-core/inc/start.md | 15 ++-- .../fx-to-core/inc/systemweb-adapters.md | 2 +- aspnetcore/migration/fx-to-core/index.md | 4 +- aspnetcore/migration/fx-to-core/tooling.md | 2 +- 8 files changed, 21 insertions(+), 87 deletions(-) diff --git a/aspnetcore/migration/fx-to-core/areas/http-handlers.md b/aspnetcore/migration/fx-to-core/areas/http-handlers.md index 92e9c196f547..48758c5911fe 100644 --- a/aspnetcore/migration/fx-to-core/areas/http-handlers.md +++ b/aspnetcore/migration/fx-to-core/areas/http-handlers.md @@ -83,77 +83,7 @@ One solution is to branch the pipeline for requests with a given extension, usin Middleware added to the pipeline before the branch will be invoked on all requests; the branch will have no impact on them. -## Loading middleware options using the options pattern - -Some handlers have configuration options that are stored in *Web.config*. However, in ASP.NET Core a new configuration model is used in place of *Web.config*. - -The new [configuration system](xref:fundamentals/configuration/index) gives you these options to solve this: - -* Directly inject the options into the middleware, as shown in the [next section](#loading-middleware-options-through-direct-injection). - -* Use the [options pattern](xref:fundamentals/configuration/options): - -1. Create a class to hold your middleware options, for example: - - [!code-csharp[](sample/Asp.Net.Core/Middleware/MyMiddlewareWithParams.cs?name=snippet_Options)] - -2. Store the option values - - The configuration system allows you to store option values anywhere you want. However, most sites use `appsettings.json`, so we'll take that approach: - - [!code-json[](sample/Asp.Net.Core/appsettings.json?range=1,14-18)] - - *MyMiddlewareOptionsSection* here is a section name. It doesn't have to be the same as the name of your options class. - -3. Associate the option values with the options class - - The options pattern uses ASP.NET Core's dependency injection framework to associate the options type (such as `MyMiddlewareOptions`) with a `MyMiddlewareOptions` object that has the actual options. - - Update your `Startup` class: - - 1. If you're using `appsettings.json`, add it to the configuration builder in the `Startup` constructor: - - [!code-csharp[](./sample/Asp.Net.Core/Startup.cs?name=snippet_Ctor&highlight=5-6)] - - 2. Configure the options service: - - [!code-csharp[](./sample/Asp.Net.Core/Startup.cs?name=snippet_ConfigureServices&highlight=4)] - - 3. Associate your options with your options class: - - [!code-csharp[](./sample/Asp.Net.Core/Startup.cs?name=snippet_ConfigureServices&highlight=6-8)] - -4. Inject the options into your middleware constructor. This is similar to injecting options into a controller. - - [!code-csharp[](./sample/Asp.Net.Core/Middleware/MyMiddlewareWithParams.cs?name=snippet_MiddlewareWithParams&highlight=4,7,10,15-16)] - - The `UseMiddleware` extension method that adds your middleware to the `IApplicationBuilder` takes care of dependency injection. - - This isn't limited to `IOptions` objects. Any other object that your middleware requires can be injected this way. - -## Loading middleware options through direct injection - -The options pattern has the advantage that it creates loose coupling between options values and their consumers. Once you've associated an options class with the actual options values, any other class can get access to the options through the dependency injection framework. There's no need to pass around options values. - -This breaks down though if you want to use the same middleware twice, with different options. For example an authorization middleware used in different branches allowing different roles. You can't associate two different options objects with the one options class. - -The solution is to get the options objects with the actual options values in your `Startup` class and pass those directly to each instance of your middleware. - -1. Add a second key to `appsettings.json` - - To add a second set of options to the `appsettings.json` file, use a new key to uniquely identify it: - - [!code-json[](sample/Asp.Net.Core/appsettings.json?range=1,10-18&highlight=2-5)] - -2. Retrieve options values and pass them to middleware. The `Use...` extension method (which adds your middleware to the pipeline) is a logical place to pass in the option values: - - [!code-csharp[](sample/Asp.Net.Core/Startup.cs?name=snippet_Configure&highlight=20-23)] - -3. Enable middleware to take an options parameter. Provide an overload of the `Use...` extension method (that takes the options parameter and passes it to `UseMiddleware`). When `UseMiddleware` is called with parameters, it passes the parameters to your middleware constructor when it instantiates the middleware object. - - [!code-csharp[](./sample/Asp.Net.Core/Middleware/MyMiddlewareWithParams.cs?name=snippet_Extensions&highlight=9-14)] - - Note how this wraps the options object in an `OptionsWrapper` object. This implements `IOptions`, as expected by the middleware constructor. +For additional details, see the [middleware documentation](xref:fundamentals/middleware/index) for additional ways to use middleware to replace your usage of handlers. ## Migrating to the new HttpContext @@ -168,7 +98,6 @@ public async Task Invoke(HttpContext context) ## Additional resources * [HTTP Handlers and HTTP Modules Overview](/iis/configuration/system.webserver/) -* [Configuration](xref:fundamentals/configuration/index) * [Application Startup](xref:fundamentals/startup) * [Middleware](xref:fundamentals/middleware/index) * [Migrate from ASP.NET Framework HttpContext to ASP.NET Core](http-context.md) diff --git a/aspnetcore/migration/fx-to-core/areas/session.md b/aspnetcore/migration/fx-to-core/areas/session.md index 25e69633cc6b..ee4b951f5690 100644 --- a/aspnetcore/migration/fx-to-core/areas/session.md +++ b/aspnetcore/migration/fx-to-core/areas/session.md @@ -157,7 +157,7 @@ Session support requires explicit activation. Configure it per-route or globally Choose this approach when your migrated components don't need to share session data with your legacy application. -The `Microsoft.Extensions.DependencyInjection.WrappedSessionExtensions.AddWrappedAspNetCoreSession` extension method adds a wraps ASP.NET Core session to work with the adapters. It uses the same backing store as while providing strongly-typed access. +The `Microsoft.Extensions.DependencyInjection.WrappedSessionExtensions.AddWrappedAspNetCoreSession` extension method adds a wrapped ASP.NET Core session to work with the adapters. It uses the same backing store as while providing strongly-typed access. **Configuration for ASP.NET Core:** diff --git a/aspnetcore/migration/fx-to-core/inc/overview.md b/aspnetcore/migration/fx-to-core/inc/overview.md index 1b3ba01adda0..f1612c84ba11 100644 --- a/aspnetcore/migration/fx-to-core/inc/overview.md +++ b/aspnetcore/migration/fx-to-core/inc/overview.md @@ -43,7 +43,10 @@ Once the ASP.NET Core app using YARP is set up, you can start updating routes fr During the migration process, additional services and infrastructure are identified that must be updated to run on .NET Core. Options listed in order of maintainability include: 1. Move the code to shared libraries -1. Link the code in the new project +1. Link the code in the new project from the old project manually + ```xml + + ``` 1. Duplicate the code Eventually, the ASP.NET Core app handles more of the routes than the .NET Framework app: diff --git a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md index 738870f3a6fe..aa21df3514d7 100644 --- a/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md +++ b/aspnetcore/migration/fx-to-core/inc/remote-app-setup.md @@ -153,7 +153,7 @@ To enable proxying from the ASP.NET Core application to the ASP.NET Framework ap ## Setup Aspire orchestration -> [!WARNING] +> [!IMPORTANT] > This is still in preview and not available on NuGet.org, so you must configure your NuGet config to pull libraries from the .NET Libraries daily feed: > > ```xml @@ -170,6 +170,9 @@ To enable proxying from the ASP.NET Core application to the ASP.NET Framework ap > > **NOTE**: This requires v2.0.1-preview1.25351.5 of the System.Web adapters or later. +> [!WARNING] +> **NOTE**: This is a 3rd party component that helps run the application in Aspire. At the current time, ASP.NET Framework applications are not supported directly in Aspire, but this project helps with that. This dependency is intended for build and development, but does not need to be deployed into production. + 1. Add Aspire orchestration for the ASP.NET Framework application 1. Add a new ASP.NET Core application to the solution and add it to your Aspire orchestration 1. Update the AppHost to target Windows as IIS integration requires that: diff --git a/aspnetcore/migration/fx-to-core/inc/start.md b/aspnetcore/migration/fx-to-core/inc/start.md index d729dd2b0737..e1e9c15c7452 100644 --- a/aspnetcore/migration/fx-to-core/inc/start.md +++ b/aspnetcore/migration/fx-to-core/inc/start.md @@ -72,19 +72,18 @@ Review and update your NuGet packages to their latest compatible versions: Update your build tools and project configuration: 1. **Update tools**: Ensure you're using a recent version of MSBuild/Visual Studio -2. **Migrate to SDK-style project files**: Convert your existing project files to the modern SDK-style format. This is essential for .NET Core/.NET 5+ compatibility and provides better tooling support -3. **Review project files**: Consider migrating from `packages.config` to `PackageReference` format if you haven't already in the Web application project -4. **Update build scripts**: Review and update any custom build scripts or CI/CD configurations -5. **Clean up unused references**: Remove any unused assembly references or NuGet packages +1. **Migrate to PackageReference for dependencies**: Consider migrating from `packages.config` to `PackageReference` format if you haven't already in the Web application project +1. **Clean up unused references**: Remove any unused assembly references or NuGet packages +1. **Migrate to SDK-style project files**: Convert your existing project files to the modern SDK-style format. This is essential for compatibility with modern .NET projects and provides better tooling support +1. **Update build scripts**: Review and update any custom build scripts or CI/CD configurations ### Address Code Quality Issues Fix known code quality issues that could complicate migration: -1. **Run static analysis**: Use tools like CodeQL or Visual Studio's built-in analyzers -2. **Fix compiler warnings**: Address any compiler warnings, especially those related to deprecated APIs -3. **Remove dead code**: Clean up unused classes, methods, and other code elements -4. **Update deprecated API usage**: Replace usage of deprecated APIs with their modern equivalents where possible +1. **Fix compiler warnings**: Address any compiler warnings, especially those related to deprecated APIs +1. **Remove dead code**: Clean up unused classes, methods, and other code elements +1. **Update deprecated API usage**: Replace usage of deprecated APIs with their modern equivalents where possible This preparation work will make the library upgrade process much smoother and reduce the likelihood of encountering complex issues during migration. diff --git a/aspnetcore/migration/fx-to-core/inc/systemweb-adapters.md b/aspnetcore/migration/fx-to-core/inc/systemweb-adapters.md index 86d5bd76a1f7..b3df7ed47a06 100644 --- a/aspnetcore/migration/fx-to-core/inc/systemweb-adapters.md +++ b/aspnetcore/migration/fx-to-core/inc/systemweb-adapters.md @@ -19,7 +19,7 @@ Let's take a look at an example using the adapters moving from .NET Framework to ## Packages -* `Microsoft.AspNetCore.SystemWebAdapters`: This package is used in supporting libraries and provide the System.Web APIs you may have taken a dependency on, such as `HttpContext` and others. This package targets .NET Standard 2.0, .NET Framework 4.5+, and .NET 5+. +* `Microsoft.AspNetCore.SystemWebAdapters`: This package is used in supporting libraries and provides the System.Web APIs you may have taken a dependency on, such as `HttpContext` and others. This package targets .NET Standard 2.0, .NET Framework 4.5+, and .NET 5+. * `Microsoft.AspNetCore.SystemWebAdapters.FrameworkServices`: This package only targets .NET Framework and is intended to provide services to ASP.NET Framework applications that may need to provide incremental migrations. This is generally not expected to be referenced from libraries, but rather from the applications themselves. * `Microsoft.AspNetCore.SystemWebAdapters.CoreServices`: This package only targets .NET 6+ and is intended to provide services to ASP.NET Core applications to configure behavior of `System.Web` APIs as well as opting into any behaviors for incremental migration. This is generally not expected to be referenced from libraries, but rather from the applications themselves. * `Microsoft.AspNetCore.SystemWebAdapters.Abstractions`: This package is a supporting package that provides abstractions for services used by both the ASP.NET Core and ASP.NET Framework application such as session state serialization. diff --git a/aspnetcore/migration/fx-to-core/index.md b/aspnetcore/migration/fx-to-core/index.md index 20a00d4fd904..90bc7a6dd89e 100644 --- a/aspnetcore/migration/fx-to-core/index.md +++ b/aspnetcore/migration/fx-to-core/index.md @@ -18,7 +18,7 @@ Your ASP.NET Framework application can successfully move to ASP.NET Core. The ke **For most production applications:** Use the [**incremental migration approach**](xref:migration/fx-to-core/inc/overview) - it's safer, faster to start, and keeps your app running in production throughout the process. -**For smaller applications or greenfield rewrites:** Consider the complete migration approach using our specialized guides. +**For smaller applications:** [Upgrade Assistant](xref:migration/fx-to-core/tooling) has an option for in-place upgrades. This works for small applications, but can quickly become unwieldy for larger projects. ## The incremental approach: Best for most teams @@ -45,4 +45,4 @@ Most non-trivial ASP.NET Framework applications should use incremental migration Before you begin, review the [technical differences between ASP.NET Framework and ASP.NET Core](xref:migration/fx-to-core/areas) to understand key changes that may affect your migration. -:::moniker-end \ No newline at end of file +:::moniker-end diff --git a/aspnetcore/migration/fx-to-core/tooling.md b/aspnetcore/migration/fx-to-core/tooling.md index 1f4718a1a725..7a6d31ba07b6 100644 --- a/aspnetcore/migration/fx-to-core/tooling.md +++ b/aspnetcore/migration/fx-to-core/tooling.md @@ -23,7 +23,7 @@ If your .NET Framework project has supporting libraries in the solution that are 1. Open your ASP.NET Framework solution in Visual Studio. 1. In **Solution Explorer**, right click on the project to upgrade and select **Upgrade**. Select **Side-by-side incremental project upgrade**, which is the only upgrade option. 1. For the upgrade target, select **New project**. -1. Name the project and select the appropriate template: +1. Name the project and select the best fit template (you may add the required services later if you have a solution that uses a mixture of project types): > [!NOTE] > **For MVC projects:** Select **ASP.NET Core MVC** template. From e92b221a813916850dbc22594381994d92ddbf3b Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 14 Jul 2025 11:05:21 -0700 Subject: [PATCH 59/61] consolidate --- .openpublishing.redirection.json | 4 +- .../fx-to-core/areas/authentication.md | 4 +- .../migration/fx-to-core/inc/ab-testing.md | 2 +- .../migration/fx-to-core/inc/overview.md | 69 --------- aspnetcore/migration/fx-to-core/index.md | 132 +++++++++++++++--- .../migration/fx-to-core/{inc => }/start.md | 6 +- aspnetcore/migration/fx-to-core/tooling.md | 4 +- aspnetcore/security/cookie-sharing.md | 2 +- aspnetcore/toc.yml | 6 +- 9 files changed, 129 insertions(+), 100 deletions(-) delete mode 100644 aspnetcore/migration/fx-to-core/inc/overview.md rename aspnetcore/migration/fx-to-core/{inc => }/start.md (97%) diff --git a/.openpublishing.redirection.json b/.openpublishing.redirection.json index ec99d8c26dd1..547eefa798e9 100644 --- a/.openpublishing.redirection.json +++ b/.openpublishing.redirection.json @@ -1032,7 +1032,7 @@ }, { "source_path": "aspnetcore/migration/inc/overview.md", - "redirect_url": "/aspnet/core/migration/fx-to-core/inc/overview", + "redirect_url": "/aspnet/core/migration/fx-to-core/index", "redirect_document_id": false }, { @@ -1057,7 +1057,7 @@ }, { "source_path": "aspnetcore/migration/inc/start.md", - "redirect_url": "/aspnet/core/migration/fx-to-core/inc/start", + "redirect_url": "/aspnet/core/migration/fx-to-core/start", "redirect_document_id": false }, { diff --git a/aspnetcore/migration/fx-to-core/areas/authentication.md b/aspnetcore/migration/fx-to-core/areas/authentication.md index b0b203947bba..cdb1deb314f8 100644 --- a/aspnetcore/migration/fx-to-core/areas/authentication.md +++ b/aspnetcore/migration/fx-to-core/areas/authentication.md @@ -177,7 +177,7 @@ The System.Web adapters' remote authentication feature allows an ASP.NET Core ap ### Remote authentication configuration -There are just a few small code changes needed to enable remote authentication in a solution that's already set up according to the [Getting Started](xref:migration/fx-to-core/inc/overview). +There are just a few small code changes needed to enable remote authentication in a solution that's already set up according to the [Getting Started](xref:migration/fx-to-core/start). First, follow the [remote app setup](xref:migration/fx-to-core/inc/remote-app-setup) instructions to connect the ASP.NET Core and ASP.NET apps. Then, there are just a couple extra extension methods to call to enable remote app authentication. @@ -370,5 +370,5 @@ For other scenarios, the remote authentication approach described previously in * * * -* +* * diff --git a/aspnetcore/migration/fx-to-core/inc/ab-testing.md b/aspnetcore/migration/fx-to-core/inc/ab-testing.md index 02493d20bfdd..76c93029d1c0 100644 --- a/aspnetcore/migration/fx-to-core/inc/ab-testing.md +++ b/aspnetcore/migration/fx-to-core/inc/ab-testing.md @@ -13,7 +13,7 @@ uid: migration/fx-to-core/inc/ab-testing During incremental migration, new endpoints are brought over to a [YARP](https://dotnet.github.io/yarp/) enabled ASP.NET Core app. With the default setup, these endpoints are automatically served for all requests once deployed. In order to test these endpoints, or be able to turn them off if needed, additional setup is needed. -This document describes how to setup a conditional endpoint selection system to enable A/B testing during incremental migration. It assumes a setup as described in [incremental migration overview](xref:migration/fx-to-core/inc/overview) as a starting point. +This document describes how to setup a conditional endpoint selection system to enable A/B testing during incremental migration. It assumes a setup as described in [incremental migration overview](xref:migration/fx-to-core/index) as a starting point. ## Conditional endpoint selection diff --git a/aspnetcore/migration/fx-to-core/inc/overview.md b/aspnetcore/migration/fx-to-core/inc/overview.md deleted file mode 100644 index f1612c84ba11..000000000000 --- a/aspnetcore/migration/fx-to-core/inc/overview.md +++ /dev/null @@ -1,69 +0,0 @@ ---- -title: Incremental ASP.NET to ASP.NET Core update -description: Incremental ASP.NET to ASP.NET Core migration -author: rick-anderson -ms.author: riande -monikerRange: '>= aspnetcore-6.0' -ms.date: 11/9/2022 -ms.topic: article -uid: migration/fx-to-core/inc/overview ---- - - - -# Incremental ASP.NET to ASP.NET Core update - -Updating an app from ASP.NET Framework to ASP.NET Core is non-trivial for the majority of production apps. These apps often incorporate new technologies as they become available and are often composed of many legacy decisions. This article provides guidance and links to tools for updating ASP.NET Framework apps to ASP.NET Core with as little change as possible. - -One of the larger challenges is the pervasive use of throughout a code base. Without the incremental approach and tools, a large scale rewrite is required to remove the dependency. The adapters in [dotnet/systemweb-adapters](https://github.com/dotnet/systemweb-adapters) provide a set of runtime helpers to access the types used in the ASP.NET Framework app in a way that works in ASP.NET Core with minimal changes. - -A complete migration may take considerable effort depending on the size of the app, dependencies, and non-portable APIs used. In order to keep deploying an app to production while working on updating, the best pattern is to follow is the [Strangler Fig pattern](/azure/architecture/patterns/strangler-fig). The *Strangler Fig pattern* allows for continual development on the old system with an incremental approach to replacing specific pieces of functionality with new services. This document describes how to apply the Strangler Fig pattern to an ASP.NET app updating towards ASP.NET Core. - -If you'd like to skip this overview article and get started, see [Get started](xref:migration/fx-to-core/inc/start). - -## App migration to ASP.NET Core - -Before starting the migration, the app targets ASP.NET Framework and runs on Windows with its supporting libraries: - -![Before starting the migration](~/migration/fx-to-core/inc/overview/static/1.png) - -Migration starts by introducing a new app based on ASP.NET Core that becomes the entry point. Incoming requests go to the ASP.NET Core app, which either handles the request or proxies the request to the .NET Framework app via [YARP](https://dotnet.github.io/yarp/). At first, the majority of code providing responses is in the .NET Framework app, but the ASP.NET Core app is now set up to start migrating routes: - -![start updating routes](~/migration/fx-to-core/inc/overview/static/nop.png) - -To migrate business logic that relies on `HttpContext`, the libraries need to be built with `Microsoft.AspNetCore.SystemWebAdapters`. Building the libraries with `SystemWebAdapters` allows: - -* The libraries to be built against .NET Framework, .NET Core, or .NET Standard 2.0. -* Ensures that the libraries are using APIs that are available on both ASP.NET Framework and ASP.NET Core. - -![Microsoft.AspNetCore.SystemWebAdapters](~/migration/fx-to-core/inc/overview/static/sys_adapt.png) - -Once the ASP.NET Core app using YARP is set up, you can start updating routes from ASP.NET Framework to ASP.NET Core. For example, WebAPI or MVC controller action methods,handlers, or some other implementation of a route. If the route is available in the ASP.NET Core app, it's matched and served. - -During the migration process, additional services and infrastructure are identified that must be updated to run on .NET Core. Options listed in order of maintainability include: - -1. Move the code to shared libraries -1. Link the code in the new project from the old project manually - ```xml - - ``` -1. Duplicate the code - -Eventually, the ASP.NET Core app handles more of the routes than the .NET Framework app: - -![the ASP.NET Core app handles more of the routes](~/migration/fx-to-core/inc/overview/static/sys_adapt.png) - -Once the ASP.NET Framework app is no longer needed and deleted: - -* The app is running on the ASP.NET Core app stack, but is still using the adapters. -* The remaining migration work is removing the use of adapters. - -![final pic](~/migration/fx-to-core/inc/overview/static/final.png) - -## Next Steps - -See the [Getting Started](~/migration/fx-to-core/inc/start.md) guide for how to update an existing application to take advantage of this pattern. - -## Additional Resources - -* [Migration Tooling](~/migration/fx-to-core/tooling.md) diff --git a/aspnetcore/migration/fx-to-core/index.md b/aspnetcore/migration/fx-to-core/index.md index 90bc7a6dd89e..b2fcebe3eec0 100644 --- a/aspnetcore/migration/fx-to-core/index.md +++ b/aspnetcore/migration/fx-to-core/index.md @@ -8,7 +8,55 @@ uid: migration/fx-to-core/index --- # Migrate from ASP.NET Framework to ASP.NET Core -:::moniker range=">= aspnetcore-6.0" + + +Updating an app from ASP.NET Framework to ASP.NET Core is non-trivial for the majority of production apps. These apps often incorporate new technologies as they become available and are often composed of many legacy decisions. This guide provides practical approaches and tools for updating ASP.NET Framework apps to ASP.NET Core with as little change as possible. + +## Why migration is challenging + +Migrating from ASP.NET Framework to ASP.NET Core involves several complex challenges that make a complete rewrite difficult and risky for most production applications: + +### Technical Debt Accumulation + +Production applications often have accumulated technical debt over years of development: + +* **System.Web dependencies** - The pervasive use of and associated types throughout a code base. +* **Outdated package dependencies** that may not have .NET Core equivalents +* **Legacy build tools and project configurations** that aren't compatible with modern .NET +* **Deprecated API usage** that needs to be replaced with modern alternatives +* **Compiler warnings and code quality issues** that complicate migration + +### Cross-Cutting Concerns + +Many applications have cross-cutting concerns that span multiple layers and need careful coordination during migration: + +* **Session state management** - ASP.NET Framework and ASP.NET Core have fundamentally different session APIs and behaviors +* **Authentication and authorization** - Different authentication models and APIs between frameworks +* **Logging and monitoring** - Need to maintain consistent logging across both applications during migration +* **Caching strategies** - In-memory, distributed, or output caching needs to be maintained consistently +* **Error handling** - Establishing consistent error handling patterns across both applications +* **Configuration management** - Managing settings that need to be shared or synchronized between applications +* **Dependency injection** - Migrating from various DI containers to ASP.NET Core's built-in container + +### Library Dependency Chains + +Supporting libraries often have complex dependency relationships that require careful upgrade ordering: + +* **Dependency tree complexity** - Libraries must be upgraded in postorder depth-first search ordering +* **Multi-targeting requirements** - Libraries need to support both .NET Framework and .NET Core/.NET Standard +* **API compatibility** - Ensuring libraries work with both framework versions during the migration period +* **Testing complexity** - Each library upgrade requires thorough testing to ensure compatibility + +### Application Architecture Differences + +The fundamental differences between ASP.NET Framework and ASP.NET Core create additional challenges: + +* **Hosting models** - Different approaches to application hosting and lifecycle management +* **Middleware pipeline** - Moving from HTTP modules and handlers to middleware +* **Request processing** - Different request processing models and contexts +* **Performance characteristics** - Different memory usage patterns and performance profiles + +These challenges make incremental migration the preferred approach for most production applications, as it allows teams to address these issues gradually while maintaining a working application in production. ## Start here: Choose your migration path @@ -16,33 +64,85 @@ Your ASP.NET Framework application can successfully move to ASP.NET Core. The ke ### Quick decision guide -**For most production applications:** Use the [**incremental migration approach**](xref:migration/fx-to-core/inc/overview) - it's safer, faster to start, and keeps your app running in production throughout the process. +**Answer these questions to choose your approach:** + +1. **What's your timeline and risk tolerance?** + * Need to stay in production during migration → [Incremental migration](#incremental-migration-best-for-most-teams) + * Can afford a complete rewrite → [Complete rewrite with tooling](#migration-tools-and-resources) + +2. **How large is your application?** + * Small to medium apps → [Upgrade Assistant](xref:migration/fx-to-core/tooling) can help + * Large production apps → [Incremental migration](#incremental-migration-best-for-most-teams) is safer + +3. **Do you have complex dependencies?** + * Heavy use of System.Web → [Incremental migration](#incremental-migration-best-for-most-teams) + * Minimal dependencies → Either approach works -**For smaller applications:** [Upgrade Assistant](xref:migration/fx-to-core/tooling) has an option for in-place upgrades. This works for small applications, but can quickly become unwieldy for larger projects. +## Incremental migration: Best for most teams -## The incremental approach: Best for most teams +Most non-trivial ASP.NET Framework applications should use incremental migration using the [Strangler Fig pattern](/azure/architecture/patterns/strangler-fig). This approach allows for continual development on the old system with an incremental approach to replacing specific pieces of functionality with new services. -Most non-trivial ASP.NET Framework applications should use incremental migration. This approach: +### Benefits of incremental migration -- **Keeps your current app running** while you migrate piece by piece -- **Reduces risk** by moving functionality gradually -- **Delivers value faster** with immediate deployment of migrated components -- **Uses proven tools** like YARP proxy and System.Web adapters +* **Keeps your current app running** while you migrate piece by piece +* **Reduces risk** by moving functionality gradually +* **Delivers value faster** with immediate deployment of migrated components +* **Uses proven tools** like YARP proxy and System.Web adapters -**→ [Start your incremental migration](xref:migration/fx-to-core/inc/overview)** +### How incremental migration works + +Before starting the migration, the app targets ASP.NET Framework and runs on Windows with its supporting libraries: + +![Before starting the migration](~/migration/fx-to-core/inc/overview/static/1.png) + +Migration starts by introducing a new app based on ASP.NET Core that becomes the entry point. Incoming requests go to the ASP.NET Core app, which either handles the request or proxies the request to the .NET Framework app via [YARP](https://dotnet.github.io/yarp/). At first, the majority of code providing responses is in the .NET Framework app, but the ASP.NET Core app is now set up to start migrating routes: + +![start updating routes](~/migration/fx-to-core/inc/overview/static/nop.png) + +To migrate business logic that relies on `HttpContext`, the libraries need to be built with `Microsoft.AspNetCore.SystemWebAdapters`. Building the libraries with `SystemWebAdapters` allows: + +* The libraries to be built against .NET Framework, .NET Core, or .NET Standard 2.0. +* Ensures that the libraries are using APIs that are available on both ASP.NET Framework and ASP.NET Core. + +![Microsoft.AspNetCore.SystemWebAdapters](~/migration/fx-to-core/inc/overview/static/sys_adapt.png) + +Once the ASP.NET Core app using YARP is set up, you can start updating routes from ASP.NET Framework to ASP.NET Core. For example, WebAPI or MVC controller action methods, handlers, or some other implementation of a route. If the route is available in the ASP.NET Core app, it's matched and served. + +During the migration process, additional services and infrastructure are identified that must be updated to run on .NET Core. Options listed in order of maintainability include: + +1. Move the code to shared libraries +1. Link the code in the new project from the old project manually + ```xml + + ``` +1. Duplicate the code + +Eventually, the ASP.NET Core app handles more of the routes than the .NET Framework app: + +![the ASP.NET Core app handles more of the routes](~/migration/fx-to-core/inc/overview/static/sys_adapt.png) + +Once the ASP.NET Framework app is no longer needed and deleted: + +* The app is running on the ASP.NET Core app stack, but is still using the adapters. +* The remaining migration work is removing the use of adapters. + +![final pic](~/migration/fx-to-core/inc/overview/static/final.png) + +**→ [Start your incremental migration](xref:migration/fx-to-core/start)** ## Migration tools and resources ### Automated assistance -- **[.NET Upgrade Assistant](https://dotnet.microsoft.com/platform/upgrade-assistant)** - Command-line tool for initial project conversion -- **[Visual Studio Extension](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.upgradeassistant)** - GUI-based upgrade assistance + +* **[.NET Upgrade Assistant](https://dotnet.microsoft.com/platform/upgrade-assistant)** - Command-line tool for initial project conversion +* **[Visual Studio Extension](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.upgradeassistant)** - GUI-based upgrade assistance ### Comprehensive guides -- **[Porting ASP.NET Apps eBook](https://aka.ms/aspnet-porting-ebook)** - Complete reference guide -- **[eShop Migration Example](/dotnet/architecture/porting-existing-aspnet-apps/example-migration-eshop)** - Real-world case study + +* **[Porting ASP.NET Apps eBook](https://aka.ms/aspnet-porting-ebook)** - Complete reference guide +* **[eShop Migration Example](/dotnet/architecture/porting-existing-aspnet-apps/example-migration-eshop)** - Real-world case study +* **[Migration Tooling](~/migration/fx-to-core/tooling.md)** - Detailed tooling guide ## Changes to technology areas Before you begin, review the [technical differences between ASP.NET Framework and ASP.NET Core](xref:migration/fx-to-core/areas) to understand key changes that may affect your migration. - -:::moniker-end diff --git a/aspnetcore/migration/fx-to-core/inc/start.md b/aspnetcore/migration/fx-to-core/start.md similarity index 97% rename from aspnetcore/migration/fx-to-core/inc/start.md rename to aspnetcore/migration/fx-to-core/start.md index e1e9c15c7452..34361758c82f 100644 --- a/aspnetcore/migration/fx-to-core/inc/start.md +++ b/aspnetcore/migration/fx-to-core/start.md @@ -6,13 +6,13 @@ ms.author: riande monikerRange: '>= aspnetcore-6.0' ms.date: 11/9/2022 ms.topic: article -uid: migration/fx-to-core/inc/start +uid: migration/fx-to-core/start --- # Get started with incremental ASP.NET to ASP.NET Core migration > [!IMPORTANT] -> **Before you begin**: This article assumes you have read the [Incremental ASP.NET to ASP.NET Core migration overview](xref:migration/fx-to-core/inc/overview). If you haven't read it yet, please start there to understand the concepts, approach, and benefits of incremental migration. +> **Before you begin**: This article assumes you have read the [ASP.NET Core migration overview](xref:migration/fx-to-core/index). If you haven't read it yet, please start there to understand the concepts, approach, and benefits of incremental migration. For a large migration, we recommend setting up a ASP.NET Core app that proxies to the original .NET Framework app. The new proxy enabled app is shown in the following image: @@ -24,7 +24,7 @@ This article provides the practical steps to proceed with an incremental migrati Before starting your incremental migration, ensure you have: -1. **Read the overview**: [Incremental ASP.NET to ASP.NET Core migration](xref:migration/fx-to-core/inc/overview) +1. **Read the overview**: [Incremental ASP.NET to ASP.NET Core migration](xref:migration/fx-to-core/index) 2. **A working ASP.NET Framework application** that you want to migrate 3. **Visual Studio 2022** with the latest updates 4. **.NET 8 or later SDK** installed diff --git a/aspnetcore/migration/fx-to-core/tooling.md b/aspnetcore/migration/fx-to-core/tooling.md index 7a6d31ba07b6..566c194cb99e 100644 --- a/aspnetcore/migration/fx-to-core/tooling.md +++ b/aspnetcore/migration/fx-to-core/tooling.md @@ -8,7 +8,7 @@ uid: migration/fx-to-core/tooling --- # Use tooling to help migrate ASP.NET Framework to ASP.NET Core -This article shows how to upgrade ASP.NET Framework applications (MVC, Web API, and Web Forms) to ASP.NET Core using the Visual Studio [.NET Upgrade Assistant](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.upgradeassistant) and the [incremental update](xref:migration/fx-to-core/inc/overview) approach. +This article shows how to upgrade ASP.NET Framework applications (MVC, Web API, and Web Forms) to ASP.NET Core using the Visual Studio [.NET Upgrade Assistant](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.upgradeassistant) and the [incremental update](xref:migration/fx-to-core/overview) approach. > [!WARNING] @@ -16,7 +16,7 @@ This article shows how to upgrade ASP.NET Framework applications (MVC, Web API, ## Prerequisites -If your .NET Framework project has supporting libraries in the solution that are required, they should be upgraded to .NET Standard 2.0, if possible. For more information, see [Upgrade supporting libraries](xref:migration/fx-to-core/inc/start#upgrade-supporting-libraries). +If your .NET Framework project has supporting libraries in the solution that are required, they should be upgraded to .NET Standard 2.0, if possible. For more information, see [Upgrade supporting libraries](xref:migration/fx-to-core/start#upgrade-supporting-libraries). 1. Install the [.NET Upgrade Assistant](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.upgradeassistant) Visual Studio extension. diff --git a/aspnetcore/security/cookie-sharing.md b/aspnetcore/security/cookie-sharing.md index 23b64cedceaa..892489eb1169 100644 --- a/aspnetcore/security/cookie-sharing.md +++ b/aspnetcore/security/cookie-sharing.md @@ -83,7 +83,7 @@ When the Identity schema is different among apps, usually because apps are using ## Share authentication cookies between ASP.NET 4.x and ASP.NET Core apps -ASP.NET 4.x apps that use Microsoft.Owin Cookie Authentication Middleware can be configured to generate authentication cookies that are compatible with the ASP.NET Core Cookie Authentication Middleware. This can be useful if a web application consists of both ASP.NET 4.x apps and ASP.NET Core apps that must share a single sign-on experience. A specific example of such a scenario is [incrementally migrating](xref:migration/fx-to-core/inc/overview) a web app from ASP.NET to ASP.NET Core. In such scenarios, it's common for some parts of an app to be served by the original ASP.NET app while others are served by the new ASP.NET Core app. Users should only have to sign in once, though. This can be accomplished by either of the following approaches: +ASP.NET 4.x apps that use Microsoft.Owin Cookie Authentication Middleware can be configured to generate authentication cookies that are compatible with the ASP.NET Core Cookie Authentication Middleware. This can be useful if a web application consists of both ASP.NET 4.x apps and ASP.NET Core apps that must share a single sign-on experience. A specific example of such a scenario is [incrementally migrating](xref:migration/fx-to-core/index) a web app from ASP.NET to ASP.NET Core. In such scenarios, it's common for some parts of an app to be served by the original ASP.NET app while others are served by the new ASP.NET Core app. Users should only have to sign in once, though. This can be accomplished by either of the following approaches: * Using the System.Web adapters' [remote authentication](xref:migration/fx-to-core/areas/authentication#remote-authentication) feature, which uses the ASP.NET app to sign users in. * Configuring the ASP.NET app to use Microsoft.Owin Cookie Authentication Middleware so that authentication cookies are shared with the ASP.NET Core app. diff --git a/aspnetcore/toc.yml b/aspnetcore/toc.yml index 9a9c024e8617..dc49c844e482 100644 --- a/aspnetcore/toc.yml +++ b/aspnetcore/toc.yml @@ -2098,17 +2098,15 @@ items: items: - name: Overview uid: migration/fx-to-core/index + - name: Get started + uid: migration/fx-to-core/start - name: Tooling uid: migration/fx-to-core/tooling - name: Incremental migration displayName: migrate, migration items: - - name: Overview - uid: migration/fx-to-core/inc/overview - name: System.Web adapters uid: migration/fx-to-core/systemweb-adapters - - name: Get started - uid: migration/fx-to-core/inc/start - name: Remote app setup uid: migration/fx-to-core/inc/remote-app-setup - name: A/B Testing endpoints From d7380c59afd46e5e92e9927d0ae53e9b699d0b11 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 14 Jul 2025 11:09:19 -0700 Subject: [PATCH 60/61] warn --- aspnetcore/migration/fx-to-core/tooling.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aspnetcore/migration/fx-to-core/tooling.md b/aspnetcore/migration/fx-to-core/tooling.md index 566c194cb99e..b781ab0bc350 100644 --- a/aspnetcore/migration/fx-to-core/tooling.md +++ b/aspnetcore/migration/fx-to-core/tooling.md @@ -8,7 +8,7 @@ uid: migration/fx-to-core/tooling --- # Use tooling to help migrate ASP.NET Framework to ASP.NET Core -This article shows how to upgrade ASP.NET Framework applications (MVC, Web API, and Web Forms) to ASP.NET Core using the Visual Studio [.NET Upgrade Assistant](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.upgradeassistant) and the [incremental update](xref:migration/fx-to-core/overview) approach. +This article shows how to upgrade ASP.NET Framework applications (MVC, Web API, and Web Forms) to ASP.NET Core using the Visual Studio [.NET Upgrade Assistant](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.upgradeassistant) and the [incremental update](xref:migration/fx-to-core/index) approach. > [!WARNING] From 869d01154d67e25e1f374509aeb00c0802f1a9d1 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Mon, 14 Jul 2025 11:18:05 -0700 Subject: [PATCH 61/61] index --- aspnetcore/migration/fx-to-core/index.md | 83 ++++-------------------- 1 file changed, 13 insertions(+), 70 deletions(-) diff --git a/aspnetcore/migration/fx-to-core/index.md b/aspnetcore/migration/fx-to-core/index.md index b2fcebe3eec0..bb0d7e4d5562 100644 --- a/aspnetcore/migration/fx-to-core/index.md +++ b/aspnetcore/migration/fx-to-core/index.md @@ -58,6 +58,8 @@ The fundamental differences between ASP.NET Framework and ASP.NET Core create ad These challenges make incremental migration the preferred approach for most production applications, as it allows teams to address these issues gradually while maintaining a working application in production. +For documentation around important areas that have changed, see the associated topics available at + ## Start here: Choose your migration path Your ASP.NET Framework application can successfully move to ASP.NET Core. The key is choosing the right approach for your specific situation. @@ -67,82 +69,23 @@ Your ASP.NET Framework application can successfully move to ASP.NET Core. The ke **Answer these questions to choose your approach:** 1. **What's your timeline and risk tolerance?** - * Need to stay in production during migration → [Incremental migration](#incremental-migration-best-for-most-teams) - * Can afford a complete rewrite → [Complete rewrite with tooling](#migration-tools-and-resources) + * Need to stay in production during migration → [Incremental migration](#incremental-migration) + * Can afford a complete rewrite → [In place migration](#in-place-migration) 2. **How large is your application?** - * Small to medium apps → [Upgrade Assistant](xref:migration/fx-to-core/tooling) can help - * Large production apps → [Incremental migration](#incremental-migration-best-for-most-teams) is safer + * Small to medium apps → [In place migration](#in-place-migration) + * Large production apps → [Incremental migration](#incremental-migration) is safer 3. **Do you have complex dependencies?** - * Heavy use of System.Web → [Incremental migration](#incremental-migration-best-for-most-teams) - * Minimal dependencies → Either approach works - -## Incremental migration: Best for most teams - -Most non-trivial ASP.NET Framework applications should use incremental migration using the [Strangler Fig pattern](/azure/architecture/patterns/strangler-fig). This approach allows for continual development on the old system with an incremental approach to replacing specific pieces of functionality with new services. - -### Benefits of incremental migration - -* **Keeps your current app running** while you migrate piece by piece -* **Reduces risk** by moving functionality gradually -* **Delivers value faster** with immediate deployment of migrated components -* **Uses proven tools** like YARP proxy and System.Web adapters - -### How incremental migration works - -Before starting the migration, the app targets ASP.NET Framework and runs on Windows with its supporting libraries: - -![Before starting the migration](~/migration/fx-to-core/inc/overview/static/1.png) - -Migration starts by introducing a new app based on ASP.NET Core that becomes the entry point. Incoming requests go to the ASP.NET Core app, which either handles the request or proxies the request to the .NET Framework app via [YARP](https://dotnet.github.io/yarp/). At first, the majority of code providing responses is in the .NET Framework app, but the ASP.NET Core app is now set up to start migrating routes: - -![start updating routes](~/migration/fx-to-core/inc/overview/static/nop.png) - -To migrate business logic that relies on `HttpContext`, the libraries need to be built with `Microsoft.AspNetCore.SystemWebAdapters`. Building the libraries with `SystemWebAdapters` allows: - -* The libraries to be built against .NET Framework, .NET Core, or .NET Standard 2.0. -* Ensures that the libraries are using APIs that are available on both ASP.NET Framework and ASP.NET Core. - -![Microsoft.AspNetCore.SystemWebAdapters](~/migration/fx-to-core/inc/overview/static/sys_adapt.png) - -Once the ASP.NET Core app using YARP is set up, you can start updating routes from ASP.NET Framework to ASP.NET Core. For example, WebAPI or MVC controller action methods, handlers, or some other implementation of a route. If the route is available in the ASP.NET Core app, it's matched and served. - -During the migration process, additional services and infrastructure are identified that must be updated to run on .NET Core. Options listed in order of maintainability include: - -1. Move the code to shared libraries -1. Link the code in the new project from the old project manually - ```xml - - ``` -1. Duplicate the code - -Eventually, the ASP.NET Core app handles more of the routes than the .NET Framework app: - -![the ASP.NET Core app handles more of the routes](~/migration/fx-to-core/inc/overview/static/sys_adapt.png) - -Once the ASP.NET Framework app is no longer needed and deleted: - -* The app is running on the ASP.NET Core app stack, but is still using the adapters. -* The remaining migration work is removing the use of adapters. - -![final pic](~/migration/fx-to-core/inc/overview/static/final.png) - -**→ [Start your incremental migration](xref:migration/fx-to-core/start)** - -## Migration tools and resources - -### Automated assistance + * Unknown or out of date dependencies → [Incremental migration](#incremental-migration) + * Heavy use of System.Web → [Incremental migration](#incremental-migration) + * Minimal dependencies → [In place migration](#in-place-migration) -* **[.NET Upgrade Assistant](https://dotnet.microsoft.com/platform/upgrade-assistant)** - Command-line tool for initial project conversion -* **[Visual Studio Extension](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.upgradeassistant)** - GUI-based upgrade assistance -### Comprehensive guides +## Incremental Migration -* **[Porting ASP.NET Apps eBook](https://aka.ms/aspnet-porting-ebook)** - Complete reference guide -* **[eShop Migration Example](/dotnet/architecture/porting-existing-aspnet-apps/example-migration-eshop)** - Real-world case study -* **[Migration Tooling](~/migration/fx-to-core/tooling.md)** - Detailed tooling guide +Incremental migration is an implementation of the Strangler Fig pattern and is best for larger projects or projects that need to continue to stay in production throughout a migration. See to get started migration an application incrementally. -## Changes to technology areas +## In place migration -Before you begin, review the [technical differences between ASP.NET Framework and ASP.NET Core](xref:migration/fx-to-core/areas) to understand key changes that may affect your migration. +In place migration can work for sufficiently small applications. If possible, this allows for a quick replacement of the application. However, small issues may be compounded if you decide to do an in place migration. See for how Upgrade Assistant can help with an in place migration.