从 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。
重要
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