Nguon: Microsoft Learn · .NET 8.0

Migration (Di chuyển) ứng dụng ASP.NET Core

Nguồn: Migrate to newer versions of ASP.NET Core | Phiên bản: .NET 8.0

Bài viết này giải thích cách cập nhật (upgrade) một dự án ASP.NET Core trong .NET 7 lên .NET 8.

Prerequisites (Điều kiện tiên quyết)

Visual Studio

!VS22 installer workloads

Visual Studio Code

Các hướng dẫn dành cho Visual Studio Code sử dụng .NET CLI cho các chức năng phát triển ASP.NET Core như tạo dự án. Bạn có thể làm theo các hướng dẫn này trên macOS, Linux hoặc Windows và với bất kỳ trình soạn thảo code nào. Có thể cần thực hiện một số thay đổi nhỏ nếu bạn sử dụng trình soạn thảo khác ngoài Visual Studio Code.


Cập nhật phiên bản .NET SDK trong global.json

Nếu bạn dựa vào file global.json để nhắm đến một phiên bản .NET SDK cụ thể, hãy cập nhật thuộc tính version sang phiên bản .NET 8 SDK đã được cài đặt. Ví dụ:

diff
{
  "sdk": {
-    "version": "7.0.100"
+    "version": "8.0.100"
  }
}

Cập nhật Target Framework (Khung mục tiêu)

Cập nhật Target Framework Moniker (TFM) trong file dự án thành net8.0:

diff
<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
-    <TargetFramework>net7.0</TargetFramework>
+    <TargetFramework>net8.0</TargetFramework>
  </PropertyGroup>

</Project>

Cập nhật Package References (Tham chiếu gói)

Trong file dự án, cập nhật thuộc tính Version của mỗi package reference Microsoft.AspNetCore.*, Microsoft.EntityFrameworkCore.*, Microsoft.Extensions.*, và System.Net.Http.Json lên 8.0.0 hoặc cao hơn. Ví dụ:

diff
<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

Các kịch bản migration (di chuyển) sau đây được đề cập:

Để biết hướng dẫn về cách thêm hỗ trợ Blazor vào ứng dụng ASP.NET Core, xem Integrate ASP.NET Core Razor components with MVC or Razor Pages.

Cập nhật ứng dụng Blazor Server

Chúng tôi khuyến nghị sử dụng Blazor Web Apps trong .NET 8, nhưng Blazor Server vẫn được hỗ trợ. Để tiếp tục sử dụng Blazor Server với .NET 8, hãy làm theo hướng dẫn trong ba phần đầu tiên của bài viết này:

Các tính năng Blazor mới được giới thiệu cho Blazor Web Apps không có sẵn cho ứng dụng Blazor Server được cập nhật để chạy trên .NET 8. Nếu bạn muốn áp dụng các tính năng Blazor .NET 8 mới, hãy làm theo hướng dẫn trong một trong các phần sau:

Áp dụng toàn bộ các quy ước của Blazor Web App

Để tùy chọn áp dụng tất cả các quy ước mới của Blazor Web App, chúng tôi khuyến nghị quy trình sau:

Các tính năng .NET 8 mới được đề cập trong What's new in ASP.NET Core in .NET 8. Khi cập nhật từ .NET 6 hoặc phiên bản cũ hơn, hãy xem các hướng dẫn migration (di chuyển) và ghi chú phát hành (What's new articles) cho các phiên bản trung gian.

Chuyển đổi ứng dụng Blazor Server thành Blazor Web App

Các ứng dụng Blazor Server được hỗ trợ trong .NET 8 mà không cần thay đổi code. Sử dụng hướng dẫn sau để chuyển đổi ứng dụng Blazor Server thành Blazor Web App tương đương với .NET 8, giúp cung cấp tất cả các tính năng .NET 8 mới.

Phần này tập trung vào các thay đổi tối thiểu cần thiết để chuyển đổi ứng dụng Blazor Server .NET 7 thành Blazor Web App .NET 8. Để áp dụng toàn bộ các quy ước mới của Blazor Web App, hãy làm theo hướng dẫn trong phần Áp dụng toàn bộ các quy ước của Blazor Web App.

  1. Làm theo hướng dẫn trong ba phần đầu tiên của bài viết này:
  1. Di chuyển nội dung của component App (App.razor) sang file component Routes mới (Routes.razor) được thêm vào thư mục gốc của dự án. Để lại file App.razor trống trong ứng dụng tại thư mục gốc của dự án.
  2. Thêm một mục vào file _Imports.razor để làm cho các render mode viết tắt (shorthand) có sẵn cho ứng dụng:

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

  1. Di chuyển nội dung trong trang _Host (Pages/_Host.cshtml) sang file App.razor trống. Tiến hành thực hiện các thay đổi sau đây cho component App.

> Lưu ý > > Trong ví dụ sau, namespace của dự án là BlazorServerApp. Điều chỉnh namespace cho phù hợp với dự án của bạn.

Xóa các dòng sau từ đầu file:

```diff

```

Thay thế các dòng trước bằng một dòng inject (tiêm) một instance IHostEnvironment:

``razor @inject IHostEnvironment Env ``

Xóa dấu ngã (~) khỏi href của thẻ <base> và thay thế bằng đường dẫn cơ sở cho ứng dụng của bạn:

```diff

```

Xóa Component Tag Helper cho component HeadOutlet và thay thế bằng component HeadOutlet.

Xóa dòng sau:

```diff

```

Thay thế dòng trước bằng:

``razor <HeadOutlet @rendermode="InteractiveServer" /> ``

Xóa Component Tag Helper cho component App và thay thế bằng component Routes.

Xóa dòng sau:

```diff

```

Thay thế dòng trước bằng:

``razor <Routes @rendermode="InteractiveServer" /> ``

> Lưu ý > > Cấu hình trên giả định rằng các component của ứng dụng áp dụng interactive server rendering (render phía server tương tác). Để biết thêm thông tin, bao gồm cách áp dụng static server-side rendering (static SSR), xem ASP.NET Core Blazor render modes.

Xóa các Environment Tag Helpers cho UI lỗi và thay thế chúng bằng Razor markup sau.

Xóa các dòng sau:

```diff

```

Thay thế các dòng trước bằng:

``razor @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> } ``

Thay đổi Blazor script từ blazor.server.js thành blazor.web.js:

```diff

```

  1. Xóa file Pages/_Host.cshtml.
  2. Cập nhật Program.cs:

> Lưu ý > > Trong ví dụ sau, namespace của dự án là BlazorServerApp. Điều chỉnh namespace cho phù hợp với dự án của bạn.

Thêm câu lệnh using vào đầu file cho namespace của dự án:

``csharp using BlazorServerApp; ``

Thay thế AddServerSideBlazor bằng AddRazorComponents và một lời gọi chained (liên kết) đến AddInteractiveServerComponents.

Xóa dòng sau:

```diff

```

Thay thế dòng trước bằng các Razor component và interactive server component services. Gọi AddRazorComponents sẽ thêm antiforgery services (AddAntiforgery) theo mặc định.

``csharp builder.Services.AddRazorComponents() .AddInteractiveServerComponents(); ``

Xóa dòng sau:

```diff

```

Thay thế dòng trước bằng lời gọi đến MapRazorComponents, cung cấp component App làm kiểu component gốc, và thêm lời gọi chained (liên kết) đến AddInteractiveServerRenderMode:

``csharp app.MapRazorComponents<App>() .AddInteractiveServerRenderMode(); ``

Xóa dòng sau:

```diff

```

Xóa Routing Middleware:

```diff

```

Thêm Antiforgery Middleware vào pipeline xử lý request (yêu cầu) sau dòng thêm HTTPS Redirection Middleware (app.UseHttpsRedirection):

``csharp app.UseAntiforgery(); ``

Lời gọi app.UseAntiforgery ở trên phải được đặt sau các lời gọi (nếu có) đến app.UseAuthenticationapp.UseAuthorization. Không cần phải thêm antiforgery services (builder.Services.AddAntiforgery) một cách tường minh, vì chúng đã được thêm tự động bởi AddRazorComponents như đã đề cập ở trên.

  1. Nếu ứng dụng Blazor Server được cấu hình để tắt prerendering (kết xuất trước), bạn có thể tiếp tục tắt prerendering cho ứng dụng đã cập nhật. Trong component App, hãy thay đổi giá trị được gán cho các directive attribute @rendermode của Razor cho các component HeadOutletRoutes.

Thay đổi giá trị của directive attribute @rendermode cho cả hai component HeadOutletRoutes để tắt prerendering:

```diff

```

Để biết thêm thông tin, xem ASP.NET Core Blazor render modes.

Cập nhật ứng dụng Blazor WebAssembly

Làm theo hướng dẫn trong ba phần đầu tiên của bài viết này:

Đối với các ứng dụng áp dụng lazy assembly loading (tải assembly lười biếng), hãy thay đổi phần mở rộng file từ .dll thành .wasm trong quá trình triển khai ứng dụng để phản ánh việc Blazor WebAssembly áp dụng Webcil assembly packaging.

Trước khi phát hành .NET 8, hướng dẫn trong Deployment layout for ASP.NET Core hosted Blazor WebAssembly apps xử lý các môi trường chặn client tải xuống và thực thi DLL bằng cách tiếp cận multipart bundling. Trong .NET 8 trở lên, Blazor sử dụng định dạng file Webcil để giải quyết vấn đề này. Multipart bundling sử dụng gói NuGet thử nghiệm được mô tả trong bài viết WebAssembly deployment layout không được hỗ trợ cho các ứng dụng Blazor trong .NET 8 trở lên. Nếu bạn muốn tiếp tục sử dụng gói multipart bundle trong .NET 8 trở lên, bạn có thể sử dụng hướng dẫn trong bài viết để tạo gói NuGet multipart bundling của riêng mình, nhưng nó sẽ không được Microsoft hỗ trợ.

Chuyển đổi ứng dụng Blazor WebAssembly được hosted thành Blazor Web App

Các ứng dụng Blazor WebAssembly được hỗ trợ trong .NET 8 mà không cần thay đổi code. Sử dụng hướng dẫn sau để chuyển đổi ứng dụng ASP.NET Core hosted Blazor WebAssembly thành Blazor Web App tương đương với .NET 8, giúp cung cấp tất cả các tính năng .NET 8 mới.

Phần này tập trung vào các thay đổi tối thiểu cần thiết để chuyển đổi ứng dụng ASP.NET Core hosted Blazor WebAssembly .NET 7 thành Blazor Web App .NET 8. Để áp dụng toàn bộ các quy ước mới của Blazor Web App, hãy làm theo hướng dẫn trong phần Áp dụng toàn bộ các quy ước của Blazor Web App.

  1. Làm theo hướng dẫn trong ba phần đầu tiên của bài viết này:

> Quan trọng > > Sử dụng hướng dẫn trên, hãy cập nhật các dự án .Client, .Server.Shared của solution.

  1. Trong file dự án .Client (.csproj), thêm các thuộc tính MSBuild sau:

``xml <NoDefaultLaunchSettingsFile>true</NoDefaultLaunchSettingsFile> <StaticWebAssetProjectMode>Default</StaticWebAssetProjectMode> ``

Cũng trong file dự án .Client, xóa package reference Microsoft.AspNetCore.Components.WebAssembly.DevServer:

```diff

```

  1. Di chuyển nội dung file từ file .Client/wwwroot/index.html sang file component App mới (App.razor) được tạo ở thư mục gốc của dự án .Server. Sau khi di chuyển nội dung file, hãy xóa file index.html.

Đổi tên App.razor trong dự án .Client thành Routes.razor.

Trong Routes.razor, cập nhật giá trị của thuộc tính AppAssembly thành typeof(Program).Assembly.

  1. Trong dự án .Client, thêm một mục vào file _Imports.razor để làm cho các render mode viết tắt (shorthand) có sẵn cho ứng dụng:

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

Tạo bản sao của file _Imports.razor từ dự án .Client và thêm nó vào dự án .Server.

  1. Thực hiện các thay đổi sau đây cho file App.razor:

Thay thế tiêu đề website mặc định (<title>...</title>) bằng component HeadOutlet. Lưu ý tiêu đề website để sử dụng sau này và xóa các thẻ title cùng tiêu đề:

```diff

```

Ở vị trí bạn đã xóa tiêu đề, đặt component HeadOutlet gán Interactive WebAssembly render mode (tắt prerendering):

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

Thay đổi CSS style bundle (gói CSS):

```diff

```

Các placeholder trong đoạn code trên:

Tìm HTML markup <div>...</div> sau:

```diff

```

Thay thế HTML markup <div>...</div> trên bằng component Routes sử dụng Interactive WebAssembly render mode (tắt prerendering):

``razor <Routes @rendermode="new InteractiveWebAssemblyRenderMode(prerender: false)" /> ``

Cập nhật script blazor.webassembly.js thành blazor.web.js:

```diff

```

  1. Mở file layout của dự án .Client (.Client/Shared/MainLayout.razor) và thêm component PageTitle với tiêu đề website mặc định (placeholder {TITLE}):

``razor <PageTitle>{TITLE}</PageTitle> ``

> Lưu ý > > Các file layout khác cũng nên nhận component PageTitle với tiêu đề website mặc định.

Để biết thêm thông tin, xem Control head content in ASP.NET Core Blazor apps.

  1. Xóa các dòng sau khỏi .Client/Program.cs:

```diff

```

  1. Cập nhật .Server/Program.cs:

Thêm Razor component và interactive WebAssembly component services vào dự án. Gọi AddRazorComponents với lời gọi chained (liên kết) đến AddInteractiveWebAssemblyComponents. Gọi AddRazorComponents sẽ thêm antiforgery services (AddAntiforgery) theo mặc định.

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

Thêm Antiforgery Middleware vào pipeline xử lý request (yêu cầu).

Đặt dòng sau sau lời gọi đến app.UseHttpsRedirection. Lời gọi app.UseAntiforgery phải được đặt sau các lời gọi (nếu có) đến app.UseAuthenticationapp.UseAuthorization. Không cần phải thêm antiforgery services (builder.Services.AddAntiforgery) một cách tường minh, vì chúng đã được thêm tự động bởi AddRazorComponents như đã đề cập ở trên.

``csharp app.UseAntiforgery(); ``

Xóa dòng sau:

```diff

```

Xóa dòng sau:

```diff

```

Thay thế dòng trước bằng lời gọi đến MapRazorComponents, cung cấp component App làm kiểu component gốc, và thêm các lời gọi chained (liên kết) đến AddInteractiveWebAssemblyRenderModeAddAdditionalAssemblies:

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

Trong ví dụ trên, placeholder {CLIENT APP NAMESPACE} là namespace của dự án .Client (ví dụ: HostedBlazorApp.Client).

  1. Chạy solution từ dự án .Server:

Đối với Visual Studio, hãy xác nhận rằng dự án .Server được chọn trong Solution Explorer khi chạy ứng dụng.

Nếu sử dụng .NET CLI, hãy chạy dự án từ thư mục của dự án .Server.

Cập nhật cấu hình service và endpoint option

Với sự ra đời của Blazor Web Apps trong .NET 8, cấu hình service và endpoint option của Blazor được cập nhật với sự giới thiệu các API mới cho interactive component services và cấu hình component endpoint.

Hướng dẫn cấu hình được cập nhật xuất hiện ở các vị trí sau:

Loại bỏ workaround định tuyến Blazor Server với Yarp

Nếu trước đây bạn đã làm theo hướng dẫn trong Enable ASP.NET Core Blazor Server support with Yarp in incremental migration để di chuyển ứng dụng Blazor Server với Yarp lên .NET 6 hoặc .NET 7, bạn có thể đảo ngược các bước workaround mà bạn đã thực hiện khi làm theo hướng dẫn đó. Định tuyến và deep linking cho Blazor Server với Yarp hoạt động chính xác trong .NET 8.

Migration (di chuyển) các component CascadingValue trong layout component

Cascading parameters (tham số cascading) không truyền dữ liệu qua các ranh giới render mode, và các layout được render tĩnh trong các ứng dụng có render mode tương tác. Do đó, các ứng dụng muốn sử dụng cascading parameters trong các component được render tương tác sẽ không thể cascade các giá trị từ một layout.

Hai cách tiếp cận để migration (di chuyển) là:

Để biết thêm thông tin, xem Cascading values/parameters and render mode boundaries.

Migration (di chuyển) thuộc tính MSBuild BlazorEnableCompression

Đối với các ứng dụng Blazor WebAssembly tắt compression (nén) và nhắm đến .NET 7 hoặc phiên bản cũ hơn nhưng được build với .NET 8 SDK, thuộc tính MSBuild BlazorEnableCompression đã được đổi thành CompressionEnabled:

diff
<PropertyGroup>
-   <BlazorEnableCompression>false</BlazorEnableCompression>
+   <CompressionEnabled>false</CompressionEnabled>
</PropertyGroup>

Khi sử dụng lệnh publish của .NET CLI, hãy sử dụng thuộc tính mới:

dotnetcli
dotnet publish -p:CompressionEnabled=false

Để biết thêm thông tin, xem các tài nguyên sau:

Migration (di chuyển) component <CascadingAuthenticationState> sang cascading authentication state services

Trong .NET 7 hoặc phiên bản cũ hơn, component CascadingAuthenticationState được bao bọc xung quanh một phần UI tree, ví dụ như xung quanh Blazor router, để cung cấp cascading authentication state:

razor
<CascadingAuthenticationState>
    <Router ...>
        ...
    </Router>
</CascadingAuthenticationState>

Trong .NET 8, không sử dụng component CascadingAuthenticationState:

diff
- <CascadingAuthenticationState>
      <Router ...>
          ...
      </Router>
- </CascadingAuthenticationState>

Thay vào đó, hãy thêm cascading authentication state services vào service collection bằng cách gọi AddCascadingAuthenticationState trong file Program:

csharp
builder.Services.AddCascadingAuthenticationState();

Để biết thêm thông tin, xem các tài nguyên sau:

Bài viết mới về các vấn đề HTTP caching

Chúng tôi đã thêm một bài viết mới thảo luận về một số vấn đề HTTP caching (bộ nhớ đệm HTTP) phổ biến có thể xảy ra khi nâng cấp ứng dụng Blazor qua các phiên bản chính và cách giải quyết các vấn đề HTTP caching.

Để biết thêm thông tin, xem Avoid HTTP caching issues when upgrading ASP.NET Core Blazor apps.

Bài viết mới về class libraries với static server-side rendering (static SSR)

Chúng tôi đã thêm một bài viết mới thảo luận về việc tạo component library trong Razor class libraries (RCLs) với static server-side rendering (static SSR).

Để biết thêm thông tin, xem ASP.NET Core Razor class libraries (RCLs) with static server-side rendering (static SSR).

Khám phá các component từ các assembly bổ sung

Khi di chuyển từ ứng dụng Blazor Server sang Blazor Web App, hãy truy cập hướng dẫn trong ASP.NET Core Blazor routing nếu ứng dụng sử dụng các component có khả năng định tuyến từ các assembly bổ sung, chẳng hạn như component class libraries.

Loại bỏ attribute [Parameter] khi tham số được cung cấp từ query string

Attribute [Parameter] không còn cần thiết khi cung cấp tham số từ query string:

diff
- [Parameter]
  [SupplyParameterFromQuery]

Chính sách ủy quyền fallback cho Blazor Server script

Trong .NET 7, Blazor Server script (blazor.server.js) được phục vụ bởi Static File Middleware. Đặt lời gọi cho Static File Middleware (UseStaticFiles) trong pipeline xử lý request trước lời gọi đến Authorization Middleware (UseAuthorization) là đủ trong các ứng dụng .NET 7 để phục vụ Blazor script cho người dùng ẩn danh.

Trong .NET 8, Blazor Server script được phục vụ bởi endpoint riêng của nó, sử dụng endpoint routing. Thay đổi này được giới thiệu bởi Fixed bug - Passing options to UseStaticFiles breaks Blazor Server (dotnet/aspnetcore #45897).

Hãy xem xét một kịch bản multi-tenant (đa thuê bao) trong đó:

Các request cho file Blazor script (blazor.server.js) được phục vụ tại /_framework/blazor.server.js, được mã hóa cứng trong framework. Các request cho file không được xác thực bởi authentication scheme bổ sung cho các tenant nhưng vẫn bị challenge bởi fallback policy, dẫn đến trả về kết quả unauthorized (không được phép).

Vấn đề này đang được đánh giá cho một tính năng framework mới trong MapRazorComponents broken with FallbackPolicy RequireAuthenticatedUser (dotnet/aspnetcore 51836), hiện được lên kế hoạch cho .NET 9 phát hành vào tháng 11 năm 2024. Cho đến lúc đó, bạn có thể giải quyết vấn đề này bằng một trong ba cách sau:

``csharp app.MapBlazorHub().Add(endpointBuilder => { if (endpointBuilder is RouteEndpointBuilder { RoutePattern: { RawText: "/_framework/blazor.server.js" } }) { endpointBuilder.Metadata.Add(new AllowAnonymousAttribute()); } }); ``

Docker

Cập nhật Docker images (hình ảnh Docker)

Đối với các ứng dụng sử dụng Docker, hãy cập nhật các câu lệnh FROM và scripts trong Dockerfile. Sử dụng base image (hình ảnh cơ sở) bao gồm runtime .NET 8. Hãy xem xét sự khác biệt lệnh docker pull giữa ASP.NET Core trong .NET 7 và .NET 8:

diff
- docker pull mcr.microsoft.com/dotnet/aspnet:7.0
+ docker pull mcr.microsoft.com/dotnet/aspnet:8.0

Cập nhật port (cổng) Docker

Port ASP.NET Core mặc định được cấu hình trong .NET container images đã được cập nhật từ port 80 lên 8080.

Biến môi trường mới ASPNETCORE_HTTP_PORTS đã được thêm như một lựa chọn thay thế đơn giản hơn cho ASPNETCORE_URLS.

Để biết thêm thông tin, xem:

Breaking changes (Thay đổi không tương thích)

Sử dụng các bài viết trong Breaking changes in .NET để tìm các breaking changes (thay đổi không tương thích) có thể áp dụng khi nâng cấp ứng dụng lên phiên bản .NET mới hơn.