--- title: Migrate from ASP.NET Core 5.0 to 6.0 author: rick-anderson description: Learn how to migrate an ASP.NET Core 5.0 project to ASP.NET Core 6.0. ms.author: riande monikerRange: '>= aspnetcore-5.0' ms.date: 04/11/2022 uid: migration/50-to-60 --- # Migrate from ASP.NET Core 5.0 to 6.0 This article explains how to update an existing ASP.NET Core 5.0 project to ASP.NET Core 6.0. For instructions on how to migrate from ASP.NET Core 3.1 to ASP.NET Core 6.0, see . ## Prerequisites # [Visual Studio](#tab/visual-studio) [!INCLUDE[](~/includes/net-prereqs-vs-6.0.md)] # [Visual Studio Code](#tab/visual-studio-code) [!INCLUDE[](~/includes/net-prereqs-vsc-6.0.md)] # [Visual Studio for Mac](#tab/visual-studio-mac) [!INCLUDE[](~/includes/net-prereqs-mac-6.0.md)] --- ## Update .NET SDK version in global.json If you rely upon a [`global.json`](/dotnet/core/tools/global-json) file to target a specific .NET SDK version, update the `version` property to the .NET 6.0 SDK version that's installed. For example: ```diff { "sdk": { - "version": "5.0.100" + "version": "6.0.100" } } ``` ## Update the target framework Update the project file's [Target Framework Moniker (TFM)](/dotnet/standard/frameworks) to `net6.0`: ```diff - net5.0 + net6.0 ``` ## Update package references In the project file, update each [`Microsoft.AspNetCore.*`](https://www.nuget.org/packages?q=Microsoft.AspNetCore.*) and [`Microsoft.Extensions.*`](https://www.nuget.org/packages?q=Microsoft.Extensions.*) package reference's `Version` attribute to 6.0.0 or later. For example: ```diff - - + + ``` ## New hosting model The new .NET 6 minimal hosting model for ASP.NET Core apps requires only one file and a few lines of code. **Apps migrating to 6.0 don't need to use the new minimal hosting model.** For more information, see [Apps migrating to 6.0 don't need to use the new minimal hosting model](#am6) in the following section. The following code from the ASP.NET Core empty template creates an app using the new minimal hosting model: [!code-csharp[](50-to-60/samples/WebEmpty/ProgramEmpty.cs?name=snippet1)] The minimal hosting model: * Significantly reduces the number of files and lines of code required to create an app. Only one file is needed with four lines of code. * Unifies `Startup.cs` and `Program.cs` into a single `Program.cs` file. * Uses [top-level statements](/dotnet/csharp/fundamentals/program-structure/top-level-statements) to minimize the code required for an app. * Uses [global `using` directives](/dotnet/csharp/whats-new/csharp-10#global-using-directives) to eliminate or minimize the number of [`using` statement](/dotnet/csharp/language-reference/keywords/using-statement) lines required. The following code displays the `Startup.cs` and `Program.cs` files from an ASP.NET Core 5 Web App template (Razor Pages) with unused `using` statements removed: [!code-csharp[](50-to-60/samples/WebAppRPv5/Startup.cs)] [!code-csharp[](50-to-60/samples/WebAppRPv5/Program.cs)] In ASP.NET Core 6, the preceding code is replaced by the following: [!code-csharp[](50-to-60/samples/WebAppRPv6/Program.cs)] The preceding ASP.NET Core 6 sample shows how: * is replaced with [`WebApplication.Services`](xref:Microsoft.AspNetCore.Builder.WebApplication.Services). * `builder.Build()` returns a configured to the variable `app`. is replaced with configuration calls to same services using `app`. Detailed examples of migrating ASP.NET Core 5 `Startup` code to ASP.NET Core 6 using the minimal hosting model are provided later in this document. There are a few changes to the other files generated for the Web App template: * `Index.cshtml` and `Privacy.cshtml` have the unused `using` statements removed. * `RequestId` in `Error.cshtml` is declared as a [nullable reference type (NRT)](/dotnet/csharp/language-reference/builtin-types/nullable-reference-types): ```diff - public string RequestId { get; set; } + public string? RequestId { get; set; } ``` * Log level defaults have changed in `appsettings.json` and `appsettings.Development.json`: ```diff - "Microsoft": "Warning", - "Microsoft.Hosting.Lifetime": "Information" + "Microsoft.AspNetCore": "Warning" ``` In the preceding ASP.NET Core template code, `"Microsoft": "Warning"` has been changed to `"Microsoft.AspNetCore": "Warning"`. This change results in logging all informational messages from the `Microsoft` namespace ***except*** `Microsoft.AspNetCore`. For example, `Microsoft.EntityFrameworkCore` is now logged at the informational level. For more details on the new hosting model, see the [Frequently asked questions](#faq) section. For more information on the adoption of NRTs and .NET compiler null-state analysis, see the [Nullable reference types (NRTs) and .NET compiler null-state static analysis](#nullable-reference-types-nrts-and-net-compiler-null-state-static-analysis) section. ### Apps migrating to or using 6.0 and later don't need to use the new minimal hosting model Using [`Startup`](xref:fundamentals/startup?view=aspnetcore-5.0&preserve-view=true) and the [Generic Host](xref:fundamentals/host/generic-host) used by the ASP.NET Core 3.1 and 5.0 templates is fully supported. ### Use Startup with the new minimal hosting model ASP.NET Core 3.1 and 5.0 apps can use their `Startup` code with the new minimal hosting model. Using `Startup` with the minimal hosting model has the following advantages: * No hidden reflection is used to call the `Startup` class. * Asynchronous code can be written because the developer controls the call to `Startup`. * Code can be written that interleaves `ConfigureServices` and `Configure`. One minor limitation in using `Startup` code with the new minimal hosting model is that to inject a dependency into `Configure`, the service in `Program.cs` must be manually resolved. Consider the following code generated by the ASP.NET Core 3.1 or 5.0 Razor Pages template: [!code-csharp[](~/migration/50-to-60/samples/WebRP31to60/Program.cs?name=snippet)] [!code-csharp[](~/migration/50-to-60/samples/WebRP31to60/Startup.cs?name=snippet)] The preceding code migrated to the new minimal hosting model: [!code-csharp[](~/migration/50-to-60/samples/WebRP31to60/Program.cs?name=snippet_60)] [!code-csharp[](~/migration/50-to-60/samples/WebRP31to60/Startup.cs?name=snippet_60)] In the preceding code, the ` if (env.IsDevelopment())` block is removed because in [development mode](xref:fundamentals/environments), the developer exception page middleware is enabled by default. For more information, see [Differences between the ASP.NET Core 5 and 6 hosting models](#diff) in the next section. When using a custom dependency injection (DI) container, add the following highlighted code: [!code-csharp[](~/migration/50-to-60/samples/WebRP31to60/Program.cs?name=snippet_60a&highlight=12-14)] [!code-csharp[](~/migration/50-to-60/samples/WebRP31to60/Startup.cs?name=snippet_60a&highlight=17-21)] When using the minimal hosting model, the endpoint routing middleware wraps the entire middleware pipeline, therefore there's no need to have explicit calls to `UseRouting` or `UseEndpoints` to register routes. `UseRouting` can still be used to specify where route matching happens, but `UseRouting` doesn't need to be explicitly called if routes should be matched at the beginning of the middleware pipeline. In the following code, the calls to `UseRouting` and `UseEndpoints` are removed from `Startup`. `MapRazorPages` is called in `Program.cs`: [!code-csharp[](~/migration/50-to-60/samples/WebRP31to60/Startup.cs?name=snippet_60e&highlight=25-30)] [!code-csharp[](~/migration/50-to-60/samples/WebRP31to60/Program.cs?name=snippet_60e&highlight=13)] When using `Startup` with the new minimal hosting model, keep in mind the following difference: * `Program.cs` controls the instantiation and lifetime of the `Startup` class. * Any additional services injected into the `Configure` method need to be manually resolved by the `Program` class. ### Differences between the ASP.NET Core 5 and 6 hosting models * In [development mode](xref:fundamentals/environments), the developer exception page middleware is enabled by default. * The app name defaults to the entry point assembly's name: `Assembly.GetEntryAssembly().GetName().FullName`. When using the in a library, explicitly change the app name to the library's assembly to allow MVC's [application part discovery](xref:mvc/extensibility/app-parts) to work. See [Change the content root, app name, and environment](xref:migration/50-to-60-samples#ccr) in this document for detailed instructions. * The endpoint routing middleware wraps the entire middleware pipeline, therefore there's no need to have explicit calls to `UseRouting` or `UseEndpoints` to register routes. `UseRouting` can still be used to specify where route matching happens, but `UseRouting` doesn't need to be explicitly called if routes should be matched at the beginning of the middleware pipeline. * The [pipeline](xref:fundamentals/middleware/index) is created before any runs, therefore exceptions caused while building the pipeline aren't visible to the `IStartupFilter` call chain. * Some tools, such as EF migrations, use [`Program.CreateHostBuilder`](xref:fundamentals/host/generic-host) to access the app's `IServiceProvider` to execute custom logic in the context of the app. These tools have been updated to use a new technique to execute custom logic in the context of the app. [Entity Framework Migrations](/ef/core/managing-schemas/migrations/) is an example of a tool that uses `Program.CreateHostBuilder` in this way. We're working to make sure tools are updated to use the new model. * Unlike the `Startup` class, the minimal host doesn't automatically configure a DI scope when instantiating the service provider. For contexts where a scope is required, it is necessary to invoke with [IServiceScopeFactory.CreateScope](xref:Microsoft.Extensions.DependencyInjection.IServiceScopeFactory.CreateScope%2A) to instantiate a new scope. For more information, see [how to resolve a service at app startup](xref:fundamentals/dependency-injection#resolve-a-service-at-app-start-up). * It's ***not*** possible to [change any host settings such as app name, environment, or the content root](xref:migration/50-to-60-samples#ccr) after the creation of the . For detailed instructions on changing host settings, see [Customize `IHostBuilder` or `IWebHostBuilder`](xref:migration/50-to-60-samples#cii). The following highlighted APIs throw an exception: [!code-csharp[](50-to-60/samples/WebThrowEx/Program.cs?name=snippet2&highlight=7-60,64-65)] * The `Startup` class can't be used from [`WebApplicationBuilder.Host`](xref:Microsoft.AspNetCore.Builder.WebApplicationBuilder.Host) or [`WebApplicationBuilder.WebHost`](xref:Microsoft.AspNetCore.Builder.WebApplicationBuilder.WebHost). The following highlighted code throws an exception: [!code-csharp[](50-to-60/samples/WebThrowEx/Program.cs?name=snippet3&highlight=5-8)] [!code-csharp[](50-to-60/samples/WebThrowEx/Program.cs?name=snippet4&highlight=5)] * The implementation on (`WebApplicationBuilder.Host`), doesn't defer execution of the , , or methods. Not deferring execution allows code using to observe changes made to the `IServiceCollection` and `IConfiguration`. The following example only adds `Service1` as an `IService`: [!code-csharp[](50-to-60/samples/WebThrowEx/Program.cs?name=snippet5)] In the preceding code, the `builder.Host.ConfigureServices` callback gets called inline rather than being deferred until `builder.Build` is called. This means that `Service1` gets added to the `IServiceCollection` before `Service2` and results in `Service1` being resolved for `IService`. ## Building libraries for ASP.NET Core 6 The existing .NET ecosystem built extensibility around , , and . These properties are available on as `Services`, `Host`, and `WebHost`. `WebApplication` implements both and . We expect library authors to continue targeting `IHostBuilder`, `IWebHostBuilder`, `IApplicationBuilder`, and `IEndpointRouteBuilder` when building ASP.NET Core specific components. This ensures that your middleware, route handler, or other extensibility points continue to work across different hosting models.

Frequently asked questions (FAQ)

* **Is the new minimal hosting model less capable?** No. The new hosting model is functionally equivalent for 98% of scenarios supported by `IHostBuilder` and the `IWebHostBuilder`. There are some advanced scenarios that require specific workarounds on `IHostBuilder`, but we expect those to be extremely rare. * **Is the generic hosting model deprecated?** No. The generic hosting model is an alternative model that is supported indefinitely. The generic host underpins the new hosting model and is still the primary way to host worker-based applications. * **Do I have to migrate to the new hosting model?** No. The new hosting model is the preferred way to host new apps using .NET 6 and later, but you aren't forced to change the project layout in existing apps. This means apps can upgrade from .NET 5 to .NET 6 by changing the target framework in the project file from `net5.0` to `net6.0`. For more information, see the [Update the target framework](#tf) section in this article. However, we recommend apps migrate to the new hosting model to take advantage of new features only available to the new hosting model. * **Do I have to use top-level statements?** No. The new project templates all use [top-level statements](/dotnet/csharp/fundamentals/program-structure/top-level-statements), but the new hosting APIs can be used in any .NET 6 app to host a webserver or web app. * **Where do I put state that was stored as fields in my `Program` or `Startup` class?** We strongly recommend using [dependency injection](xref:fundamentals/dependency-injection) (DI) to flow state in ASP.NET Core apps. There are two approaches to storing state outside of DI: * Store the state in another class. Storing in a class assumes a static state that can be accessed from anywhere in the app. * Use the `Program` class generated by top level statements to store state. Using `Program` to store state is the semantic approach: [!code-csharp[](50-to-60/samples/WebThrowEx/Program.cs?name=snippetE)] * **What if I was using a custom dependency injection container?** Custom DI containers are supported. For an example, see [Custom dependency injection (DI) container](xref:migration/50-to-60-samples#cdi). * **Do `WebApplicationFactory` and `TestServer` still work?** Yes. `WebApplicationFactory` is the way to test the new hosting model. For an example, see [Test with `WebApplicationFactory` or `TestServer`](xref:migration/50-to-60-samples#twa). ## Blazor After following the guidance earlier in this article to update an app to 6.0, adopt specific features by following the links in . To adopt all of the [new 6.0 features for Blazor apps](xref:aspnetcore-6.0#blazor), we recommend the following process: * Create a new 6.0 Blazor project from one of the Blazor project templates. For more information, see . * Move the app's components and code to the 6.0 app making modifications to adopt the new 6.0 features. ## Migrating SPA projects ### Migrating Angular apps from SPA extensions See [this GitHub issue](https://github.com/dotnet/aspnetcore/issues/44600) ### Migrating React apps from SPA extensions See **Migrating React applications from Spa Extensions** in [this GitHub issue](https://github.com/dotnet/aspnetcore/issues/44600) ## Update Docker images For apps using Docker, update your *Dockerfile* `FROM` statements and scripts. Use a base image that includes the ASP.NET Core 6.0 runtime. Consider the following `docker pull` command difference between ASP.NET Core 5.0 and 6.0: ```diff - docker pull mcr.microsoft.com/dotnet/aspnet:5.0 + docker pull mcr.microsoft.com/dotnet/aspnet:6.0 ``` See GitHub issue [Breaking Change: Default console logger format set to JSON](https://github.com/dotnet/dotnet-docker/issues/3274). ## Changes to the ASP.NET Core Razor SDK The Razor compiler now leverages the new [source generators feature](https://devblogs.microsoft.com/dotnet/introducing-c-source-generators/) to generate compiled C# files from the Razor views and pages in a project. In previous versions: * The compilation relied on the `RazorGenerate` and `RazorCompile` targets to produce the generated code. These targets are no longer valid. In .NET 6, both code generation and compilation are supported by a single call to the compiler. `RazorComponentGenerateDependsOn` is still supported to specify dependencies that are required before the build runs. * A separate Razor assembly, `AppName.Views.dll`, was generated that contained the compiled view types in an application. This behavior has been deprecated and a single assembly `AppName.dll` is produced that contains both the app types and the generated views. * The app types in `AppName.Views.dll` were public. In .NET 6, the app types are in `AppName.dll` but are `internal sealed`. Apps doing type discover on `AppName.Views.dll` won't be able to do type discover on `AppName.dll`. The following shows the API change: ```diff - public class Views_Home_Index : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage + internal sealed class Views_Home_Index : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage ``` Make the following changes: * The following properties are no longer applicable with the single-step compilation model. * `RazorTargetAssemblyAttribute` * `RazorTargetName` * `EnableDefaultRazorTargetAssemblyInfoAttributes` * `UseRazorBuildServer` * `GenerateRazorTargetAssemblyInfo` * `GenerateMvcApplicationPartsAssemblyAttributes` For more information, see [Razor compiler no longer produces a Views assembly](https://github.com/aspnet/Announcements/issues/459). ## Project templates use Duende Identity Server Project templates now use [Duende Identity Server](https://docs.duendesoftware.com). For migration guidance, see [IdentityServer4 v4.1 to Duende IdentityServer v5](https://docs.duendesoftware.com/identityserver/v5/upgrades/is4_v4_to_dis_v5/). > [!IMPORTANT] > Duende Identity Server is an open source product with a reciprocal license agreement. If you plan to use Duende Identity Server in production, you might be required to obtain a commercial licence from [Duende Software](https://duendesoftware.com/) and pay a license fee. For more information, see [Duende Software: Licenses](https://aka.ms/identityserverlicense). > > To learn how to use [Microsoft Azure Active Directory](https://azure.microsoft.com/services/active-directory/) for ASP.NET Core Identity, see [Identity (dotnet/aspnetcore GitHub repository)](https://aka.ms/aspnetidentityserver). Add a `DbSet` property named `Keys` to every `IdentityDbContext` to satisfy a new requirement from the updated version of `IPersistedGrantDbContext`. The keys are required as part of the contract with Duende Identity Server's stores. ```csharp public DbSet Keys { get; set; } ``` > [!NOTE] > Existing migrations must be recreated for Duende Identity Server. ## Code samples migrated to ASP.NET Core 6.0 ## Review breaking changes See the following resources: * [Identity: Default Bootstrap version of UI changed](/dotnet/core/compatibility/aspnet-core/6.0/identity-bootstrap4-to-5) * [Breaking changes for migration from version 5.0 to 6.0](/dotnet/core/compatibility/6.0): Includes ASP.NET Core and Entity Framework Core. * [Announcements GitHub repository (aspnet/Announcements, `6.0.0` label)](https://github.com/aspnet/Announcements/issues?q=is%3Aissue+label%3A6.0.0+is%3Aopen): Includes breaking and non-breaking information. ## Nullable reference types (NRTs) and .NET compiler null-state static analysis ASP.NET Core project templates use nullable reference types (NRTs), and the .NET compiler performs null-state static analysis. These features were released with C# 8 and are enabled by default for apps generated using ASP.NET Core 6.0 (C# 10) or later. The .NET compiler's null-state static analysis warnings can either serve as a guide for updating a documentation example or sample app locally or be ignored. Null-state static analysis can be disabled by [setting `Nullable` to `disable`](/dotnet/csharp/language-reference/builtin-types/nullable-reference-types#setting-the-nullable-context) in the app's project file, which we only recommend for documentation examples and sample apps if the compiler warnings are distracting while learning about .NET. **_We don't recommend disabling null-state checking in production projects._** For more information on NRTs, the MSBuild `Nullable` property, and updating apps (including `#pragma` guidance), see the following resources in the C# documentation: * [Nullable reference types](/dotnet/csharp/nullable-references) * [Nullable reference types (C# reference)](/dotnet/csharp/language-reference/builtin-types/nullable-reference-types) * [Learn techniques to resolve nullable warnings](/dotnet/csharp/nullable-warnings) * [Update a codebase with nullable reference types to improve null diagnostic warnings](/dotnet/csharp/nullable-migration-strategies) * [Attributes for null-state static analysis](/dotnet/csharp/language-reference/attributes/nullable-analysis) * [! (null-forgiving) operator (C# reference)](/dotnet/csharp/language-reference/operators/null-forgiving) ## ASP.NET Core Module (ANCM) [!INCLUDE[](~/includes/hosting-bundle.md)] [!INCLUDE[](~/includes/appname6.md)] ## Additional resources *