Nguon: Microsoft Learn · .NET 8.0

Những điểm mới trong ASP.NET Core trong .NET 11

Nguồn: What's new in ASP.NET Core in .NET 11

Bài viết này nêu bật những thay đổi quan trọng nhất trong ASP.NET Core trong .NET 11 kèm theo các liên kết đến tài liệu liên quan.

Bài viết sẽ được cập nhật khi có các phiên bản preview (xem trước) mới.

Blazor

Phần này mô tả các tính năng mới cho Blazor.

Component (thành phần) DisplayName mới và hỗ trợ cho các thuộc tính [Display][DisplayName]

Component DisplayName có thể được dùng để hiển thị tên thuộc tính từ các metadata attribute (thuộc tính siêu dữ liệu):

csharp
[Required, DisplayName("Production Date")]
public DateTime ProductionDate { get; set; }

Thuộc tính [Display] trên thuộc tính lớp model (mô hình) được hỗ trợ:

csharp
[Required, Display(Name = "Production Date")]
public DateTime ProductionDate { get; set; }

Trong hai cách trên, nên dùng thuộc tính [Display] vì nó cung cấp thêm nhiều thuộc tính bổ sung. Thuộc tính [Display] còn cho phép gán resource type (kiểu tài nguyên) để hỗ trợ localization (bản địa hóa). Khi cả hai thuộc tính đều có mặt, [Display] ưu tiên hơn [DisplayName]. Nếu không có thuộc tính nào, component sẽ dùng tên thuộc tính.

Dùng component DisplayName trong label (nhãn) hoặc table header (tiêu đề bảng):

razor
<label>
    <DisplayName For="@(() => Model!.ProductionDate)" />
    <InputDate @bind-Value="Model!.ProductionDate" />
</label>

Định dạng tùy chọn khởi động script của Blazor Web App hiện được hỗ trợ cho Blazor Server và Blazor WebAssembly scripts

Script của Blazor Web App (blazor.web.js) với đối tượng tùy chọn truyền vào Blazor.start() sử dụng định dạng sau kể từ khi phát hành .NET 8:

javascript
Blazor.start({
  ssr: { ... },
  circuit: { ... },
  webAssembly: { ... },
});

Bây giờ, Blazor Server (blazor.server.js) và Blazor WebAssembly (blazor.webassembly.js) scripts có thể sử dụng cùng định dạng tùy chọn này.

Ví dụ dưới đây cho thấy định dạng tùy chọn trước đây, vẫn được hỗ trợ:

javascript
Blazor.start({
  loadBootResource: function (...) {
      ...
    },
  });

Định dạng tùy chọn mới được hỗ trợ cho ví dụ trên:

javascript
Blazor.start({
  webAssembly: {
    loadBootResource: function (...) {
      ...
    },
  },
});

Component BasePath mới

Blazor Web Apps có thể dùng component BasePath mới (<BasePath />) để tự động render (kết xuất) thẻ HTML app base path (<base href>) của ứng dụng.

Loại bỏ inline JS event handler (trình xử lý sự kiện JS nội tuyến) khỏi component NavMenu

Inline JS event handler dùng để bật/tắt hiển thị các navigation link (liên kết điều hướng) không còn hiện diện trong component NavMenu của Blazor Web App project template (mẫu dự án). Các ứng dụng được tạo từ project template giờ đây sử dụng cách tiếp cận collocated JS module (module JS đặt cùng vị trí) để hiển thị hoặc ẩn navigation bar (thanh điều hướng). Cách tiếp cận mới cải thiện Content Security Policy (CSP) (Chính sách bảo mật nội dung) vì không cần CSP phải bao gồm unsafe hash (mã băm không an toàn) cho inline JS.

Tham số mới RelativeToCurrentUri (mặc định: false) cho NavigationManager.NavigateTo và component NavLink cho phép điều hướng đến URI tương đối so với đường dẫn trang hiện tại thay vì base URI của ứng dụng.

Xét các endpoint (điểm cuối) lồng nhau sau:

Khi URI của trình duyệt là /docs/getting-started/installation và bạn muốn điều hướng người dùng đến /docs/getting-started/configuration, NavigateTo("/configuration") sẽ chuyển hướng đến /configuration ở gốc ứng dụng thay vì đường dẫn tương đối /docs/getting-started/configuration. Đặt RelativeToCurrentUri với NavigateTo hoặc component NavLink để điều hướng mong muốn:

csharp
Navigation.NavigateTo("/configuration", new NavigationOptions
{
    RelativeToCurrentUri = true
});
razor
<NavLink href="configuration" RelativeToCurrentUri="true">Configuration</NavLink>

Persist (lưu trữ) dữ liệu tạm thời giữa các HTTP request trong static server-side rendering (SSR tĩnh phía server)

Để lưu trữ dữ liệu tạm thời giữa các HTTP request trong static SSR (kết xuất phía server tĩnh), Blazor hỗ trợ TempData. TempData lý tưởng cho các tình huống như flash message (thông báo nháy) sau khi submit form, truyền dữ liệu trong quá trình redirect (chuyển hướng) theo pattern POST-Redirect-GET, và thông báo một lần.

TempData khả dụng khi AddRazorComponents được gọi trong file Program của ứng dụng và được cung cấp như cascading value (giá trị xếp tầng) với thuộc tính [CascadingParameter]:

csharp
[CascadingParameter]
public ITempData? TempData { get; set; }

Khi cung cấp cho tham số để đọc/ghi đơn giản một giá trị, dùng thuộc tính [SupplyParameterFromTempData]:

csharp
[SupplyParameterFromTempData]
public string? Message { get; set; }

Blazor Web Worker template mới (blazorwebworker)

.NET Web Worker project template, chứa Web Worker client (máy khách Web Worker) để chuyển công việc chạy lâu sang background thread (luồng nền), đã được đổi tên thành Blazor Web Worker project template (blazorwebworker). Việc đổi tên làm rõ template thuộc Blazor stack dùng trong Blazor WebAssembly và Blazor Web apps.

Hai khả năng thường được yêu cầu đã được thêm vào WebWorkerClient được tạo:

Cải tiến Virtualization (ảo hóa)

Các cập nhật sử dụng phương pháp hybrid: native CSS scroll anchoring trên các trình duyệt hỗ trợ nó cho các layout (bố cục) không phải <table>, với fallback (dự phòng) dựa trên ResizeObserver thủ công cho <table> layout và Safari.

Các ứng dụng dùng component Virtualize nhận được lợi ích từ các cập nhật này tự động. Không cần thay đổi developer API.

Giá trị mặc định của Virtualize<TItem>.OverscanCount thay đổi từ 3 (trong .NET 10 hoặc cũ hơn) sang 15 (trong .NET 11 hoặc mới hơn).

``razor <Virtualize AnchorMode="Beginning" ...> ... </Virtualize> ``

Service defaults library project template mới cho Blazor WebAssembly apps

Template blazor-wasm-servicedefaults tạo service defaults library (thư viện mặc định dịch vụ) cho Blazor WebAssembly apps với tích hợp Aspire.

Development server mới cho Blazor WebAssembly apps

Microsoft.AspNetCore.Components.Gateway là ASP.NET Core host (máy chủ) nhẹ thay thế Microsoft.AspNetCore.Components.WebAssembly.DevServer để phục vụ standalone Blazor WebAssembly applications (ứng dụng Blazor WebAssembly độc lập).

Server-triggered circuit pause (tạm dừng circuit do server kích hoạt)

Tính năng này áp dụng cho ứng dụng Blazor phía server.

.NET 11 giới thiệu khả năng tạm dừng và tiếp tục circuit (vòng kết nối) đối xứng phía server, nơi server có thể yêu cầu các client (máy khách) kết nối bắt đầu luồng tạm dừng circuit duyên dáng.

Circuit.RequestCircuitPauseAsync(CancellationToken) được dùng để yêu cầu client kết nối bắt đầu luồng tạm dừng circuit duyên dáng. CancellationToken hủy yêu cầu trước khi được framework chấp nhận. Phương thức trả về true nếu yêu cầu được chấp nhận.

Tính năng này hữu ích trong các tình huống:

Blazor WebAssembly publish output nhỏ hơn

Hai thay đổi trimming (cắt tỉa) làm giảm kích thước Blazor WebAssembly apps đã publish không dùng OpenTelemetry (OTEL) hoặc Hot Reload:

Blazor Hybrid

Phần này mô tả các tính năng mới cho Blazor Hybrid.

Ghi chú phát hành xuất hiện trong phần này khi các tính năng preview trở nên khả dụng.

SignalR

Phần này mô tả các tính năng mới cho SignalR.

Minimal APIs

Endpoint filter (bộ lọc điểm cuối) quan sát các lỗi parameter-binding

Khi một minimal API endpoint có bất kỳ filter hoặc filter factory nào được cấu hình, filter pipeline (đường ống bộ lọc) giờ đây chạy ngay cả khi parameter binding (liên kết tham số) thất bại. Filter có thể đọc HttpContext.Response.StatusCode == 400 và thay thế response body (nội dung phản hồi) của chúng.

OpenAPI

Mô tả binary file responses (phản hồi file nhị phân)

ASP.NET Core 11 giới thiệu hỗ trợ tạo mô tả OpenAPI cho các operation (hoạt động) trả về binary file responses. Ánh xạ kiểu kết quả FileContentResult thành OpenAPI schema (lược đồ) với type: stringformat: binary.

csharp
app.MapPost("/filecontentresult", () =>
{
    var content = "This endpoint returns a FileContentResult!"u8.ToArray();
    return TypedResults.File(content);
})
.Produces<FileContentResult>(contentType: MediaTypeNames.Application.Octet);

Tài liệu OpenAPI được tạo mô tả phản hồi endpoint như sau:

yaml
responses:
  '200':
    description: OK
    content:
      application/octet-stream:
        schema:
          $ref: '#/components/schemas/FileContentResult'

FileContentResult được định nghĩa trong components/schemas:

yaml
components:
  schemas:
    FileContentResult:
      type: string
      format: binary

Hỗ trợ OpenAPI 3.2.0 (Breaking Change - Thay đổi đột phá)

Microsoft.AspNetCore.OpenApi hiện hỗ trợ OpenAPI 3.2.0 thông qua dependency (phụ thuộc) được cập nhật trên Microsoft.OpenApi 3.3.1.

Để tạo tài liệu OpenAPI 3.2.0, chỉ định phiên bản khi gọi AddOpenApi:

csharp
builder.Services.AddOpenApi(options =>
{
    options.OpenApiVersion = Microsoft.OpenApi.OpenApiSpecVersion.OpenApi3_2;
});

HTTP QUERY trong tài liệu OpenAPI được tạo

Việc tạo tài liệu OpenAPI giờ đây nhận dạng HTTP QUERY như một kiểu operation đã biết. QUERY là phương thức an toàn, idempotent (mang tính bất biến) được đề xuất cho phép client gửi request body khi mô tả tìm kiếm.

csharp
using Microsoft.OpenApi;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddOpenApi(options =>
{
    options.OpenApiVersion = OpenApiSpecVersion.OpenApi3_2;
});

var app = builder.Build();

app.MapOpenApi();

app.MapMethods("/search", ["QUERY"], (SearchRequest request) =>
    SearchService.Run(request));

app.Run();

Authentication and authorization (Xác thực và ủy quyền)

Hỗ trợ TimeProvider trong ASP.NET Core Identity

ASP.NET Core Identity giờ đây sử dụng TimeProvider thay vì DateTimeDateTimeOffset cho tất cả các hoạt động liên quan đến thời gian. Thay đổi này làm cho các thành phần Identity dễ kiểm tra hơn.

csharp
// Trong tests (kiểm thử)
var fakeTimeProvider = new FakeTimeProvider(
    new DateTimeOffset(2024, 1, 1, 0, 0, 0, TimeSpan.Zero));

services.AddSingleton<TimeProvider>(fakeTimeProvider);
services.AddIdentity<IdentityUser, IdentityRole>();

Suy luận tên hiển thị passkey từ authenticator (bộ xác thực)

ASP.NET Core Identity giờ đây tự động suy luận tên hiển thị thân thiện cho passkey dựa trên AAGUID (Authenticator Attestation GUID) của chúng. Các ánh xạ tích hợp sẵn cho các passkey authenticator phổ biến nhất bao gồm Google Password Manager, iCloud Keychain, Windows Hello, 1Password và Bitwarden.

Miscellaneous (Các tính năng khác)

Interface IOutputCachePolicyProvider

ASP.NET Core trong .NET 11 cung cấp interface IOutputCachePolicyProvider để triển khai logic chọn output caching policy (chính sách bộ nhớ đệm đầu ra) tùy chỉnh.

csharp
public interface IOutputCachePolicyProvider
{
    IReadOnlyList<IOutputCachePolicy> GetBasePolicies();
    ValueTask<IOutputCachePolicy?> GetPolicyAsync(string policyName);
}

Tự động tin cậy development certificates (chứng chỉ phát triển) trong WSL

Việc thiết lập development certificate (chứng chỉ phát triển) giờ đây tự động tin cậy chứng chỉ trong môi trường WSL (Windows Subsystem for Linux). Khi chạy dotnet dev-certs https --trust trong WSL, chứng chỉ tự động được cài đặt và tin cậy trong cả môi trường WSL lẫn Windows.

bash
# Tự động tin cậy chứng chỉ trong cả WSL và Windows
dotnet dev-certs https --trust

Native OpenTelemetry tracing (theo dõi) cho ASP.NET Core

ASP.NET Core giờ đây tự nhiên thêm các thuộc tính OpenTelemetry semantic convention (quy ước ngữ nghĩa) vào HTTP server activity (hoạt động máy chủ HTTP).

csharp
builder.Services.AddOpenTelemetry()
    .WithTracing(tracing => tracing
        .AddSource("Microsoft.AspNetCore")
        .AddConsoleExporter());

Không cần thư viện instrumentation (đo đạc) bổ sung nào. Framework giờ đây trực tiếp điền các thuộc tính semantic convention vào request activity (hoạt động yêu cầu), như http.request.method, url.path, http.response.status_code, và server.address.

Cải tiến hiệu suất

HTTP/1.1 request parser của Kestrel giờ đây sử dụng code path (đường dẫn mã) không ném ngoại lệ để xử lý các yêu cầu không đúng định dạng. Trong các tình huống với nhiều yêu cầu không đúng định dạng, điều này cải thiện throughput (thông lượng) lên đến 20-40%.

Nén response và giải nén request bằng Zstandard

ASP.NET Core giờ đây hỗ trợ Zstandard (zstd) cho cả nén response và giải nén request.

csharp
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddResponseCompression();
builder.Services.AddRequestDecompression();
builder.Services.Configure<ZstandardCompressionProviderOptions>(options =>
{
    options.CompressionOptions = new ZstandardCompressionOptions
    {
        Quality = 6 // 1-22, cao hơn = nén tốt hơn, chậm hơn
    };
});

HTTP/3 bắt đầu xử lý request sớm hơn

Kestrel giờ đây bắt đầu xử lý HTTP/3 requests mà không cần đợi control stream và SETTINGS frame trước, giảm độ trễ cho request đầu tiên.

MCP Server template đi kèm với .NET SDK

Project template mcpserver giờ đây được đưa vào như một bundled template (mẫu đi kèm) trong .NET SDK:

dotnetcli
dotnet new mcpserver -o MyMcpServer

TLS handshake observability (khả năng quan sát) trong Kestrel

ITlsHandshakeFeature giờ đây có thuộc tính Exception chứa ngoại lệ ném ra trong quá trình TLS handshake thất bại.

csharp
var builder = WebApplication.CreateBuilder(args);

builder.WebHost.ConfigureKestrel(options =>
{
    options.ListenAnyIP(5001, listenOptions =>
    {
        listenOptions.Use(next => async context =>
        {
            await next(context);

            var tlsHandshakeFeature = context.Features.Get<ITlsHandshakeFeature>();
            if (tlsHandshakeFeature?.Exception is { } ex)
            {
                Console.WriteLine($"[TLS Handshake Failed] ConnectionId={context.ConnectionId}, Exception={ex.GetType().Name}: {ex.Message}");
            }
        });

        listenOptions.UseTlsClientHelloListener((connection, clientHelloBytes) =>
        {
            Console.WriteLine($"TLS Client Hello received on {connection.ConnectionId}, {clientHelloBytes.Length} bytes");
        });
        listenOptions.UseHttps();
    });
});

Response compression luôn phát ra Vary: Accept-Encoding

Response-compression middleware (phần mềm trung gian nén phản hồi) giờ đây thêm Vary: Accept-Encoding vào mọi response khi compression (nén) được bật, ngay cả khi response không được nén.

Rate-limiting middleware trả về Retry-After headers chính xác

FixedWindowRateLimiter giờ đây báo cáo giá trị metadata RetryAfter phản ánh chính xác ranh giới cửa sổ tiếp theo.

Breaking changes (Thay đổi đột phá)

Dùng các bài viết trong Breaking changes in .NET để tìm các breaking change có thể áp dụng khi nâng cấp ứng dụng lên phiên bản .NET mới hơn.