从 .NET 7 中的 ASP.NET Core 迁移到 .NET 8

本文介绍如何将 .NET 7 项目中的现有 ASP.NET Core 更新为 .NET 8。

先决条件

更新 global.json 中的 .NET SDK 版本

如果依赖 global.json 文件以特定 .NET SDK 版本为目标,请将 version 属性更新为已安装的 .NET 8 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.0.0 或更高版本。 例如:

<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

涵盖以下迁移方案:

有关向 ASP.NET Core 应用添加 Blazor 支持的指导,请参阅 将 ASP.NET Core Razor 组件与 MVC 或 Razor Pages 集成

更新 Blazor Server 应用

建议在 .NET 8 中使用 Blazor Web App,但支持 Blazor Server。 若要继续在 .NET 8 中使用 Blazor Server,请按照本文前三个部分中的指导进行操作:

为 Blazor 引入的新 Blazor Web App 功能不适用于已更新为在 .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 的布局和样式。

.NET 8 中的新增功能在 .NET 8 ASP.NET Core 中的新增功能中进行了介绍。 从 .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 约定 ”部分中的指导进行作。

  1. 按照本文前三部分中的指导进行操作:

  2. App 组件 (App.razor) 的内容移动到添加到项目的根文件夹中的新 Routes 组件文件 (Routes.razor)。 将空 App.razor 文件保留在项目的根文件夹中的应用中。

  3. _Imports.razor 文件添加一个条目,使速记呈现模式可供应用使用:

    @using static Microsoft.AspNetCore.Components.Web.RenderMode
    
  4. _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
    

    ~ 标记的 href 中删除波形符 (<base>),并替换为应用的基本路径:

    - <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>
    
  5. 删除 Pages/_Host.cshtml 文件,

  6. 更新 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.UseAuthenticationapp.UseAuthorization之后进行。 无需显式添加反forgery 服务(builder.Services.AddAntiforgery),因为它们是自动添加的 AddRazorComponents,前面已涵盖。

  7. 如果 Blazor Server 应用配置为禁用预呈现,则可以继续禁用更新的应用预呈现。 在 App 组件中,更改分配给 @rendermode 和 Razor 组件的 HeadOutletRoutes 指令属性的值。

    更改 @rendermodeHeadOutlet 组件的 Routes 指令属性的值以禁用预呈现:

    - @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文章中所述的试验 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 约定 ”部分中的指导进行作。

  1. 按照本文前三部分中的指导进行操作:

    重要

    使用前面的指导更新解决方案的 .Client.Server.Shared 项目。

  2. .Client 项目文件 (.csproj) 中,添加以下 MS Build 属性:

    <NoDefaultLaunchSettingsFile>true</NoDefaultLaunchSettingsFile>
    <StaticWebAssetProjectMode>Default</StaticWebAssetProjectMode>
    

    另外,请从 .Client 项目文件中移除 Microsoft.AspNetCore.Components.WebAssembly.DevServer 包引用:

    - <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer"... />
    
  3. 将文件内容从 .Client/wwwroot/index.html 文件移动到在 App 项目的根目录中创建的新 App.razor 组件文件 (.Server)。 移动文件的内容后,删除 index.html 文件。

    App.razor 项目中的 .Client 重命名为 Routes.razor

    Routes.razor 中,将 AppAssembly 属性的值更新为 typeof(Program).Assembly

  4. .Client 项目中,向 _Imports.razor 文件添加一个条目,使速记呈现模式可供应用使用:

    @using static Microsoft.AspNetCore.Components.Web.RenderMode
    

    创建 .Client 项目的 _Imports.razor 文件的副本,并将其添加到 .Server 项目中。

  5. App.razor 文件进行以下更改:

    将网站的默认网站标题 (<title>...</title>) 替换为 HeadOutlet 组件。 记下该网站标题供以后使用,并移除标题标签和标题:

    - <title>...</title>
    

    在移除标题的位置,放置一个分配交互式 WebAssembly 呈现模式(禁用预呈现)的 HeadOutlet 组件:

    <HeadOutlet @rendermode="new InteractiveWebAssemblyRenderMode(prerender: false)" />
    

    更改 CSS 样式捆绑包

    - <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>
    
  6. 打开 .Client 项目的布局文件 (.Client/Shared/MainLayout.razor),并添加具有网站默认标题(PageTitle 占位符)的 {TITLE} 组件:

    <PageTitle>{TITLE}</PageTitle>
    

    注释

    其他布局文件也应接收具有默认网站标题的 PageTitle 组件。

    有关详细信息,请参阅 ASP.NET Core Blazor 应用中的控制头内容

  7. .Client/Program.cs 中删除以下行:

    - builder.RootComponents.Add<App>("#app");
    - builder.RootComponents.Add<HeadOutlet>("head::after");
    
  8. 更新 .Server/Program.cs

    向项目添加 Razor 组件和交互式 WebAssembly 组件服务。 通过对 AddRazorComponents 的链式调用来调用 AddInteractiveWebAssemblyComponents。 默认情况下,调用 AddRazorComponents 会添加防伪服务 (AddAntiforgery)。

    builder.Services.AddRazorComponents()
        .AddInteractiveWebAssemblyComponents();
    

    Antiforgery 中间件 添加到请求处理管道。

    在调用 app.UseHttpsRedirection后放置以下行。 app.UseAntiforgery调用必须在调用后(如果存在)和 app.UseAuthenticationapp.UseAuthorization。 无需显式添加反forgery 服务(builder.Services.AddAntiforgery),因为它们是自动添加的 AddRazorComponents,前面已涵盖。

    app.UseAntiforgery();
    

    删除以下行:

    - app.UseBlazorFrameworkFiles();
    

    删除以下行:

    - app.MapFallbackToFile("index.html");
    

    将前面的行替换为对 MapRazorComponents 的调用,将 App 组件作为根组件类型提供,并向 AddInteractiveWebAssemblyRenderModeAddAdditionalAssemblies 添加链式调用:

    app.MapRazorComponents<App>()
        .AddInteractiveWebAssemblyRenderMode()
        .AddAdditionalAssemblies(typeof({CLIENT APP NAMESPACE}._Imports).Assembly);
    

    在前面的示例中,{CLIENT APP NAMESPACE} 占位符是 .Client 项目的命名空间(例如,HostedBlazorApp.Client)。

  9. .Server 项目运行解决方案:

    对于 Visual Studio,确认在运行应用时在.Server中选择了 项目。

    如果使用 .NET CLI,请从 .Server 项目的文件夹运行项目。

更新服务和终结点选项配置

随着 .NET 8 中 Blazor Web App 的发布,Blazor 服务和终结点选项配置已更新,引入了用于交互式组件服务和组件终结点配置的新 API。

更新的配置指南出现在以下位置:

使用 Yarp 路由解决方法删除 Blazor Server

如果您之前遵循了文章“ 在增量迁移中使用 Yarp 启用 ASP.NET Core 支持”中的指南,将 Yarp 应用程序迁移到 .NET 6 或 .NET 7,那么您可以撤销之前按照该文章指导所采取的解决方法步骤。 包含 Yarp 的 Blazor Server 的路由和深层链接在 .NET 8 中正常工作。

在布局组件中迁移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>

而是通过在 AddCascadingAuthenticationState 文件中调用 Program,将级联身份验证状态服务添加到服务集合:

builder.Services.AddCascadingAuthenticationState();

有关详细信息,请参阅以下资源:

有关 HTTP 缓存问题的新文章

我们添加了一篇新文章,讨论在跨主要版本升级 Blazor 应用时可能发生的一些常见 HTTP 缓存问题,以及如何解决 HTTP 缓存问题。

有关详细信息,请参阅在升级 ASP.NET Core Blazor 应用时避免 HTTP 缓存问题

关于使用静态服务器端渲染(SSR)的类库的新文章

我们新增了一篇文章,讨论了在包含静态服务器端呈现(静态 SSR)的 Razor 类库 (RCL) 中的组件库开发。

有关详细信息,请参阅Razor。

从其他程序集中发现组件

从应用迁移到 a Blazor ServerBlazor Web App时,如果应用使用其他程序集(例如组件类库)中的可路由组件,则访问 ASP.NET 核心 Blazor 路由和导航 中的指南。

从查询字符串提供参数时删除 [Parameter] 属性

从查询字符串提供参数时,不再需要 [Parameter] 属性:

- [Parameter]
  [SupplyParameterFromQuery]

Blazor Server 脚本回退策略授权

在 .NET 7 中,脚本 Blazor Server(blazor.server.js由静态文件中间件托管。 在 .NET 7 应用中,只需在请求处理管道中将静态文件中间件(UseStaticFiles)的调用放在授权中间件(UseAuthorization)之前,就可以为匿名用户提供 Blazor 脚本。

在 .NET 8 中,Blazor Server脚本通过终结点路由在其专属终结点上提供服务。 此更改是通过修复 bug 引入的 - 将选项传递给 UseStaticFiles 中断Blazor Server(dotnet/aspnetcore#45897)。

请考虑多租户场景,其中:

  • 默认策略和回退策略的设置方式都相同。
  • 使用请求路径中的第一段(例如 tld.com/tenant-name/...)解析租户。
  • 向租户终结点发出的请求通过其他身份验证方案进行身份验证,该方案向请求主体添加其他标识。
  • 回退授权策略要求通过其他标识检查声明。

针对 Blazor 脚本文件 (blazor.server.js) 的请求在 /_framework/blazor.server.js 中提供,此服务器在框架中进行了硬编码。 对文件的请求不经过租户其他身份验证方案的验证,但仍会被备用策略验证,从而导致返回未经授权的结果。

此问题正在评估,以用于MapRazorComponents 中因 FallbackPolicy RequireAuthenticatedUser (dotnet/aspnetcore 51836)而中断的新框架功能,这项功能目前计划于 2024 年 11 月发布.NET 9。 在此之前,可以使用以下三种方法中的任何一种方法解决此问题:

  • 不使用回退策略。 在 [Authorize] 文件中应用 _Imports.razor 属性,将其应用于应用的所有组件。 对于非 blazor 终结点,显式使用 [Authorize]RequireAuthorization

  • [AllowAnonymous] 添加到 /_framework/blazor.server.js 文件中的 Program 终结点:

    app.MapBlazorHub().Add(endpointBuilder =>
    {
        if (endpointBuilder is 
            RouteEndpointBuilder
            { 
                RoutePattern: { RawText: "/_framework/blazor.server.js" }
            })
        {
            endpointBuilder.Metadata.Add(new AllowAnonymousAttribute());
        }
    });
    
  • 注册一个用于AuthorizationHandler以便允许HttpContext文件通过的自定义

Docker

更新 Docker 映像

对于使用 Docker 的应用,请更新 Dockerfile 语句和脚本FROM。 使用包含 .NET 8 运行时的基本映像。 请考虑在 .NET 7 和 .NET 8 中 ASP.NET Core 之间的以下命令 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 中的重大变化》中的文章,以帮助您在将应用程序升级到 .NET 的较新版本时查找可能适用的重大变化。