aspnetcore/migration/50-to-60.md
This article explains how to update an existing ASP.NET Core in .NET 5 project to .NET 6. For instructions on how to migrate from ASP.NET Core 3.1 to .NET 6, see xref:migration/31-to-60.
If you rely upon a global.json file to target a specific .NET SDK version, update the version property to the .NET 6 SDK version that's installed. For example:
{
"sdk": {
- "version": "5.0.100"
+ "version": "6.0.100"
}
}
<a name="tf"></a>
Update the project file's Target Framework Moniker (TFM) to net6.0:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
- <TargetFramework>net5.0</TargetFramework>
+ <TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
</Project>
In the project file, update each Microsoft.AspNetCore.* and Microsoft.Extensions.* package reference's Version attribute to 6.0.0 or later. For example:
<ItemGroup>
- <PackageReference Include="Microsoft.AspNetCore.JsonPatch" Version="5.0.3" />
- <PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="5.0.0" />
+ <PackageReference Include="Microsoft.AspNetCore.JsonPatch" Version="6.0.0" />
+ <PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="6.0.0" />
</ItemGroup>
<a name="nhm"></a>
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 .NET 6 don't need to use the new minimal hosting model. For more information, see Apps migrating to .NET 6 don't need to use the new minimal hosting model in the following section.
The following code from the ASP.NET Core empty template creates an app using the new minimal hosting model:
The minimal hosting model:
Startup.cs and Program.cs into a single Program.cs file.using directives to eliminate or minimize the number of using statement lines required.The following code displays the Startup.cs and Program.cs files from an .NET 5 Web App template (Razor Pages) with unused using statements removed:
In ASP.NET Core in .NET 6, the preceding code is replaced by the following:
The preceding ASP.NET Core in .NET 6 sample shows how:
WebApplication.Services.builder.Build() returns a configured xref:Microsoft.AspNetCore.Builder.WebApplication to the variable app. xref:Microsoft.AspNetCore.Hosting.StartupBase.Configure* is replaced with configuration calls to same services using app.Detailed examples of migrating ASP.NET Core in .NET 5 Startup code to .NET 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):- public string RequestId { get; set; }
+ public string? RequestId { get; set; }
appsettings.json and appsettings.Development.json:- "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 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 section.
<a name="am6"></a> <a name="apps-migrating-to-60-dont-need-to-use-the-new-minimal-hosting-model"></a> <!-- previous title -->
Using Startup and the Generic Host used by the ASP.NET Core 3.1 and 5.0 templates is fully supported.
<a name="smhm"></a>
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:
Startup class.Startup.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:
The preceding code migrated to the new minimal hosting model:
In the preceding code, the if (env.IsDevelopment()) block is removed because in development mode, the developer exception page middleware is enabled by default. For more information, see Differences between the ASP.NET Core in .NET 5 and .NET 6 hosting models in the next section.
When using a custom dependency injection (DI) container, add the following highlighted code:
<a name="wraps"></a>
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:
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.Configure method need to be manually resolved by the Program class.<a name="diff"></a>
Assembly.GetEntryAssembly().GetName().FullName. When using the xref:Microsoft.AspNetCore.Builder.WebApplicationBuilder in a library, explicitly change the app name to the library's assembly to allow MVC's application part discovery to work. See Change the content root, app name, and environment in this document for detailed instructions.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.IStartupFilter call chain.Program.CreateHostBuilder 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 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.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 xref:Microsoft.Extensions.DependencyInjection.IServiceScope with IServiceScopeFactory.CreateScope to instantiate a new scope. For more information, see how to resolve a service at app startup.IHostBuilder or IWebHostBuilder. The following highlighted APIs throw an exception:The Startup class can't be used from WebApplicationBuilder.Host or WebApplicationBuilder.WebHost. The following highlighted code throws an exception:
The xref:Microsoft.Extensions.Hosting.IHostBuilder implementation on xref:Microsoft.AspNetCore.Builder.WebApplicationBuilder (WebApplicationBuilder.Host), doesn't defer execution of the xref:Microsoft.AspNetCore.Hosting.IStartup.ConfigureServices%2A, xref:Microsoft.Extensions.Hosting.HostBuilder.ConfigureAppConfiguration%2A, or xref:Microsoft.Extensions.Hosting.IHostBuilder.ConfigureHostConfiguration%2A methods. Not deferring execution allows code using xref:Microsoft.AspNetCore.Builder.WebApplicationBuilder to observe changes made to the IServiceCollection and IConfiguration. The following example only adds Service1 as an IService:
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.
The existing .NET ecosystem built extensibility around xref:Microsoft.Extensions.DependencyInjection.IServiceCollection, xref:Microsoft.Extensions.Hosting.IHostBuilder, and xref:Microsoft.AspNetCore.Hosting.IWebHostBuilder. These properties are available on xref:Microsoft.AspNetCore.Builder.WebApplicationBuilder as Services, Host, and WebHost.
WebApplication implements both xref:Microsoft.AspNetCore.Builder.IApplicationBuilder?displayProperty=fullName and xref:Microsoft.AspNetCore.Routing.IEndpointRouteBuilder?displayProperty=fullName.
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.
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 or 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 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, 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 (DI) to flow state in ASP.NET Core apps.
There are two approaches to storing state outside of DI:
What if I was using a custom dependency injection container?
Custom DI containers are supported. For an example, see Custom dependency injection (DI) container.
Do WebApplicationFactory and TestServer still work?
Yes. WebApplicationFactory<TEntryPoint> is the way to test the new hosting model. For an example, see Test with WebApplicationFactory or TestServer.
After following the guidance earlier in this article to update an app to .NET 6, adopt specific features by following the links in xref:aspnetcore-6.0#blazor.
To adopt all of the new 6.0 features for Blazor apps, we recommend the following process:
See Migrating React applications from Spa Extensions in this GitHub issue
For apps using Docker, update your Dockerfile FROM statements and scripts. Use a base image that includes the ASP.NET Core in .NET 6 runtime. Consider the following docker pull command difference between ASP.NET Core in .NET 5 and .NET 6:
- 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.
The Razor compiler now leverages the new source generators feature to generate compiled C# files from the Razor views and pages in a project. In previous versions:
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.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.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:- public class Views_Home_Index : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage<dynamic>
+ internal sealed class Views_Home_Index : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage<dynamic>
Make the following changes:
RazorTargetAssemblyAttributeRazorTargetNameEnableDefaultRazorTargetAssemblyInfoAttributesUseRazorBuildServerGenerateRazorTargetAssemblyInfoGenerateMvcApplicationPartsAssemblyAttributesFor more information, see Razor compiler no longer produces a Views assembly.
Project templates now use Duende Identity Server.
[!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 and pay a license fee. For more information, see Duende Software: Licenses.
To learn how to use Microsoft Azure Active Directory for ASP.NET Core Identity, see Identity (dotnet/aspnetcore GitHub repository).
Add a DbSet<Key> 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.
public DbSet<Key> Keys { get; set; }
[!NOTE] Existing migrations must be recreated for Duende Identity Server.
xref:migration/50-to-60-samples
Use the articles in Breaking changes in .NET to find breaking changes that might apply when upgrading an app to a newer version of .NET.
For more information, see Announcements GitHub repository (aspnet/Announcements, 6.0.0 label): Includes breaking and non-breaking information.
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 in .NET 6 (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 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: