从 .NET 7 中的 ASP.NET Core 迁移到 .NET 8
本文介绍如何将现有 ASP.NET Core 7.0 项目更新为 ASP.NET Core 8.0。
先决条件
带有 ASP.NET 和 Web 开发工作负载的 Visual Studio 2022。
更新 global.json
中的 .NET SDK 版本
如果你依靠 global.json
文件来定向特定的 .NET Core SDK 版本,请将 version
属性更新为已安装的 .NET 8.0 SDK 版本。 例如:
{
"sdk": {
- "version": "7.0.100"
+ "version": "8.0.100"
}
}
更新目标框架
将项目文件的目标框架名字对象 (TFM) 更新为 net8.0
:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
- <TargetFramework>net7.0</TargetFramework>
+ <TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
</Project>
更新包引用
在项目文件中,将每个 Microsoft.AspNetCore.*
、Microsoft.EntityFrameworkCore.*
、Microsoft.Extensions.*
和 System.Net.Http.Json
包引用的 Version
属性更新为 8.00 或更高版本。 例如:
<ItemGroup>
- <PackageReference Include="Microsoft.AspNetCore.JsonPatch" Version="7.0.12" />
- <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.12" />
- <PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="7.0.0" />
- <PackageReference Include="System.Net.Http.Json" Version="7.0.1" />
+ <PackageReference Include="Microsoft.AspNetCore.JsonPatch" Version="8.0.0" />
+ <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.0" />
+ <PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="8.0.0" />
+ <PackageReference Include="System.Net.Http.Json" Version="8.0.0" />
</ItemGroup>
Blazor
涵盖以下迁移方案:
- 更新 Blazor Server 应用
- 采用所有 Blazor Web App 约定
- 将 Blazor Server 应用转换为 Blazor Web App
- 更新 Blazor WebAssembly 应用
- 将托管的 Blazor WebAssembly 应用转换为 Blazor Web App
- 更新服务和终结点选项配置
- 使用 Yarp 路由解决方法删除 Blazor Server
- 在布局组件中迁移
CascadingValue
组件 - 迁移
BlazorEnableCompression
MSBuild 属性 - 将
<CascadingAuthenticationState>
组件迁移到级联身份验证状态服务 - 新文章:迁移过程中的 HTTP 缓存问题
- 新文章:关于使用静态服务器端呈现(静态 SSR)的类库的新文章
- 从其他程序集中发现组件
- 从查询字符串提供参数时删除
[Parameter]
属性 - Blazor Server 脚本回退策略授权
有关向 ASP.NET Core 应用添加 Blazor 支持的指导,请参阅将 ASP.NET Core Razor 组件集成到 ASP.NET Core 应用。
更新 Blazor Server 应用
建议在 .NET 8 中使用 Blazor Web App,但支持 Blazor Server。 若要继续在 .NET 8 中使用 Blazor Server,请按照本文前三个部分中的指导进行操作:
为 Blazor Web App 引入的新 Blazor 功能不适用于已更新为在 .NET 8 中运行的 Blazor Server 应用。 如果你想要采用新的 .NET 8 Blazor 功能,请按照以下任一部分中的指导进行操作:
采用所有 Blazor Web App 约定
若要选择采用所有新的 Blazor Web App 约定,建议执行以下过程:
- 从 Blazor Web App 项目模板创建新应用。 有关详细信息,请参阅用于 ASP.NET Core Blazor 的工具。
- 将应用的组件和代码移动到新的 Blazor Web App,进行修改以采用新功能。
- 更新 Blazor Web App 的布局和样式。
ASP.NET Core 8.0 的新增功能介绍了新的 .NET 8 功能。 从 .NET 6 或更早版本更新应用时,请参阅迁移和发行说明(新增功能文章),了解干预版本。
将 Blazor Server 应用转换为 Blazor Web App
.NET 8 支持 Blazor Server 应用,无需进行任何代码更改。 使用以下指导将 Blazor Server 应用转换为等效的 .NET 8 Blazor Web App,使所有新的 .NET 8 功能可用。
重要
本部分重点介绍将 .NET 7 Blazor Server 应用转换为 .NET 8 Blazor Web App 所需的最小更改。 若要采用所有新的 Blazor Web App 约定,请按照采用所有 Blazor Web App 约定部分中的指导进行操作。
按照本文前三部分中的指导进行操作:
将
App
组件 (App.razor
) 的内容移动到添加到项目的根文件夹中的新Routes
组件文件 (Routes.razor
)。 将空App.razor
文件保留在项目的根文件夹中的应用中。向
_Imports.razor
文件添加一个条目,使速记呈现模式可供应用使用:@using static Microsoft.AspNetCore.Components.Web.RenderMode
将
_Host
页 (Pages/_Host.cshtml
) 中的内容移动到空的App.razor
文件中。 继续对App
组件进行以下更改。注意
在下面的示例中,项目的命名空间为
BlazorServerApp
。 调整命名空间以匹配项目。从文件的顶部删除以下行:
- @page "/" - @using Microsoft.AspNetCore.Components.Web - @namespace BlazorServerApp.Pages - @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
将前面的行替换为用于注入 IHostEnvironment 实例的行:
@inject IHostEnvironment Env
从
<base>
标记的href
中删除波形符 (~
),并替换为应用的基本路径:- <base href="~/" /> + <base href="/" />
删除 HeadOutlet 组件的组件标记帮助程序,并将其替换为 HeadOutlet 组件。
删除以下行:
- <component type="typeof(HeadOutlet)" render-mode="ServerPrerendered" />
将前面的行替换为以下内容:
<HeadOutlet @rendermode="InteractiveServer" />
删除
App
组件的组件标记帮助程序,并将其替换为Routes
组件。删除以下行:
- <component type="typeof(App)" render-mode="ServerPrerendered" />
将前面的行替换为以下内容:
<Routes @rendermode="InteractiveServer" />
注意
上述配置假定应用的组件采用交互式服务器呈现。 有关详细信息,包括如何采用静态服务器端呈现 (SSR),请参阅 ASP.NET 核心 Blazor 呈现模式。
删除错误 UI 的环境标记帮助程序,并将其替换为以下 Razor 标记。
删除以下各行:
- <environment include="Staging,Production"> - An error has occurred. This application may no longer respond until reloaded. - </environment> - <environment include="Development"> - An unhandled exception has occurred. See browser dev tools for details. - </environment>
将前面的行替换为以下内容:
@if (Env.IsDevelopment()) { <text> An unhandled exception has occurred. See browser dev tools for details. </text> } else { <text> An error has occurred. This app may no longer respond until reloaded. </text> }
将 Blazor 脚本从
blazor.server.js
更改为blazor.web.js
:- <script src="_framework/blazor.server.js"></script> + <script src="_framework/blazor.web.js"></script>
删除
Pages/_Host.cshtml
文件,更新
Program.cs
:注意
在下面的示例中,项目的命名空间为
BlazorServerApp
。 调整命名空间以匹配项目。将
using
语句添加到项目命名空间的文件顶部:using BlazorServerApp;
将 AddServerSideBlazor 替换为 AddRazorComponents 和对 AddInteractiveServerComponents 的链式调用。
删除以下行:
- builder.Services.AddServerSideBlazor();
将前面的行替换为 Razor 组件和交互式服务器组件服务。 默认情况下,调用 AddRazorComponents 会添加防伪服务 (AddAntiforgery)。
builder.Services.AddRazorComponents() .AddInteractiveServerComponents();
删除以下行:
- app.MapBlazorHub();
将前面的行替换为对 MapRazorComponents 的调用,将
App
组件作为根组件类型提供,并向 AddInteractiveServerRenderMode 添加链式调用:app.MapRazorComponents<App>() .AddInteractiveServerRenderMode();
删除以下行:
- app.MapFallbackToPage("/_Host");
删除路由中间件:
- app.UseRouting();
在添加 HTTPS 重定向中间件的行之后,将 Antiforgery 中间件添加到请求处理管道(
app.UseHttpsRedirection
):app.UseAntiforgery();
上述调用
app.UseAntiforgery
必须在调用(如果存在)和app.UseAuthentication
app.UseAuthorization
之后进行。 无需显式添加反forgery 服务(builder.Services.AddAntiforgery
),因为它们是自动添加的 AddRazorComponents,前面已涵盖。如果 Blazor Server 应用配置为禁用预呈现,则可以继续禁用更新的应用预呈现。 在
App
组件中,更改分配给 HeadOutlet 和Routes
组件的@rendermode
Razor 指令属性的值。更改 HeadOutlet 和
Routes
组件的@rendermode
指令属性的值以禁用预呈现:- @rendermode="InteractiveServer" + @rendermode="new InteractiveServerRenderMode(prerender: false)"
有关详细信息,请参阅 ASP.NET Core Blazor 呈现模式。
更新 Blazor WebAssembly 应用
按照本文前三部分中的指导进行操作:
对于采用延迟程序集加载的应用,在应用的实现中将文件扩展名从 .dll
更改为 .wasm
,以反映 Blazor WebAssembly采用 Webcil 程序集打包。
在 .NET 8 版本之前,“ASP.NET Core 托管的 Blazor WebAssembly 应用的部署布局”中的指导通过多部分绑定方法解决了阻止客户端下载和执行 DLL 的环境问题。 在 .NET 8 或更高版本中,Blazor 使用 Webcil 文件格式解决此问题。 .NET 8 或更高版本中的 Blazor 应用不支持使用 WebAssembly 部署布局文章中所述的试验 NuGet 包进行多部分捆绑。 如果想要继续在 .NET 8 或更高版本应用中使用多部分捆绑包,则可以按照本文中的指导创建自己的多部分捆绑 NuGet 包,但 Microsoft 不支持该包。
将托管的 Blazor WebAssembly 应用转换为 Blazor Web App
.NET 8 支持 Blazor WebAssembly 应用,无需进行任何代码更改。 使用以下指导将 ASP.NET Core 托管的 Blazor WebAssembly 应用转换为等效的 .NET 8 Blazor Web App,使所有新的 .NET 8 功能可用。
重要
本部分重点介绍将 .NET 7 ASP.NET Core 托管的 Blazor WebAssembly 应用转换为 .NET 8 Blazor Web App 所需的最小更改。 若要采用所有新的 Blazor Web App 约定,请按照采用所有 Blazor Web App 约定部分中的指导进行操作。
按照本文前三部分中的指导进行操作:
重要
使用前面的指导更新解决方案的
.Client
、.Server
和.Shared
项目。在
.Client
项目文件 (.csproj
) 中,添加以下 MS Build 属性:<NoDefaultLaunchSettingsFile>true</NoDefaultLaunchSettingsFile> <StaticWebAssetProjectMode>Default</StaticWebAssetProjectMode>
另外,请从
.Client
项目文件中移除Microsoft.AspNetCore.Components.WebAssembly.DevServer
包引用:- <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer"... />
将文件内容从
.Client/wwwroot/index.html
文件移动到在.Server
项目的根目录中创建的新App
组件文件 (App.razor
)。 移动文件的内容后,删除index.html
文件。将
.Client
项目中的App.razor
重命名为Routes.razor
。在
Routes.razor
中,将AppAssembly
属性的值更新为typeof(Program).Assembly
。在
.Client
项目中,向_Imports.razor
文件添加一个条目,使速记呈现模式可供应用使用:@using static Microsoft.AspNetCore.Components.Web.RenderMode
创建
.Client
项目的_Imports.razor
文件的副本,并将其添加到.Server
项目中。对
App.razor
文件进行以下更改:将网站的默认网站标题 (
<title>...</title>
) 替换为 HeadOutlet 组件。 记下该网站标题供以后使用,并移除标题标签和标题:- <title>...</title>
在移除标题的位置,放置一个分配交互式 WebAssembly 呈现模式(禁用预呈现)的 HeadOutlet 组件:
<HeadOutlet @rendermode="new InteractiveWebAssemblyRenderMode(prerender: false)" />
- <link href="{CLIENT PROJECT ASSEMBLY NAME}.styles.css" rel="stylesheet"> + <link href="{SERVER PROJECT ASSEMBLY NAME}.styles.css" rel="stylesheet">
前面代码中的占位符:
{CLIENT PROJECT ASSEMBLY NAME}
:客户端项目程序集名称。 示例:BlazorSample.Client
{SERVER PROJECT ASSEMBLY NAME}
:服务器项目程序集名称。 示例:BlazorSample.Server
找到以下
<div>...</div>
HTML 标记:- <div id="app"> - ... - </div>
使用交互式 WebAssembly 呈现模式(禁用预呈现)将上述
<div>...</div>
HTML 标记替换为Routes
组件:<Routes @rendermode="new InteractiveWebAssemblyRenderMode(prerender: false)" />
将
blazor.webassembly.js
脚本更新为blazor.web.js
:- <script src="_framework/blazor.webassembly.js"></script> + <script src="_framework/blazor.web.js"></script>
打开
.Client
项目的布局文件 (.Client/Shared/MainLayout.razor
),并添加具有网站默认标题({TITLE}
占位符)的 PageTitle 组件:<PageTitle>{TITLE}</PageTitle>
从
.Client/Program.cs
中删除以下行:- builder.RootComponents.Add<App>("#app"); - builder.RootComponents.Add<HeadOutlet>("head::after");
更新
.Server/Program.cs
:向项目添加 Razor 组件和交互式 WebAssembly 组件服务。 通过对 AddInteractiveWebAssemblyComponents 的链式调用来调用 AddRazorComponents。 默认情况下,调用 AddRazorComponents 会添加防伪服务 (AddAntiforgery)。
builder.Services.AddRazorComponents() .AddInteractiveWebAssemblyComponents();
将 Antiforgery 中间件添加到请求处理管道。
在调用
app.UseHttpsRedirection
后放置以下行。app.UseAntiforgery
调用必须在调用后(如果存在)和app.UseAuthentication
app.UseAuthorization
。 无需显式添加反forgery 服务(builder.Services.AddAntiforgery
),因为它们是自动添加的 AddRazorComponents,前面已涵盖。app.UseAntiforgery();
删除以下行:
- app.UseBlazorFrameworkFiles();
删除以下行:
- app.MapFallbackToFile("index.html");
将前面的行替换为对 MapRazorComponents 的调用,将
App
组件作为根组件类型提供,并向 AddInteractiveWebAssemblyRenderMode 和 AddAdditionalAssemblies 添加链式调用:app.MapRazorComponents<App>() .AddInteractiveWebAssemblyRenderMode() .AddAdditionalAssemblies(typeof({CLIENT APP NAMESPACE}._Imports).Assembly);
在前面的示例中,
{CLIENT APP NAMESPACE}
占位符是.Client
项目的命名空间(例如,HostedBlazorApp.Client
)。从
.Server
项目运行解决方案:对于 Visual Studio,确认在运行应用时在解决方案资源管理器中选择了
.Server
项目。如果使用 .NET CLI,请从
.Server
项目的文件夹运行项目。
更新服务和终结点选项配置
随着 .NET 8 中 Blazor Web App 的发布,Blazor 服务和终结点选项配置已更新,引入了用于交互式组件服务和组件终结点配置的新 API。
更新的配置指南出现在以下位置:
- 设置和读取应用环境:包含更新的指导,尤其是在标题为“在 Blazor Web App 中读取客户端环境”的部分中。
- 服务器端线路处理程序选项:包括新的 Blazor-SignalR 线路和中心选项配置。
- 从 JavaScript 呈现 Razor 组件:包括使用 RegisterForJavaScript 进行动态组件注册的功能。
- Blazor 自定义元素:Blazor Web App 注册:包括使用
RegisterCustomElement
进行根组件自定义元素注册的功能。 - Blazor WebAssembly 资产的前缀:包括对指示 Blazor WebAssembly 资产前缀的路径字符串的控制。
- 临时重定向 URL 有效期:包括对 Blazor 服务器端呈现发出的临时重定向 URL 的数据保护有效性生存期的控制。
- 详细错误:包括为 Razor 组件服务器端呈现启用详细错误的功能。
- 预呈现配置:默认情况下为 Blazor Web App 启用预呈现。 如果存在需要应用禁用预呈现的特殊情况,请单击此链接获取有关如何禁用预呈现的指南。
- 表单绑定选项:涵盖表单绑定选项配置。
使用 Yarp 路由解决方法删除 Blazor Server
如果之前遵循《在增量迁移中通过 Yarp 启用 ASP.NET Core Blazor Server 支持》中的指导使用 Yarp 将 Blazor Server 应用迁移到 .NET 6 或 .NET 7,可以反向执行按照本文指导所执行的解决步骤。 包含 Yarp 的 Blazor Server 的路由和深层链接在 .NET 8 中正常工作。
在布局组件中迁移CascadingValue
组件
级联参数不会跨呈现模式边界传递数据,并且布局以静态方式呈现在其他交互式应用中。 因此,寻求在交互式呈现的组件中使用级联参数的应用将无法级联布局中的值。
迁移的两种方法为:
- (建议)将状态作为根级级联值传递。 有关详细信息,请参阅根级级联值。
- 使用
CascadingValue
组件将路由器包装在Routes
组件中,并使Routes
组件以交互方式呈现。 有关示例,请参阅CascadingValue
组件。
有关详细信息,请参阅级联值/参数和呈现模式边界。
迁移BlazorEnableCompression
MSBuild 属性
对于禁用压缩和面向 .NET 7 或更早版本但使用 .NET 8 SDK 生成的Blazor WebAssembly应用,BlazorEnableCompression
MSBuild 属性已更改为CompressionEnabled
:
<PropertyGroup>
- <BlazorEnableCompression>false</BlazorEnableCompression>
+ <CompressionEnabled>false</CompressionEnabled>
</PropertyGroup>
使用 .NET CLI 发布命令时,请使用新属性:
dotnet publish -p:CompressionEnabled=false
有关详细信息,请参阅以下资源:
将 <CascadingAuthenticationState>
组件迁移到级联身份验证状态服务
在 .NET 7 或更早版本中,组件 CascadingAuthenticationState 包装在 UI 树的某些部分(例如围绕路由器周围 Blazor)以提供级联身份验证状态:
<CascadingAuthenticationState>
<Router ...>
...
</Router>
</CascadingAuthenticationState>
在 .NET 8 中,请勿使用 CascadingAuthenticationState 组件:
- <CascadingAuthenticationState>
<Router ...>
...
</Router>
- </CascadingAuthenticationState>
而是通过在 Program
文件中调用 AddCascadingAuthenticationState,将级联身份验证状态服务添加到服务集合:
builder.Services.AddCascadingAuthenticationState();
有关详细信息,请参阅以下资源:
- ASP.NET Core Blazor 身份验证和授权
- 为 ASP.NET Core 服务器端 Blazor 应用提供保护
有关 HTTP 缓存问题的新文章
我们添加了一篇新文章,讨论在跨主要版本升级 Blazor 应用时可能发生的一些常见 HTTP 缓存问题,以及如何解决 HTTP 缓存问题。
有关详细信息,请参阅在升级 ASP.NET Core Blazor 应用时避免 HTTP 缓存问题。
关于使用静态服务器端呈现(静态 SSR)的类库的新文章
我们新增了一篇文章,其中讨论了使用静态服务器端呈现(静态 SSR)的 Razor 类库 (RCL) 中的组件库创作。
有关详细信息,请参阅使用静态服务器端呈现(静态 SSR)的 ASP.NET Core Razor 类库 (RCL)。
从其他程序集中发现组件
从 Blazor Server 应用迁移到 Blazor Web App 时,如果应用使用来自其他程序集(例如组件类库)的可路由组件,请参阅 ASP.NET Core Blazor 路由和导航中的指导。
从查询字符串提供参数时删除 [Parameter]
属性
从查询字符串提供参数时,不再需要 [Parameter]
属性:
- [Parameter]
[SupplyParameterFromQuery]
Blazor Server 脚本回退策略授权
在 .NET 7 中,Blazor Server 脚本 (blazor.server.js
) 由静态文件中间件提供。 在 .NET 7 应用中,在调用授权中间件 (UseAuthorization) 之前将对静态文件中间件 (UseStaticFiles) 的调用放在请求处理管道中就足以向匿名用户提供 Blazor 脚本。
在 .NET 8 中,Blazor Server 脚本由其自己的终结点提供(使用终结点路由)。 此更改由以下资源引入:修复了 Bug - 将选项传递给 UseStaticFiles 时中断Blazor Server (dotnet/aspnetcore
#45897)。
请考虑多租户场景,其中:
- 默认策略和回退策略的设置方式都相同。
- 使用请求路径中的第一段(例如
tld.com/tenant-name/...
)解析租户。 - 向租户终结点发出的请求通过其他身份验证方案进行身份验证,该方案可向请求主体添加其他 identity。
- 回退授权策略要求通过其他 identity 检查声明。
针对 Blazor 脚本文件 (blazor.server.js
) 的请求在 /_framework/blazor.server.js
中提供,此服务器在框架中进行了硬编码。 针对文件的请求未通过租户的附加身份验证方案进行身份验证,但仍会受到回退策略的质询,这会导致返回未经授权的结果。
目前正在对 MapRazorComponents 中的一个新框架功能评估此问题,该组件已被 FallbackPolicy RequireAuthenticatedUser (dotnet/aspnetcore
51836) 损坏,目前计划于 2024 年 11 月发布 .NET 9。 在此之前,可以使用以下三种方法中的任何一种方法解决此问题:
不使用回退策略。 在
_Imports.razor
文件中应用[Authorize]
属性,将其应用于应用的所有组件。 对于非 blazor 终结点,显式使用[Authorize]
或RequireAuthorization
。将
[AllowAnonymous]
添加到Program
文件中的/_framework/blazor.server.js
终结点:app.MapBlazorHub().Add(endpointBuilder => { if (endpointBuilder is RouteEndpointBuilder { RoutePattern: { RawText: "/_framework/blazor.server.js" } }) { endpointBuilder.Metadata.Add(new AllowAnonymousAttribute()); } });
注册自定义
AuthorizationHandler
,以检查HttpContext
是否允许/_framework/blazor.server.js
文件通过。
Docker
更新 Docker 映像
对于使用 Docker 的应用,请更新 Dockerfile FROM
语句和脚本。 使用包含 ASP.NET Core 8.0 运行时的基础映像。 请注意 ASP.NET Core 7.0 和 8.0 之间的以下 docker pull
命令差异:
- docker pull mcr.microsoft.com/dotnet/aspnet:7.0
+ docker pull mcr.microsoft.com/dotnet/aspnet:8.0
更新 Docker 端口
.NET 容器映像中配置的默认 ASP.NET Core 端口已从端口 80 更新为 8080。
添加了新的 ASPNETCORE_HTTP_PORTS
环境变量,作为 ASPNETCORE_URLS
的更简单的替代方法。
有关详细信息,请参阅:
查看中断性变更
有关从 .NET Core .NET 7.0 到 8.0 的中断性变更,请参阅 .NET 8 中的中断性变更,其中包括 ASP.NET Core 和 Entity Framework Core 部分。