--- title: Migrate from ASP.NET Core 7.0 to 8.0 author: rick-anderson description: Learn how to migrate an ASP.NET Core 6 project to ASP.NET Core 8.0 ms.author: riande ms.date: 10/13/2022 uid: migration/70-to-80 --- # Migrate from ASP.NET Core in .NET 7 to .NET 8 This article explains how to update an existing ASP.NET Core 7.0 project to ASP.NET Core 8.0. ## Prerequisites # [Visual Studio](#tab/visual-studio) [!INCLUDE[](~/includes/net-prereqs-vs-8.0.md)] # [Visual Studio Code](#tab/visual-studio-code) [!INCLUDE[](~/includes/net-prereqs-vsc-8.0.md)] # [Visual Studio for Mac](#tab/visual-studio-mac) [!INCLUDE[](~/includes/net-prereqs-mac-8.0.md)] --- ## Update the .NET SDK version in `global.json` If you rely on a [`global.json`](/dotnet/core/tools/global-json) file to target a specific .NET Core SDK version, update the `version` property to the .NET 8.0 SDK version that's installed. For example: ```diff { "sdk": { - "version": "7.0.100" + "version": "8.0.100" } } ``` ## Update the target framework Update the project file's [Target Framework Moniker (TFM)](/dotnet/standard/frameworks) to `net8.0`: ```diff - net7.0 + net8.0 ``` ## Update package references In the project file, update each [`Microsoft.AspNetCore.*`](https://www.nuget.org/packages?q=Microsoft.AspNetCore.*), [`Microsoft.EntityFrameworkCore.*`](https://www.nuget.org/packages?q=Microsoft.EntityFrameworkCore.*), [`Microsoft.Extensions.*`](https://www.nuget.org/packages?q=Microsoft.Extensions.*), and [`System.Net.Http.Json`](https://www.nuget.org/packages/System.Net.Http.Json) package reference's `Version` attribute to 8.00 or later. For example: ```diff - - - - + + + + ``` ## Blazor The following migration scenarios are covered: * [Update a Blazor Server app](#update-a-blazor-server-app) * [Adopt all Blazor Web App conventions](#adopt-all-blazor-web-app-conventions) * [Convert a Blazor Server app into a Blazor Web App](#convert-a-blazor-server-app-into-a-blazor-web-app) * [Update a Blazor WebAssembly app](#update-a-blazor-webassembly-app) * [Convert a hosted Blazor WebAssembly app into a Blazor Web App](#convert-a-hosted-blazor-webassembly-app-into-a-blazor-web-app) * [Update service and endpoint option configuration](#update-service-and-endpoint-option-configuration) * [Drop Blazor Server with Yarp routing workaround](#drop-blazor-server-with-yarp-routing-workaround) * [Migrate `CascadingValue` components in layout components](#migrate-cascadingvalue-components-in-layout-components) * [Migrate the `BlazorEnableCompression` MSBuild property](#migrate-the-blazorenablecompression-msbuild-property) * [Migrate the `` component to cascading authentication state services](#migrate-the-cascadingauthenticationstate-component-to-cascading-authentication-state-services) * [*New article*: HTTP caching issues during migration](#new-article-on-http-caching-issues) * [*New article*: New article on class libraries with static server-side rendering (static SSR)](#new-article-on-class-libraries-with-static-server-side-rendering-static-ssr) * [Discover components from additional assemblies](#discover-components-from-additional-assemblies) * [Drop `[Parameter]` attribute when the parameter is supplied from a query string](#drop-parameter-attribute-when-the-parameter-is-supplied-from-a-query-string) * [Blazor Server script fallback policy authorization](#blazor-server-script-fallback-policy-authorization) For guidance on adding Blazor support to an ASP.NET Core app, see . ### Update a Blazor Server app We recommend using Blazor Web Apps in .NET 8, but Blazor Server is supported. To continue using Blazor Server with .NET 8, follow the guidance in the first three sections of this article: * [Update the .NET SDK version in `global.json`](#update-the-net-sdk-version-in-globaljson) * [Update the target framework](#update-the-target-framework) * [Update package references](#update-package-references) New Blazor features introduced for Blazor Web Apps aren't available to a Blazor Server app updated to run under .NET 8. If you wish to adopt the new .NET 8 Blazor features, follow the guidance in either of the following sections: * [Adopt all Blazor Web App conventions](#adopt-all-blazor-web-app-conventions) * [Convert a Blazor Server app into a Blazor Web App](#convert-a-blazor-server-app-into-a-blazor-web-app) ### Adopt all Blazor Web App conventions To optionally adopt all of the new Blazor Web App conventions, we recommend the following process: * Create a new app from the Blazor Web App project template. For more information, see . * Move the your app's components and code to the new Blazor Web App app, making modifications to adopt new features. * Update the layout and styles of the Blazor Web App. New .NET 8 features are covered in . When updating an app from .NET 6 or earlier, see the migration and release notes (*What's new* articles) for intervening releases. ### Convert a Blazor Server app into a Blazor Web App Blazor Server apps are supported in .NET 8 without any code changes. Use the following guidance to convert a Blazor Server app into an equivalent .NET 8 Blazor Web App, which makes all of the [new .NET 8 features](xref:aspnetcore-8#blazor) available. > [!IMPORTANT] > This section focuses on the minimal changes required to convert a .NET 7 Blazor Server app into a .NET 8 Blazor Web App. To adopt all of the new Blazor Web App conventions, follow the guidance in the [Adopt all Blazor Web App conventions](#adopt-all-blazor-web-app-conventions) section. 1. Follow the guidance in the first three sections of this article: * [Update the .NET SDK version in `global.json`](#update-the-net-sdk-version-in-globaljson) * [Update the target framework](#update-the-target-framework) * [Update package references](#update-package-references) 1. Move the contents of the `App` component (`App.razor`) to a new `Routes` component file (`Routes.razor`) added to the project's root folder. Leave the empty `App.razor` file in the app in the project's root folder. 1. Add an entry to the `_Imports.razor` file to make shorthand render modes available to the app: ```razor @using static Microsoft.AspNetCore.Components.Web.RenderMode ``` 1. Move the content in the `_Host` page (`Pages/_Host.cshtml`) to the empty `App.razor` file. Proceed to make the following changes to the `App` component. > [!NOTE] > In the following example, the project's namespace is `BlazorServerApp`. Adjust the namespace to match your project. Remove the following lines from the top of the file: ```diff - @page "/" - @using Microsoft.AspNetCore.Components.Web - @namespace BlazorServerApp.Pages - @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers ``` Replace the preceding lines with a line that injects an instance: ```razor @inject IHostEnvironment Env ``` Remove the tilde (`~`) from the `href` of the `` tag and replace with the base path for your app: ```diff - + ``` Remove the Component Tag Helper for the `HeadOutlet` component and replace it with the `HeadOutlet` component. Remove the following line: ```diff - ``` Replace the preceding line with the following: ```razor ``` Remove the Component Tag Helper for the `App` component and replace it with the `Routes` component. Remove the following line: ```diff - ``` Replace the preceding line with the following: ```razor ``` > [!NOTE] > The preceding configuration assumes that the app's components adopt interactive server rendering. For more information, including how to adopt static server-side rendering (SSR), see . Remove the Environment Tag Helpers for error UI and replace them with the following Razor markup. Remove the following lines: ```diff - - An error has occurred. This application may no longer respond until reloaded. - - - An unhandled exception has occurred. See browser dev tools for details. - ``` Replace the preceding lines with the following: ```razor @if (Env.IsDevelopment()) { An unhandled exception has occurred. See browser dev tools for details. } else { An error has occurred. This app may no longer respond until reloaded. } ``` Change the Blazor script from `blazor.server.js` to `blazor.web.js`: ```diff - + ``` 1. Delete the `Pages/_Host.cshtml` file. 1. Update `Program.cs`: > [!NOTE] > In the following example, the project's namespace is `BlazorServerApp`. Adjust the namespace to match your project. Add a `using` statement to the top of the file for the project's namespace: ```csharp using BlazorServerApp; ``` Replace `AddServerSideBlazor` with `AddRazorComponents` and a chained call to `AddInteractiveServerComponents`. Remove the following line: ```diff - builder.Services.AddServerSideBlazor(); ``` Replace the preceding line with Razor component and interactive server component services. Calling `AddRazorComponents` adds antiforgery services (`AddAntiforgery`) by default. ```csharp builder.Services.AddRazorComponents() .AddInteractiveServerComponents(); ``` Remove the following line: ```diff - app.MapBlazorHub(); ``` Replace the preceding line with a call to `MapRazorComponents`, supplying the `App` component as the root component type, and add a chained call to `AddInteractiveServerRenderMode`: ```csharp app.MapRazorComponents() .AddInteractiveServerRenderMode(); ``` Remove the following line: ```diff - app.MapFallbackToPage("/_Host"); ``` Add [Antiforgery Middleware](xref:blazor/security/index#antiforgery-support) to the request processing pipeline after the call to `app.UseRouting`. If there are calls to `app.UseRouting` and `app.UseEndpoints`, the call to `app.UseAntiforgery` must go between them. A call to `app.UseAntiforgery` must be placed after calls to `app.UseAuthentication` and `app.UseAuthorization`. There's no need to add antiforgery services (`builder.Services.AddAntiforgery()`), as they're added automatically by `AddRazorComponents`, which was covered earlier. ```csharp app.UseAntiforgery(); ``` 1. If the Blazor Server app was configured to disable prerendering, you can continue to disable prerendering for the updated app. In the `App` component, change the value assigned to the `@rendermode` Razor directive attributes for the `HeadOutlet` and `Routes` components. Change the value of the `@rendermode` directive attribute for both the `HeadOutlet` and `Routes` components to disable prerendering: ```diff - @rendermode="InteractiveServer" + @rendermode="new InteractiveServerRenderMode(prerender: false)" ``` For more information, see . ### Update a Blazor WebAssembly app Follow the guidance in the first three sections of this article: * [Update the .NET SDK version in `global.json`](#update-the-net-sdk-version-in-globaljson) * [Update the target framework](#update-the-target-framework) * [Update package references](#update-package-references) ### Convert a hosted Blazor WebAssembly app into a Blazor Web App Blazor WebAssembly apps are supported in .NET 8 without any code changes. Use the following guidance to convert an ASP.NET Core hosted Blazor WebAssembly app into an equivalent .NET 8 Blazor Web App, which makes all of the [new .NET 8 features](xref:aspnetcore-8#blazor) available. > [!IMPORTANT] > This section focuses on the minimal changes required to convert a .NET 7 ASP.NET Core hosted Blazor WebAssembly app into a .NET 8 Blazor Web App. To adopt all of the new Blazor Web App conventions, follow the guidance in the [Adopt all Blazor Web App conventions](#adopt-all-blazor-web-app-conventions) section. 1. Follow the guidance in the first three sections of this article: * [Update the .NET SDK version in `global.json`](#update-the-net-sdk-version-in-globaljson) * [Update the target framework](#update-the-target-framework) * [Update package references](#update-package-references) > [!IMPORTANT] > Using the preceding guidance, update the `.Client`, `.Server`, and `.Shared` projects of the solution. 1. In the `.Client` project file (`.csproj`), add the following MSBuild properties: ```xml true Default ``` Also in the `.Client` project file, remove the [`Microsoft.AspNetCore.Components.WebAssembly.DevServer`](https://www.nuget.org/packages/Microsoft.AspNetCore.Components.WebAssembly.DevServer) package reference: ```diff - ``` 1. Move the file content from the `.Client/wwwroot/index.html` file to a new `App` component file (`App.razor`) created at the root of the `.Server` project. After you move the file's contents, delete the `index.html` file. Rename `App.razor` in the `.Client` project to `Routes.razor`. In `Routes.razor`, update the value of the `AppAssembly` attribute to `typeof(Program).Assembly`. 1. In the `.Client` project, add an entry to the `_Imports.razor` file to make shorthand render modes available to the app: ```razor @using static Microsoft.AspNetCore.Components.Web.RenderMode ``` Make a copy of the `.Client` project's `_Imports.razor` file and add it to the `.Server` project. 1. Make the following changes to the `App.razor` file: Replace the website's default website title (`...`) with a `HeadOutlet` component. Note the website title for use later and remove the title tags and title: ```diff - ... ``` Where you removed the title, place a `HeadOutlet` component assigning the Interactive WebAssembly render mode (prerendering disabled): ```razor ``` Change the [CSS style bundle](xref:blazor/components/css-isolation#css-isolation-bundling): ```diff - + ``` Placeholders in the preceding code: * `{CLIENT PROJECT ASSEMBLY NAME}`: Client project assembly name. Example: `BlazorSample.Client` * `{SERVER PROJECT ASSEMBLY NAME}`: Server project assembly name. Example: `BlazorSample.Server` Locate following `
...
` HTML markup: ```diff -
- ... -
``` Replace the preceding `
...
` HTML markup with the `Routes` component using the Interactive WebAssembly render mode (prerendering disabled): ```razor ``` Update the `blazor.webassembly.js` script to `blazor.web.js`: ```diff - + ``` 1. Open the `.Client` project's layout file (`.Client/Shared/MainLayout.razor`) and add a `PageTitle` component with the website's default title (`{TITLE}` placeholder): ```razor {TITLE} ``` > [!NOTE] > Other layout files should also receive a `PageTitle` component with the default website title. > > For more information, see . 1. Remove the following lines from `.Client/Program.cs`: ```diff - builder.RootComponents.Add("#app"); - builder.RootComponents.Add("head::after"); ``` 1. Update `.Server/Program.cs`: Add Razor component and interactive WebAssembly component services to the project. Call `AddRazorComponents` with a chained call to `AddInteractiveWebAssemblyComponents`. Calling `AddRazorComponents` adds antiforgery services (`AddAntiforgery`) by default. ```csharp builder.Services.AddRazorComponents() .AddInteractiveWebAssemblyComponents(); ``` Add [Antiforgery Middleware](xref:blazor/security/index#antiforgery-support) to the request processing pipeline. Place the following code: * After the call to `app.UseRouting`. * If there are calls to `app.UseRouting` and `app.UseEndpoints`, the call to `app.UseAntiforgery` must go between them. * The call to `app.UseAntiforgery` must be placed after a call to `app.UseAuthorization`, if present. * There's no need to add antiforgery services (`builder.Services.AddAntiforgery()`), as they're added automatically by `AddRazorComponents`, which was covered earlier. ```csharp app.UseAntiforgery(); ``` Remove the following line: ```diff - app.UseBlazorFrameworkFiles(); ``` Remove the following line: ```diff - app.MapFallbackToFile("index.html"); ``` Replace the preceding line with a call to `MapRazorComponents`, supplying the `App` component as the root component type, and add chained calls to `AddInteractiveWebAssemblyRenderMode` and `AddAdditionalAssemblies`: ```csharp app.MapRazorComponents() .AddInteractiveWebAssemblyRenderMode() .AddAdditionalAssemblies(typeof({CLIENT APP NAMESPACE}._Imports).Assembly); ``` In the preceding example, the `{CLIENT APP NAMESPACE}` placeholder is the namespace of the `.Client` project (for example, `HostedBlazorApp.Client`). 1. Run the solution from the `.Server` project: For Visual Studio, confirm that the `.Server` project is selected in **Solution Explorer** when running the app. If using the .NET CLI, run the project from the `.Server` project's folder. ### Update service and endpoint option configuration With the release of Blazor Web Apps in .NET 8, Blazor service and endpoint option configuration is updated with the introduction of new API for interactive component services and component endpoint configuration. Updated configuration guidance appears in the following locations: * [Setting and reading the app's environment](xref:blazor/fundamentals/environments): Contains updated guidance, especially in the section titled *Read the environment client-side in a Blazor Web App*. * [Server-side circuit handler options](xref:blazor/fundamentals/signalr?view=aspnetcore-8.0&preserve-view=true#server-side-circuit-handler-options): Covers new Blazor-SignalR circuit and hub options configuration. * [Render Razor components from JavaScript](xref:blazor/components/js-spa-frameworks?view=aspnetcore-8.0&preserve-view=true#render-razor-components-from-javascript): Covers dynamic component registration with . * [Blazor custom elements: Blazor Web App registration](xref:blazor/components/js-spa-frameworks?view=aspnetcore-8.0&preserve-view=true#blazor-web-app-registration): Covers root component custom element registration with `RegisterCustomElement`. * [Prefix for Blazor WebAssembly assets](xref:blazor/fundamentals/static-files?view=aspnetcore-8.0&preserve-view=true#prefix-for-blazor-webassembly-assets): Covers control of the path string that indicates the prefix for Blazor WebAssembly assets. * [Temporary redirection URL validity duration](xref:blazor/security/server/index?view=aspnetcore-8.0&preserve-view=true#temporary-redirection-url-validity-duration): Covers control of the lifetime of data protection validity for temporary redirection URLs emitted by Blazor server-side rendering. * [Detailed errors](xref:blazor/fundamentals/handle-errors?view=aspnetcore-8.0&preserve-view=true#detailed-errors-for-razor-component-server-side-rendering): Covers enabling detailed errors for Razor component server-side rendering. * [Prerendering configuration](xref:blazor/components/render-modes?view=aspnetcore-8.0&preserve-view=true#prerendering): Prerendering is enabled by default for Blazor Web Apps. Follow this link for guidance on how to disable prerendering if you have special circumstances that require an app to disable prerendering. * [Form binding options](xref:blazor/forms/binding?view=aspnetcore-8.0&preserve-view=true#additional-binding-options): Covers form binding options configuration. ### Drop Blazor Server with Yarp routing workaround If you previously followed the guidance in for migrating a Blazor Server app with Yarp to .NET 6 or .NET 7, you can reverse the workaround steps that you took when following the article's guidance. Routing and deep linking for Blazor Server with Yarp work correctly in .NET 8. ### Migrate `CascadingValue` components in layout components Cascading parameters don't pass data across render mode boundaries, and layouts are statically rendered in otherwise interactive apps. Therefore, apps that seek to use cascading parameters in interactively rendered components won't be able to cascade the values from a layout. The two approaches for migration are: * (*Recommended*) Pass the state as a root-level cascading value. For more information, see [Root-level cascading values](xref:blazor/components/cascading-values-and-parameters#root-level-cascading-values). * Wrap the router in the `Routes` component with the [`CascadingValue`](xref:Microsoft.AspNetCore.Components.CascadingValue%601) component and make the `Routes` component interactively rendered. For an example, see [`CascadingValue` component](xref:blazor/components/cascading-values-and-parameters?view=aspnetcore-8.0&preserve-view=true#cascadingvalue-component). For more information, see [Cascading values/parameters and render mode boundaries](xref:blazor/components/cascading-values-and-parameters?view=aspnetcore-8.0&preserve-view=true#cascading-valuesparameters-and-render-mode-boundaries). ### Migrate the `BlazorEnableCompression` MSBuild property For Blazor WebAssembly apps that disable compression and target .NET 7 or earlier but are built with the .NET 8 SDK, the `BlazorEnableCompression` MSBuild property has changed to `CompressionEnabled`: ```diff - false + false ``` When using the .NET CLI publish command, use the new property: ```dotnetcli dotnet publish -p:CompressionEnabled=false ``` For more information, see the following resources: * [Static Web Assets Compression Flag Breaking Change (dotnet/announcements #283)](https://github.com/dotnet/announcements/issues/283) * ### Migrate the `` component to cascading authentication state services In .NET 7 or earlier, the component is wrapped around some part of the UI tree, for example around the Blazor router, to provide cascading authentication state: ```razor ... ``` In .NET 8, don't use the component: ```diff - ... - ``` Instead, add cascading authentication state services to the service collection by calling in the `Program` file: ```csharp builder.Services.AddCascadingAuthenticationState(); ``` For more information, see the following resources: * *ASP.NET Core Blazor authentication and authorization* article * [`AuthenticationStateProvider` service](xref:blazor/security/index#authenticationstateprovider-service) * [Expose the authentication state as a cascading parameter](xref:blazor/security/index#expose-the-authentication-state-as-a-cascading-parameter) * [Customize unauthorized content with the Router component](xref:blazor/security/index#customize-unauthorized-content-with-the-router-component) * ### New article on HTTP caching issues We've added a new article that discusses some of the common HTTP caching issues that can occur when upgrading Blazor apps across major versions and how to address HTTP caching issues. For more information, see . ### New article on class libraries with static server-side rendering (static SSR) We've added a new article that discusses component library authorship in Razor class libraries (RCLs) with static server-side rendering (static SSR). For more information, see . ### Discover components from additional assemblies When migrating from a Blazor Server app to a Blazor Web App, access the guidance in if the app uses routable components from additional assemblies, such as component class libraries. ### Drop `[Parameter]` attribute when the parameter is supplied from a query string The `[Parameter]` attribute is no longer required when supplying a parameter from the query string: ```diff - [Parameter] [SupplyParameterFromQuery] ``` ### Blazor Server script fallback policy authorization In .NET 7, the Blazor Server script (`blazor.server.js`) is [served by Static Files Middleware](https://github.com/dotnet/aspnetcore/blob/v7.0.16/src/Components/Server/src/DependencyInjection/ConfigureStaticFilesOptions.cs). Placing the call for Static Files Middleware (`UseStaticFiles`) in the request processing pipeline before the call to Authorization Middleware (`UseAuthorization`) is sufficient in .NET 7 apps to serve the Blazor script to anonymous users. In .NET 8, the Blazor Server script is served [by its own endpoint](https://github.com/search?q=repo%3Adotnet%2Faspnetcore%20GetBlazorEndpoint&type=code), using endpoint routing. This change is introduced by [Fixed bug - Passing options to UseStaticFiles breaks Blazor Server (`dotnet/aspnetcore` #45897)](https://github.com/dotnet/aspnetcore/pull/45897). Consider a multi-tenant scenario where: * Both the default and fallback policies are set identically. * The tenant is resolved using the first segment in the request path (for example, `tld.com/tenant-name/...`). * The requests to tenant endpoints are authenticated by an additional authentication scheme, which adds an additional identity to the request principal. * The fallback authorization policy has requirements that check claims via the additional identity. Requests for the Blazor script file (`blazor.server.js`) are served at `/_framework/blazor.server.js`, which is hardcoded in the framework. Requests for the file aren't authenticated by the additional authentication scheme for tenants ***but are still challenged by the fallback policy***, which results in returning an unauthorized result. This problem is under evaluation for a new framework feature in [MapRazorComponents broken with FallbackPolicy RequireAuthenticatedUser (`dotnet/aspnetcore` 51836)](https://github.com/dotnet/aspnetcore/issues/51836), which is currently scheduled for .NET 9's release in November, 2024. Until then, you can work around this problem using any of the following three approaches: * Don't use a fallback policy. Apply the `[Authorize]` attribute in the `_Imports.razor` file to apply it to all of the components of the app. For non-blazor endpoints, explicitly use `[Authorize]` or `RequireAuthorization`. * Add `[AllowAnonymous]` to the `/_framework/blazor.server.js` endpoint in the `Program` file: ```csharp app.MapBlazorHub().Add(endpointBuilder => { if (endpointBuilder is RouteEndpointBuilder { RoutePattern: { RawText: "/_framework/blazor.server.js" } }) { endpointBuilder.Metadata.Add(new AllowAnonymousAttribute()); } }); ``` * Register a custom `AuthorizationHandler` that [checks the `HttpContext`](xref:security/authorization/policies#access-mvc-request-context-in-handlers) to allow the `/_framework/blazor.server.js` file through. ## Docker ### Update Docker images For apps using Docker, update the *Dockerfile* `FROM` statements and scripts. Use a base image that includes the ASP.NET Core 8.0 runtime. Consider the following `docker pull` command difference between ASP.NET Core 7.0 and 8.0: ```diff - docker pull mcr.microsoft.com/dotnet/aspnet:7.0 + docker pull mcr.microsoft.com/dotnet/aspnet:8.0 ``` ### Update Docker port The default ASP.NET Core port configured in .NET container images has been updated from port 80 to 8080. The new `ASPNETCORE_HTTP_PORTS` environment variable was added as a simpler alternative to `ASPNETCORE_URLS`. For more information, see: * [Default ASP.NET Core port changed from 80 to 8080](/dotnet/core/compatibility/containers/8.0/aspnet-port). * [Specify ports only with `ASPNETCORE_HTTP_PORTS`](/aspnet/core/fundamentals/servers/kestrel/endpoints#specify-ports-only) ## Review breaking changes For breaking changes from .NET Core .NET 7.0 to 8.0, see [Breaking changes in .NET 8](/dotnet/core/compatibility/8.0), which includes [ASP.NET Core](/dotnet/core/compatibility/8.0#aspnet-core) and [Entity Framework Core](/dotnet/core/compatibility/8.0#entity-framework-core) sections.