从 ASP.NET Core 5.0 迁移到 6.0
本文介绍如何将现有 ASP.NET Core 5.0 项目更新为 ASP.NET Core 6.0。 有关如何从 ASP.NET Core 3.1 迁移到 ASP.NET Core 6.0 的说明,请参阅从 ASP.NET Core 3.1 迁移到 6.0。
先决条件
- 带有 ASP.NET 和 Web 开发工作负载的 Visual Studio 2022。
- .NET 6.0 SDK
更新 global.json 中的 .NET SDK 版本
如果依靠 global.json
文件来定向于特定 .NET SDK 版本,请将 version
属性更新为已安装的 .NET 6.0 SDK 版本。 例如:
{
"sdk": {
- "version": "5.0.100"
+ "version": "6.0.100"
}
}
更新目标框架
将项目文件的目标框架名字对象 (TFM) 更新为 net6.0
:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
- <TargetFramework>net5.0</TargetFramework>
+ <TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
</Project>
更新包引用
在项目文件中,将每个 Microsoft.AspNetCore.*
和 Microsoft.Extensions.*
包引用的 Version
特性更新为 6.0.0 或更高版本。 例如:
<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>
新托管模型
适用于 ASP.NET Core 的新的 .NET 6 最小托管模型只需要一个文件和几行代码。 迁移到 6.0 的应用不需要使用新的最小托管模型。 有关详细信息,请参阅以下部分中的迁移到 6.0 的应用不需要使用新的最小托管模型。
ASP.NET Core 空模板中的以下代码使用新的最小托管模型创建应用:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();
最小托管模型:
- 显著减少创建应用所需的文件和代码行数。 只需要一个文件和四行代码。
- 将
Startup.cs
和Program.cs
统一到单个Program.cs
文件中。 - 使用顶级语句最大程度减少应用所需的代码。
- 使用全局
using
指令消除或最大程度减少所需的using
语句行数。
以下代码显示 ASP.NET Core 5 Web 应用模板 (Razor Pages) 中的 Startup.cs
和 Program.cs
文件,其中删除了未使用的 using
语句:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
// Unused usings removed.
namespace WebAppRPv5
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
}
}
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
// Unused usings removed.
namespace WebAppRPv5
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
在 ASP.NET Core 6 中,上面的代码替换为以下内容:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorPages();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
上面的 ASP.NET Core 6 示例演示了以下操作方式:
- ConfigureServices 替换为
WebApplication.Services
。 builder.Build()
将配置的 WebApplication 返回到变量app
。 Configure 会替换为对使用app
的相同服务的配置调用。
本文档后面会提供使用最小托管模型将 ASP.NET Core 5 Startup
代码迁移到 ASP.NET Core 6 的详细示例。
对为 Web 应用模板生成的其他文件进行了几处更改:
Index.cshtml
和Privacy.cshtml
删除了未使用的using
语句。Error.cshtml
中的RequestId
声明为空引用类型 (NRT):
- public string RequestId { get; set; }
+ public string? RequestId { get; set; }
appsettings.json
和appsettings.Development.json
中的日志级别默认值已更改:
- "Microsoft": "Warning",
- "Microsoft.Hosting.Lifetime": "Information"
+ "Microsoft.AspNetCore": "Warning"
在前面的 ASP.NET Core 模板代码中,"Microsoft": "Warning"
已更改为"Microsoft.AspNetCore": "Warning"
。 此更改导致记录 Microsoft
命名空间中除 Microsoft.AspNetCore
以外的所有信息性消息。 例如,Microsoft.EntityFrameworkCore
现记录在信息级别。
有关新托管模型的更多详细信息,请参阅常见问题解答部分。 有关采用 NRT 和 .NET 编译器 Null 状态分析的详细信息,请参阅空引用类型 (NRT) 和 .NET 编译器 Null 状态静态分析部分。
迁移到或使用 6.0 及更高版本的应用不需要使用新的最小托管模型
完全支持使用 Startup
以及由 ASP.NET Core 3.1 和 5.0 模板使用的通用主机。
将 Startup 与新的最小托管模型结合使用
ASP.NET Core 3.1 和 5.0 应用可以将其 Startup
代码与新的最小托管模型结合使用。 将Startup
与最小托管模型结合使用具有以下优点:
- 没有隐藏反射用于调用
Startup
类。 - 可以编写异步代码,因为开发人员控制对
Startup
的调用。 - 可以编写交错
ConfigureServices
和Configure
的代码。
将Startup
代码与新的最小托管模型结合使用的一个次要限制是,要将依赖项注入到Configure
中,必须手动解析Program.cs
中的服务。
请考虑由 ASP.NET Core 3.1 或 5.0 Razor Pages 模板生成的代码:
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
}
上面的代码已迁移到新的最小托管模型:
using Microsoft.AspNetCore.Builder;
var builder = WebApplication.CreateBuilder(args);
var startup = new Startup(builder.Configuration);
startup.ConfigureServices(builder.Services);
var app = builder.Build();
startup.Configure(app, app.Environment);
app.Run();
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (!env.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
}
在上面的代码中,删除了 if (env.IsDevelopment())
程序块,因为在开发模式下,开发人员异常页中间件在默认情况下处于启用状态。 有关详细信息,请参阅下一部分中的 ASP.NET Core 5 与 6 托管模型之间的差异。
使用自定义依赖项注入 (DI) 容器时,请添加以下突出显示的代码:
using Autofac;
using Autofac.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Hosting;
var builder = WebApplication.CreateBuilder(args);
var startup = new Startup(builder.Configuration);
startup.ConfigureServices(builder.Services);
// Using a custom DI container.
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
builder.Host.ConfigureContainer<ContainerBuilder>(startup.ConfigureContainer);
var app = builder.Build();
startup.Configure(app, app.Environment);
app.Run();
using Autofac;
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
}
// Using a custom DI container
public void ConfigureContainer(ContainerBuilder builder)
{
// Configure custom container.
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (!env.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
}
使用最小托管模型时,终结点路由中间件会包装整个中间件管道,因此无需显式调用 UseRouting
或 UseEndpoints
来注册路由。 UseRouting
仍可用于指定进行路由匹配的位置,但如果应在中间件管道开头匹配路由,则无需显式调用 UseRouting
。
在下面的代码中,从 Startup
中删除了对 UseRouting
和 UseEndpoints
的调用。 MapRazorPages
在Program.cs
中调用:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (!env.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
//app.UseRouting();
//app.UseEndpoints(endpoints =>
//{
// endpoints.MapRazorPages();
//});
}
}
using Microsoft.AspNetCore.Builder;
var builder = WebApplication.CreateBuilder(args);
var startup = new Startup(builder.Configuration);
startup.ConfigureServices(builder.Services);
var app = builder.Build();
startup.Configure(app, app.Environment);
app.MapRazorPages();
app.Run();
将 Startup
与新的最小托管模型结合使用时,请记住以下差异:
Program.cs
控制Startup
类的实例化和生存期。- 注入
Configure
方法中的其他任何服务都需要通过Program
类手动解析。
ASP.NET Core 5 与 6 托管模型之间的差异
- 在开发模式下,开发人员异常页中间件在默认情况下处于启用状态。
- 应用名称默认为入口点程序集的名称:
Assembly.GetEntryAssembly().GetName().FullName
。 使用库中的 WebApplicationBuilder 时,会将应用名称显式更改为库的程序集,以便 MVC 的应用程序部件发现可正常工作。 有关详细说明,请参阅本文档中的更改内容根、应用名称和环境。 - 终结点路由中间件会包装整个中间件管道,因此无需显式调用
UseRouting
或UseEndpoints
来注册路由。UseRouting
仍可用于指定进行路由匹配的位置,但如果应在中间件管道开头匹配路由,则无需显式调用UseRouting
。 - 管道会在任何 IStartupFilter 运行之前创建,因此生成管道时导致的异常对
IStartupFilter
调用链不可见。 - 某些工具(如 EF 迁移)使用
Program.CreateHostBuilder
访问应用的IServiceProvider
,以在应用上下文中执行自定义逻辑。 这些工具已更新为使用新方法在应用上下文中执行自定义逻辑。 实体框架迁移是采用此方式使用Program.CreateHostBuilder
的工具示例。 我们正在努力确保更新工具以使用新模型。 - 与
Startup
类不同,在实例化服务提供程序时,最小主机不会自动配置 DI 作用域。 对于需要作用域的上下文,必须使用 IServiceScopeFactory.CreateScope 调用 IServiceScope 以实例化新的作用域。 有关详细信息,请参阅如何在应用启动时解析服务。 - 创建 WebApplicationBuilder 之后,无法更改任何主机设置,例如应用名称、环境或内容根。 有关更改主机设置的详细说明,请参阅自定义
IHostBuilder
或IWebHostBuilder
。 以下突出显示的 API 会引发异常:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
// WebHost
try
{
builder.WebHost.UseContentRoot(Directory.GetCurrentDirectory());
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
try
{
builder.WebHost.UseEnvironment(Environments.Staging);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
try
{
builder.WebHost.UseSetting(WebHostDefaults.ApplicationKey, "ApplicationName2");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
try
{
builder.WebHost.UseSetting(WebHostDefaults.ContentRootKey, Directory.GetCurrentDirectory());
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
try
{
builder.WebHost.UseSetting(WebHostDefaults.EnvironmentKey, Environments.Staging);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
// Host
try
{
builder.Host.UseEnvironment(Environments.Staging);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
try
{
// TODO: This does not throw
builder.Host.UseContentRoot(Directory.GetCurrentDirectory());
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
无法从
WebApplicationBuilder.Host
或WebApplicationBuilder.WebHost
使用Startup
类。 以下突出显示的代码会引发异常:var builder = WebApplication.CreateBuilder(args); try { builder.Host.ConfigureWebHostDefaults(webHostBuilder => { webHostBuilder.UseStartup<Startup>(); }); } catch (Exception ex) { Console.WriteLine(ex.Message); throw; } builder.Services.AddRazorPages(); var app = builder.Build();
var builder = WebApplication.CreateBuilder(args); try { builder.WebHost.UseStartup<Startup>(); } catch (Exception ex) { Console.WriteLine(ex.Message); throw; } builder.Services.AddRazorPages(); var app = builder.Build();
WebApplicationBuilder (
WebApplicationBuilder.Host
) 上的 IHostBuilder 实现不会延迟 ConfigureServices、ConfigureAppConfiguration 或 ConfigureHostConfiguration 方法的执行。 不延迟执行使得使用 WebApplicationBuilder 的代码可以观察到对IServiceCollection
和IConfiguration
进行的更改。 下面的示例仅添加Service1
作为IService
:using Microsoft.Extensions.DependencyInjection.Extensions; var builder = WebApplication.CreateBuilder(args); builder.Host.ConfigureServices(services => { services.TryAddSingleton<IService, Service1>(); }); builder.Services.TryAddSingleton<IService, Service2>(); var app = builder.Build(); // Displays Service1 only. Console.WriteLine(app.Services.GetRequiredService<IService>()); app.Run(); class Service1 : IService { } class Service2 : IService { } interface IService { }
在上面的代码中,builder.Host.ConfigureServices
回调进行内联调用,而不是延迟到调用了 builder.Build
。 这意味着 Service1
会在 Service2
之前添加到 IServiceCollection
,从而导致为 IService
解析 Service1
。
为 ASP.NET Core 6 生成库
现有 .NET 生态系统围绕 IServiceCollection、IHostBuilder 和 IWebHostBuilder 构建扩展性。 这些属性在 WebApplicationBuilder 上作为 Services
、Host
和 WebHost
来提供。
WebApplication
实现了 Microsoft.AspNetCore.Builder.IApplicationBuilder 和 Microsoft.AspNetCore.Routing.IEndpointRouteBuilder。
生成 ASP.NET Core 特定组件时,我们期望库创建者继续面向 IHostBuilder
、IWebHostBuilder
、IApplicationBuilder
和 IEndpointRouteBuilder
。 这可确保中间件、路由处理程序或其他扩展点可继续跨不同的托管模型正常工作。
常见问题解答 (FAQ)
新的最小托管模型是否减少了功能?
不是。 新的托管模型在功能上等效于
IHostBuilder
和IWebHostBuilder
支持的 98% 的方案。 有一些高级方案需要对IHostBuilder
采用特定解决方法,但我们预计这种情况非常罕见。通用托管模型是否已弃用?
不是。 通用托管模型是受到无限支持的替代模型。 通用主机支持新的托管模型,仍是托管基于辅助角色的应用程序的主要方式。
是否必须迁移到新的托管模型?
不是。 新的托管模型是使用 .NET 6 和更高版本托管新应用的首选方法,但不强制更改现有应用中的项目布局。 这意味着应用可以通过将项目文件中的目标框架从
net5.0
更改为net6.0
,从 .NET 5 升级到 .NET 6。 有关详细信息,请参阅本文中的更新目标框架部分。 但是,建议将应用迁移到新的托管模型,以利用仅适用于新的托管模型的新功能。是否必须使用顶级语句?
不是。 新项目模板全都使用顶级语句,不过可以在任何 .NET 6 应用中使用新的托管 API 来托管 Web 服务器或 Web 应用。
将存储为字段的状态放置在
Program
或Startup
类中的哪个位置?强烈建议在 ASP.NET Core 应用中使用依赖项注入 (DI) 来流式传输状态。
有两种方法可用于在 DI 外部存储状态:
将状态存储在其他类中。 存储在类中会采用可以从应用中的任何位置访问的静态状态。
使用由顶级语句生成的
Program
类存储状态。 使用Program
存储状态是语义方法:var builder = WebApplication.CreateBuilder(args); ConfigurationValue = builder.Configuration["SomeKey"] ?? "Hello"; var app = builder.Build(); app.MapGet("/", () => ConfigurationValue); app.Run(); partial class Program { public static string? ConfigurationValue { get; private set; } }
项,该?
支持自定义 DI 容器。 有关示例,请参阅自定义依赖项注入 (DI) 容器。
WebApplicationFactory
和TestServer
是否仍可正常工作?是。
WebApplicationFactory<TEntryPoint>
是测试新托管模型的方法。 有关示例,请参见使用WebApplicationFactory
或TestServer
进行测试。
Blazor
按照本文前面所述的指导将应用更新到 6.0 后,请按照 ASP.NET Core 6.0 的新增功能中的链接采用特定功能。
要为 Blazor 应用采用所有新的 6.0 功能,我们建议使用以下过程:
- 通过一个 Blazor 项目模板创建新的 6.0 Blazor 项目。 有关详细信息,请参阅用于 ASP.NET Core Blazor 的工具。
- 将应用的组件和代码移动到 6.0 应用,进行修改以采用新的 6.0 功能。
迁移 SPA 项目
从 SPA 扩展迁移 Angular 应用
请参阅此 GitHub 问题
从 SPA 扩展迁移 React 应用
请参阅此 GitHub 问题中的从 Spa 扩展迁移React 应用程序
更新 Docker 映像
对于使用 Docker 的应用,请更新Dockerfile FROM
语句和脚本。 使用包含 ASP.NET Core 6.0 运行时的基础映像。 请考虑 ASP.NET Core 5.0 和 6.0 之间的以下 docker pull
命令差异:
- docker pull mcr.microsoft.com/dotnet/aspnet:5.0
+ docker pull mcr.microsoft.com/dotnet/aspnet:6.0
请参阅 GitHub 问题中断性变更:默认控制台记录器格式设置为 JSON。
对 ASP.NET Core Razor SDK 的更改
Razor 编译器现在利用新的源生成器功能从项目中的 Razor 视图和页面生成编译的 C# 文件。 在以前的版本中:
- 编译依赖于
RazorGenerate
和RazorCompile
目标来生成生成的代码。 这些目标不再有效。 在 .NET 6 中,对编译器的单个调用支持代码生成和编译。RazorComponentGenerateDependsOn
仍受支持,可指定生成运行之前所需的依赖项。 - 生成了单独的 Razor 程序集 (
AppName.Views.dll
),其中包含应用程序中编译的视图类型。 此行为已弃用,会生成单个程序集AppName.dll
,其中包含应用类型和生成的视图。 AppName.Views.dll
中的应用类型是公共的。 在 .NET 6 中,应用类型处于AppName.dll
中,不过是internal sealed
。 对AppName.Views.dll
进行类型发现的应用无法对AppName.dll
进行类型发现。 下面显示了 API 更改:
- 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>
进行以下更改:
- 以下属性不再适用于单步编译模型。
RazorTargetAssemblyAttribute
RazorTargetName
EnableDefaultRazorTargetAssemblyInfoAttributes
UseRazorBuildServer
GenerateRazorTargetAssemblyInfo
GenerateMvcApplicationPartsAssemblyAttributes
有关详细信息,请参阅Razor编译器不再生成 Views 程序集。
项目模板使用 Duende Identity Server
项目模板使用Duende Identity Server。 有关迁移指南,请参阅 IdentityServer4 v4.1 到 Duende IdentityServer v5。
重要
Duende Identity Server 是具有互惠许可协议的开放源代码产品。 如果计划在生产中使用 Duende Identity Server,则可能需要从 Duende Software 获取商业许可证并支付许可证费用。 有关详细信息,请参阅 Duende Software:许可证。
要了解如何为 ASP.NET CoreIdentity使用Microsoft Azure Active Directory,请参阅Identity(dotnet/aspnetcore GitHub 存储库)。
将名为 Keys
的 DbSet<Key>
属性添加到每个 IdentityDbContext
,以满足 IPersistedGrantDbContext
的更新版本中的新要求。 密钥需要包含在与 Duende Identity Server 存储的协定中。
public DbSet<Key> Keys { get; set; }
注意
必须为 Duende Identity Server 重新创建现有迁移。
迁移到 ASP.NET Core 6.0 的代码示例
查看中断性变更
请参阅以下资源:
- Identity:已更改 UI 的默认 Bootstrap 版本
- 从版本 5.0 到 6.0 的迁移的中断性变更:包括 ASP.NET Core 和 Entity Framework Core。
- 公告 GitHub 存储库(aspnet/Announcements,
6.0.0
标签):包括中断性和非中断性信息。
空引用类型 (NRT) 和 .NET 编译器 Null 状态静态分析
ASP.NET Core 项目模板使用空引用类型 (NRT),.NET 编译器会执行 Null 状态静态分析。 这些功能随 C# 8 一起发布,默认已为使用 ASP.NET Core 6.0 (C# 10) 或更高版本生成的应用启用。
.NET 编译器的 Null 状态静态分析警告可充当本地更新文档示例或示例应用的指示,也可忽略。 可以通过在应用的项目文件中将 Nullable
设置为 disable
来禁用 Null 状态静态分析,建议仅将其用于文档示例和示例应用(如果编译器警告在你了解 .NET 时会分散你的注意力)。 不建议在生产项目中禁用 Null 状态检查。
有关 NRT、MSBuild Nullable
属性和更新应用(包括 #pragma
指南)的详细信息,请参阅 C# 文档中的以下资源:
- 可为空引用类型
- 可为 null 的引用类型(C# 引用)
- 了解用于解析可为空警告的方法
- 使用可为 Null 的引用类型更新代码库以改进 null 诊断警告
- null 状态静态分析的属性
- ! (null 包容)运算符(C# 参考)
ASP.NET Core 模块 (ANCM)
如果在安装 Visual Studio 时未选择 ASP.NET Core 模块 (ANCM) 组件,或者系统上安装了 ANCM 的早期版本,请下载最新的 .NET Core 托管捆绑包安装程序(直接下载)并运行该安装程序。 有关详细信息,请参阅托管捆绑包。
应用程序名称更改
在 .NET 6 中,WebApplicationBuilder 会将内容根路径规范化以 DirectorySeparatorChar 结尾。 大多数从HostBuilder或WebHostBuilder迁移的应用不会共享相同的应用名称,因为它们没有规范化。 有关详细信息,请参阅SetApplicationName