本文介绍如何将 .NET 5 项目中的现有 ASP.NET Core 更新为 .NET 6。 有关如何从 ASP.NET Core 3.1 迁移到 .NET 6 的说明,请参阅 从 ASP.NET Core 3.1 迁移到 .NET 6。
先决条件
- 带有 ASP.NET 和 Web 开发工作负载的 Visual Studio 2022。
- .NET 6 SDK
更新 global.json 中的 .NET SDK 版本
如果依赖 global.json
文件以特定 .NET SDK 版本为目标,请将 version
属性更新为已安装的 .NET 6 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 最小托管模型只需要一个文件和几行代码。 迁移到 .NET 6 的应用不需要使用新的最小托管模型。 有关详细信息,请参阅以下部分中迁移到 .NET 6 的应用不需要使用新的最小托管模型 。
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
。
以下代码显示 .NET 5 Web 应用模板中的 Razor 页面和 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>();
});
}
}
在 .NET 6 中的 ASP.NET Core 中,上述代码替换为以下代码:
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();
.NET 6 示例中的上述 ASP.NET Core 演示如何:
-
ConfigureServices 替换为
WebApplication.Services
。 -
builder.Build()
将已配置的 WebApplication 返回给变量app
。 Configure 被替换为对使用app
的同一服务的配置调用。
本文档后面提供了使用最小托管模型将 .NET 5 Startup
代码中的 ASP.NET Core 迁移到 .NET 6 的详细示例。
对为 Web 应用模板生成的其他文件进行了一些更改:
- 已删除
Index.cshtml
和Privacy.cshtml
中的未使用using
语句。 -
RequestId
inError.cshtml
被声明为可为 null 的引用类型(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 核心模板代码中, "Microsoft": "Warning"
已更改为 "Microsoft.AspNetCore": "Warning"
。 此更改会导致记录命名空间 Microsoft
中的所有信息性消息,但Microsoft.AspNetCore
除外。 例如, Microsoft.EntityFrameworkCore
现在在信息级别记录。
有关新托管模型的更多详细信息,请参阅 常见问题解答 部分。 有关采用 NRT 和 .NET 编译器 null 状态分析的详细信息,请参阅 可以为 Null 的引用类型(NRT)和 .NET 编译器 null 状态静态分析 部分。
迁移到或使用 6.0 或更高版本的应用不需要使用新的最小托管模型
完全支持 ASP.NET Core 3.1 和 5.0 模板中使用的 Startup
和 Generic Host。
将 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())
块被删除,因为在开发模式下,开发人员异常页中间件默认是启用的。 有关详细信息,请参阅下一部分中 .NET 5 和 .NET 6 托管模型中的 ASP.NET Core 之间的差异 。
使用自定义依赖项注入(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
类手动解析。
.NET 5 中的 ASP.NET Core 与 .NET 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();
Startup
类不能在WebApplicationBuilder.Host
或WebApplicationBuilder.WebHost
中使用。 以下突出显示的代码引发异常: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();
IHostBuilder上的WebApplicationBuilder
WebApplicationBuilder.Host
实现不会延迟执行ConfigureServices或ConfigureAppConfigurationConfigureHostConfiguration方法。 不延迟执行允许代码使用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
,并导致 Service1
对 IService
的解析。
在 .NET 6 中为 ASP.NET Core 构建库
现有的 .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)
新的最小托管模型的能力是否较弱?
否。 新的托管模型在功能上等效于 98% 支持的
IHostBuilder
方案和方案IWebHostBuilder
。 有些高级情况需要针对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
按照本文前面的指南将应用更新到 .NET 6 后,请遵循 .NET 6 中 ASP.NET Core 中的新增功能链接,采用特定功能。
若要 为 Blazor 应用采用所有新的 6.0 功能,建议执行以下过程:
- 从其中Blazor一个项目模板创建新的 6.0 Blazor 项目。 有关详细信息,请参阅用于 ASP.NET Core Blazor 的工具。
- 将应用的组件和代码移动到 6.0 应用进行修改以采用新的 .NET 6 功能。
迁移 SPA 项目
从 SPA 扩展迁移 Angular 应用
请参阅此 GitHub 问题
从 SPA 扩展迁移 React 应用
请参阅此 GitHub 问题中的从 Spa 扩展迁移 React 应用程序
更新 Docker 映像
对于使用 Docker 的应用,请更新 DockerfileFROM
语句和脚本。 使用包含 .NET 6 运行时中的 ASP.NET Core 的基本映像。 请考虑在 .NET 5 和 .NET 6 中 ASP.NET Core 之间的以下命令 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 服务器
项目模板现在使用 Duende Identity 服务器。
重要
Duende Identity Server 是具有互惠许可协议的开源产品。 如果计划在生产环境中使用 Duende Identity 服务器,可能需要从 Duende Software 获取商业许可证并支付许可证费用。 有关详细信息,请参阅 Duende Software:许可证。
若要了解如何使用 Microsoft Azure Active Directory 进行 ASP.NET CoreIdentity,请参阅 Identity (dotnet/aspnetcore GitHub 存储库)。
添加一个名为DbSet<Key>
的Keys
属性到每个IdentityDbContext
中,以满足更新版本IPersistedGrantDbContext
的新要求。 密钥是 Duende Identity Server 存储协定的一部分所必需的。
public DbSet<Key> Keys { get; set; }
注释
必须为 Duende Identity 服务器重新创建现有迁移。
迁移到 .NET 6 中 ASP.NET Core 的代码示例
查看中断性变更
参阅以下资源:
- Identity:默认引导程序版本的用户界面已更改
- 从版本 .NET 5 迁移到 .NET 6 的重大更改:包括 ASP.NET Core 和 Entity Framework Core。
-
公告 GitHub 存储库(aspnet/Announcements,
6.0.0
label):包括中断性和非中断性信息。
可空引用类型(Nullable Reference Types, NRT)和 .NET 编译器的 null 状态静态分析
ASP.NET 核心项目模板使用可以为 null 的引用类型(NRT),.NET 编译器执行 null 状态静态分析。 这些功能随 C# 8 一起发布,默认为在 .NET 6(C# 10)或更高版本中使用 ASP.NET Core 生成的应用启用。
.NET 编译器的 null 状态静态分析警告可以作为本地更新文档示例或示例应用的指南,也可以被忽略。 若编译器警告在学习 .NET 过程中造成困扰,我们仅建议在文档示例和示例应用中通过在应用的项目文件中设置Nullable
为disable
来禁用 Null 状态静态分析。
不建议在生产项目中禁用 null 状态检查。
有关 NRT、MSBuild Nullable
属性和更新应用(包括 #pragma
指南)的详细信息,请参阅 C# 文档中的以下资源:
- 可为空引用类型
- 可空引用类型 (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