ASP.NET Core 6.0 的新功能

本文會重點介紹 ASP.NET Core 6.0 中最重要的變更,並隨附相關文件的連結。

ASP.NET Core MVC 和 Razor 改進事項

最小 API

基本 API 的架構是用於建立具有最低相依性的 HTTP API。 它們很適合只要包含 ASP.NET Core 中基本檔案、功能和相依性的微服務及應用程式。 如需詳細資訊,請參閱

SignalR

SignalR 連線的長時間執行活動標籤

SignalR 會使用新的 Microsoft.AspNetCore.Http.Features.IHttpActivityFeature.Activity,將 http.long_running 標籤新增至要求活動。 Azure Monitor Application InsightsAPM 服務會使用 IHttpActivityFeature.Activity 篩選建立長時間執行要求警示的 SignalR 要求。

SignalR 效能改善

  • 為每個連線配置一次 HubCallerClients,而不是針對每個中樞方法呼叫。
  • 避免在 SignalRDefaultHubDispatcher.Invoke 中結束配置。 狀態會透過參數傳遞至本機靜態函式,避免關閉配置。 如需詳細資訊,請參閱這個 GitHub 提取要求
  • 在伺服器對用戶端串流中,為每次串流 (而不是每個串流專案) 配置單一 StreamItemMessage。 如需詳細資訊,請參閱這個 GitHub 提取要求

Razor 編譯器

Razor 編譯器已更新為使用來源產生器

Razor 編譯器現在以 C# 來源產生器為基礎。 來源產生器會在編譯期間執行,並檢查正在編譯的內容,以產生與專案其餘部分一同編譯的其他檔案。 使用來源產生器可簡化 Razor 編譯器,並大幅加快建置時間。

Razor 編譯器不再產生個別檢視組件

Razor 編譯器先前已使用雙步驟編譯處理序產生個別的檢視組件,其中包含應用程式中定義的已產生檢視和頁面 (.cshtml 檔案)。 產生的型別是公用的且在 AspNetCore 命名空間下。

更新的 Razor 編譯器會將檢視表和頁面型別建置到主要專案組件中。 依預設,這些型別現在會以 AspNetCoreGeneratedDocument 命名空間中的內部密封形式產生。 這項變更可改善建置效能、啟用單一檔案部署,並讓這些型別參與熱重新載入

如需這項變更的詳細資訊,請參閱 GitHub 上的相關公告問題

ASP.NET Core 效能和 API 改進事項

進行許多變更,以減少配置並改善堆疊整體效能:

降低閒置 TLS 連線的記憶體使用量

對於長時間執行且偶爾來回傳送資料的 TLS 連線,我們已大幅降低 .NET 6 中 ASP.NET Core 應用程式的記憶體使用量。 這應該有助於改善 WebSocket 伺服器等案例的可擴縮性。 此情況可能是 System.IO.PipelinesSslStream 和 Kestrel 的諸多改進事項所致。 下列各節詳述有助於降低記憶體使用量的部分改進事項:

減少 System.IO.Pipelines.Pipe 的大小

針對每個已建立的連線,會在 Kestrel 中配置兩個管道:

  • 針對要求的應用程式傳輸層。
  • 針對回應的傳輸應用程式層。

藉由將 System.IO.Pipelines.Pipe 的大小從 368 個位元組縮小到 264 個位元組 (約減少 28.2%),每個連線會儲存 208 個位元組 (每個管道 104 個位元組)。

共用 SocketSender

SocketSender 物件 (子類別為 SocketAsyncEventArgs) 在執行階段大約是 350 個位元組。 不是為每個連線配置新的 SocketSender 物件,而是共用該物件。 SocketSender 物件可以共用,因為傳送速度通常很快。 共用可減少每個連線的額外負荷。 不是為每個連線配置 350 個位元組,而是只為每個 IOQueue 配置 350 個位元組。 會為每個佇列進行配置以避免爭用。 我們的 WebSocket 伺服器具有 5000 個閒置連線,配置的 SocketSender 物件則從約 1.75 MB (350 個位元組 * 5000) 到約 2.8 kb (350 個位元組 * 8)。

使用 SslStream 讀取零個位元組

無緩衝讀取是 ASP.NET Core 中使用的技術,可在通訊端上沒有可用的資料時,避免從記憶體集區租用記憶體。 在此變更之前,我們具有 5000 個閒置連線的 WebSocket 伺服器在沒有 TLS 的情況下需要約 200 MB (具有 TLS 時約 800 MB)。 其中有些配置 (每個連線 4k) 來自 Kestrel,在等待 SslStream 上的讀取完成時必須保留至 ArrayPool<T> 緩衝區。 假設這些連線為閒置狀態,則不會完成任何讀取並將其緩衝區傳回至 ArrayPool,從而強制 ArrayPool 配置更多記憶體。 剩餘的配置是在 SslStream 本身:4k 緩衝區用於 TLS 交握,32k 緩衝區用於正常讀取。 在 .NET 6 中,當使用者在 SslStream 執行零位元組讀取且沒有可用資料時,SslStream 會在內部對基礎包裝串流執行零位元組讀取。 在最佳情況下 (閒置連線),這些變更會導致每個連線節省 40 Kb,同時仍允許取用者 (Kestrel) 在資料可用時收到通知,而無須保存任何未使用的緩衝區。

使用 PipeReader 讀取零位元組

由於 SslStream 支援無緩衝讀取,因此新增選項來對 StreamPipeReader (將 Stream 調整為 PipeReader 的內部類型) 執行零位元組讀取。 在 Kestrel 中會使用 StreamPipeReader,將基礎 SslStream 調整為 PipeReader。 因此,必須在 PipeReader 上公開這些零位元組讀取語意。

現在可以使用下列 API 建立 PipeReader,以支援對任何支援零位元組讀取語意的基礎 Stream (例如 SslStreamNetworkStream 等) 進行零位元組讀取:

var reader = PipeReader.Create(stream, new StreamPipeReaderOptions(useZeroByteReads: true));

SlabMemoryPool 移除 Slab

為了減少堆積的片段,Kestrel 採用一種技術,將 128 KB 的記憶體 Slab 配置為記憶體集區的一部分。 然後,這些 Slab 會進一步分為供 Kestrel 內部使用的 4 KB 區塊。 Slab 必須大於 85 KB 才能強制配置大型物件堆積,以嘗試防止 GC 重新放置此陣列。 不過,隨著釘選的物件堆積 (POH) 這個新 GC 世代推出,在 Slab 上配置區塊不再有意義。 Kestrel 現在會直接在 POH 上配置區塊,以減少管理記憶體集區的相關複雜度。 這項變更應該有利於未來改善,例如更輕鬆地壓縮 Kestrel 使用的記憶體集區。

支援 IAsyncDisposable

IAsyncDisposable 現在適用於控制器、Razor Pages 和檢視元件。 非同步版本已新增至處理站和啟動項中的相關介面:

  • 新方法會提供預設介面實作,以委派給同步版本並呼叫 Dispose
  • 這些實作會覆寫預設實作,並處理處置中的 IAsyncDisposable 實作。
  • 當兩個介面都實作時,IAsyncDisposable 的實作優先等級高於 IDisposable
  • 擴充項必須覆寫包含的新方法以支援 IAsyncDisposable 執行個體。

IAsyncDisposable 在處理下列項目時很有用:

  • 非同步列舉程式 (例如在非同步串流中)。
  • 需釋放資源密集型 I/O 作業的非受控資源。

實作這個介面時,請使用 DisposeAsync 方法釋放資源。

請考慮建立和使用 Utf8JsonWriter 的控制器。 Utf8JsonWriterIAsyncDisposable 資源:

public class HomeController : Controller, IAsyncDisposable
{
    private Utf8JsonWriter? _jsonWriter;
    private readonly ILogger<HomeController> _logger;

    public HomeController(ILogger<HomeController> logger)
    {
        _logger = logger;
        _jsonWriter = new Utf8JsonWriter(new MemoryStream());
    }

IAsyncDisposable 必須實作 DisposeAsync

public async ValueTask DisposeAsync()
{
    if (_jsonWriter is not null)
    {
        await _jsonWriter.DisposeAsync();
    }

    _jsonWriter = null;
}

SignalR C++ 用戶端的 Vcpkg 連接埠

Vcpkg 是適用於 C 和 C++ 程式庫的跨平台命令列套件管理員。 我們最近已將連接埠新增至 vcpkg,為 SignalR C++ 用戶端新增 CMake 原生支援。 vcpkg 也適用於 MSBuild。

當 vcpkg 包含在工具鏈檔案中時,可以使用下列程式碼片段將 SignalR 用戶端新增至 CMake 專案:

find_package(microsoft-signalr CONFIG REQUIRED)
link_libraries(microsoft-signalr::microsoft-signalr)

透過上述程式碼片段,SignalR C++ 用戶端已準備好使用 #include,且不需任何其他組態即可在專案中供取用。 如需使用 SignalR C++ 用戶端的 C++ 應用程式完整範例,請參閱 halter73/SignalR-Client-Cpp-Sample 存放庫。

Blazor

專案範本變更

Blazor 應用程式進行了多項專案範本變更,包括使用 Pages/_Layout.cshtml 檔案來取得先前 Blazor Server 應用程式的 _Host.cshtml 檔案中所顯示的配置內容。 您可以從 6.0 專案範本建立應用程式,或存取專案範本的 ASP.NET Core 參考來源,以深入了解變更內容:

Blazor WebAssembly 原生相依性支援

Blazor WebAssembly 應用程式可使用專為在 WebAssembly 執行而建置的原生相依性。 如需詳細資訊,請參閱 ASP.NET Core Blazor WebAssembly 原生相依性

WebAssembly 預先 (AOT) 編譯和執行階段重新連結

Blazor WebAssembly 支援預先 (AOT) 編譯,您可以在其中直接將 .NET 程式碼編譯成 WebAssembly。 AOT 編譯會導致執行階段的效能提升,但代價是應用程式會比較大。 重新連結 .NET WebAssembly 執行階段會修剪未使用的執行階段程式碼,進而改善下載速度。 如需詳細資訊,請參閱預先 (AOT) 編譯執行階段重新連結

保存預先轉譯的狀態

Blazor 支援保存預先轉譯頁面中的狀態,因此完全載入應用程式時不需重新建立狀態。 如需詳細資訊,請參閱預先轉譯和整合 ASP.NET Core Razor 元件

錯誤界限

錯誤界限提供處理 UI 層級例外狀況的便利方法。 如需詳細資訊,請參閱處理 ASP.NET Core Blazor 應用程式中的錯誤

SVG 支援

支援 <foreignObject> 元素在 SVG 中顯示任意 HTML。 如需詳細資訊,請參閱 ASP.NET Core Razor 元件

Blazor Server 支援 JS Interop 中的位元組陣列傳輸

Blazor 支援最佳化的位元組陣列 JS Interop,可避免將位元組陣列編碼和解碼為 Base64。 如需詳細資訊,請參閱以下資源:

查詢字串增強功能

改善對查詢字串使用方式的支援。 如需詳細資訊,請參閱 ASP.NET Core Blazor 路由和瀏覽

繫結以選取多個選項

繫結支援使用 <input> 元素選取多個選項。 如需詳細資訊,請參閱以下資源:

標頭 (<head>) 內容控制項

Razor 元件可以修改頁面的 HTML <head> 元素內容,包括設定頁面的標題 (<title> 元素) 和修改中繼資料 (<meta> 元素)。 如需詳細資訊,請參閱在 ASP.NET Core Blazor 應用程式中控制 <head> 內容

產生 Angular 和 React 元件

針對 Web 架構 (例如 Angular 或 React) 從 Razor 元件產生架構特定的 JavaScript 元件。 如需詳細資訊,請參閱 ASP.NET Core Razor 元件

從 JavaScript 轉譯 元件

從現有 JavaScript 應用程式的 JavaScript 動態轉譯 Razor 元件。 如需詳細資訊,請參閱 ASP.NET Core Razor 元件

自訂元素

實驗性支援可用於建置使用標準 HTML 介面的自訂元素。 如需詳細資訊,請參閱 ASP.NET Core Razor 元件

從上階元件推斷元件泛型型別

上階元件可以使用 [CascadingTypeParameter] 屬性,依名稱將型別參數串聯至子系。 如需詳細資訊,請參閱 ASP.NET Core Razor 元件

動態轉譯的元件

使用新的內建 DynamicComponent 元件,依型別轉譯元件。 如需詳細資訊,請參閱動態轉譯 ASP.NET Core Razor 元件

改善的 Blazor 協助工具

使用新的 FocusOnNavigate 元件,從某個頁面導覽到另一個頁面之後,根據 CSS 選取器將 UI 焦點設定為元素。 如需詳細資訊,請參閱 ASP.NET Core Blazor 路由和瀏覽

自訂事件引數支援

Blazor 支援自訂事件引數,可讓您透過自訂事件將任意資料傳遞至 .NET 事件處理常式。 如需詳細資訊,請參閱 ASP.NET Core Blazor 事件處理

必要參數

套用新的 [EditorRequired] 屬性以指定必要的元件參數。 如需詳細資訊,請參閱 ASP.NET Core Razor 元件

將 JavaScript 檔案與頁面、檢視表和元件共置

共置頁面、檢視表和 Razor 元件的 JavaScript 檔案,是組織應用程式中指令碼的便利方式。 如需詳細資訊,請參閱 ASP.NET Core Blazor JavaScript 互通性 (JS Interop)

JavaScript 初始設定式

JavaScript 初始設定式會在 Blazor 應用程式載入前後執行邏輯。 如需詳細資訊,請參閱 ASP.NET Core Blazor JavaScript 互通性 (JS Interop)

串流 JavaScript Interop

Blazor 現在支援直接在 .NET 和 JavaScript 之間串流資料。 如需詳細資訊,請參閱以下資源:

泛型型別條件約束

現在支援泛型型別參數。 如需詳細資訊,請參閱 ASP.NET Core Razor 元件

WebAssembly 部署配置

使用部署配置,在受限制的安全性環境中啟用 Blazor WebAssembly 應用程式下載。 如需詳細資訊,請參閱 ASP.NET Core 裝載式 Blazor WebAssembly 應用程式的部署配置

Blazor 新文章

除了上述各節所述的 Blazor 功能之外,我們也提供下列主題的 Blazor 新文章:

使用 .NET MAUI、WPF 和 Windows Forms 建置 Blazor Hybrid 應用程式

使用 Blazor Hybrid 搭配 .NET 和 Blazor 混合桌面與行動原生用戶端架構:

  • .NET Multi-platform App UI (.NET MAUI) 是使用 C# 和 XAML 建立原生行動和桌面應用程式的跨平台架構。
  • Blazor Hybrid 應用程式可以使用 Windows Presentation Foundation (WPF) 和 Windows Forms 架構來建置。

重要

Blazor Hybrid 處於預覽狀態,在發行最終版本之前不應該用於生產應用程式。

如需詳細資訊,請參閱以下資源:

Kestrel

HTTP/3 目前處於草稿階段,因此可能有所變更。 未發行 ASP.NET Core 中的 HTTP/3 支援,這是 .NET 6 包含的預覽功能。

Kestrel 現在支援 HTTP/3。 如需詳細資訊,請參閱搭配 ASP.NET Core Kestrel Web 伺服器使用 HTTP/3,以及部落格文章 .NET6 中的 HTTP/3 支援

所選記錄的新 Kestrel 記錄類別

在此變更之前,啟用 Kestrel 的詳細資訊記錄成本過高,因為所有 Kestrel 都共用 Microsoft.AspNetCore.Server.Kestrel 記錄類別名稱。 Microsoft.AspNetCore.Server.Kestrel 仍可供使用,但下列新的子類別支援更多記錄控制項:

  • Microsoft.AspNetCore.Server.Kestrel (目前類別):ApplicationErrorConnectionHeadResponseBodyWriteApplicationNeverCompletedRequestBodyStartRequestBodyDoneRequestBodyNotEntirelyReadRequestBodyDrainTimedOutResponseMinimumDataRateNotSatisfiedInvalidResponseHeaderRemovedHeartbeatSlow
  • Microsoft.AspNetCore.Server.Kestrel.BadRequestsConnectionBadRequestRequestProcessingErrorRequestBodyMinimumDataRateNotSatisfied
  • Microsoft.AspNetCore.Server.Kestrel.ConnectionsConnectionAcceptedConnectionStartConnectionStopConnectionPauseConnectionResumeConnectionKeepAliveConnectionRejectedConnectionDisconnectNotAllConnectionsClosedGracefullyNotAllConnectionsAbortedApplicationAbortedConnection
  • Microsoft.AspNetCore.Server.Kestrel.Http2Http2ConnectionErrorHttp2ConnectionClosingHttp2ConnectionClosedHttp2StreamErrorHttp2StreamResetAbortHPackDecodingErrorHPackEncodingErrorHttp2FrameReceivedHttp2FrameSendingHttp2MaxConcurrentStreamsReached
  • Microsoft.AspNetCore.Server.Kestrel.Http3Http3ConnectionErrorHttp3ConnectionClosingHttp3ConnectionClosedHttp3StreamAbortHttp3FrameReceivedHttp3FrameSending

現有規則會繼續運作,但您現在可以更有選擇性地啟用規則。 例如,僅對錯誤要求啟用 Debug 記錄的可檢視性額外負荷大幅減少,並且可以透過下列組態來啟用:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning",
      "Microsoft.AspNetCore.Kestrel.BadRequests": "Debug"
    }
  }

記錄篩選會套用具有最長相符類別前置詞的規則。 如需詳細資訊,請參閱如何套用篩選規則

透過 EventSource 事件發出 KestrelServerOptions

KestrelEventSource 會在啟用詳細資訊 EventLevel.LogAlways 時,發出包含 JSON 序列化 KestrelServerOptions 的新事件。 透過此事件,可以在分析收集的追蹤資料時更輕鬆地推斷伺服器行為。 下列 JSON 是事件承載的範例:

{
  "AllowSynchronousIO": false,
  "AddServerHeader": true,
  "AllowAlternateSchemes": false,
  "AllowResponseHeaderCompression": true,
  "EnableAltSvc": false,
  "IsDevCertLoaded": true,
  "RequestHeaderEncodingSelector": "default",
  "ResponseHeaderEncodingSelector": "default",
  "Limits": {
    "KeepAliveTimeout": "00:02:10",
    "MaxConcurrentConnections": null,
    "MaxConcurrentUpgradedConnections": null,
    "MaxRequestBodySize": 30000000,
    "MaxRequestBufferSize": 1048576,
    "MaxRequestHeaderCount": 100,
    "MaxRequestHeadersTotalSize": 32768,
    "MaxRequestLineSize": 8192,
    "MaxResponseBufferSize": 65536,
    "MinRequestBodyDataRate": "Bytes per second: 240, Grace Period: 00:00:05",
    "MinResponseDataRate": "Bytes per second: 240, Grace Period: 00:00:05",
    "RequestHeadersTimeout": "00:00:30",
    "Http2": {
      "MaxStreamsPerConnection": 100,
      "HeaderTableSize": 4096,
      "MaxFrameSize": 16384,
      "MaxRequestHeaderFieldSize": 16384,
      "InitialConnectionWindowSize": 131072,
      "InitialStreamWindowSize": 98304,
      "KeepAlivePingDelay": "10675199.02:48:05.4775807",
      "KeepAlivePingTimeout": "00:00:20"
    },
    "Http3": {
      "HeaderTableSize": 0,
      "MaxRequestHeaderFieldSize": 16384
    }
  },
  "ListenOptions": [
    {
      "Address": "https://127.0.0.1:7030",
      "IsTls": true,
      "Protocols": "Http1AndHttp2"
    },
    {
      "Address": "https://[::1]:7030",
      "IsTls": true,
      "Protocols": "Http1AndHttp2"
    },
    {
      "Address": "http://127.0.0.1:5030",
      "IsTls": false,
      "Protocols": "Http1AndHttp2"
    },
    {
      "Address": "http://[::1]:5030",
      "IsTls": false,
      "Protocols": "Http1AndHttp2"
    }
  ]
}

拒絕 HTTP 要求的新 DiagnosticSource 事件

Kestrel 現在會針對伺服器層拒絕的 HTTP 要求發出新的 DiagnosticSource 事件。 在這項變更之前,無法觀察這些遭拒絕的要求。 新的 DiagnosticSource 事件 Microsoft.AspNetCore.Server.Kestrel.BadRequest 包含 IBadRequestExceptionFeature,可用來檢討拒絕要求的原因。

using Microsoft.AspNetCore.Http.Features;
using System.Diagnostics;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
var diagnosticSource = app.Services.GetRequiredService<DiagnosticListener>();
using var badRequestListener = new BadRequestEventListener(diagnosticSource,
    (badRequestExceptionFeature) =>
{
    app.Logger.LogError(badRequestExceptionFeature.Error, "Bad request received");
});
app.MapGet("/", () => "Hello world");

app.Run();

class BadRequestEventListener : IObserver<KeyValuePair<string, object>>, IDisposable
{
    private readonly IDisposable _subscription;
    private readonly Action<IBadRequestExceptionFeature> _callback;

    public BadRequestEventListener(DiagnosticListener diagnosticListener,
                                   Action<IBadRequestExceptionFeature> callback)
    {
        _subscription = diagnosticListener.Subscribe(this!, IsEnabled);
        _callback = callback;
    }
    private static readonly Predicate<string> IsEnabled = (provider) => provider switch
    {
        "Microsoft.AspNetCore.Server.Kestrel.BadRequest" => true,
        _ => false
    };
    public void OnNext(KeyValuePair<string, object> pair)
    {
        if (pair.Value is IFeatureCollection featureCollection)
        {
            var badRequestFeature = featureCollection.Get<IBadRequestExceptionFeature>();

            if (badRequestFeature is not null)
            {
                _callback(badRequestFeature);
            }
        }
    }
    public void OnError(Exception error) { }
    public void OnCompleted() { }
    public virtual void Dispose() => _subscription.Dispose();
}

如需詳細資訊,請參閱 Kestrel 中的記錄和診斷

從接受通訊端建立 ConnectionCoNtext

新的 SocketConnectionContextFactory 支援從接受的通訊端建立 ConnectionContext。 如此可以建置以通訊端為基礎的自訂 IConnectionListenerFactory,且不會遺失 SocketConnection 中發生的所有效能工作和共用。

請參閱這個自訂 IConnectionListenerFactory 範例,了解如何使用此 SocketConnectionContextFactory

Kestrel 是 Visual Studio 的預設啟動設定檔

所有新 DotNet Web 專案的預設啟動設定檔為 Kestrel。 啟動 Kestrel 的速度會大幅加快,而且在開發應用程式時會產生反應更靈敏的體驗。

針對 Windows 驗證或連接埠共用等案例,IIS Express 仍可作為啟動設定檔。

Kestrel 的 Localhost 連接埠是隨機的

如需詳細資訊,請參閱本文件中的範本產生的 Kestrel 連接埠

驗證和授權

驗證伺服器

.NET 3 到 .NET 5 使用 IdentityServer4 作為範本的一部分,以支援發行 SPA 和 Blazor 應用程式的 JWT 權杖。 範本現在使用 Duende Identity Server

如果您要擴充身分識別模型且正在更新現有的專案,則需要將程式碼中的命名空間從 IdentityServer4.IdentityServer 更新為 Duende.IdentityServer,並遵循移轉指示

Duende Identity 伺服器的授權模型已變更為相互授權,在實際執行環境中使用時可能需要授權費用。 如需詳細資訊,請參閱 Duende 授權頁面

延遲的用戶端憑證交涉

開發人員現在可以在 HttpsConnectionAdapterOptions 上指定 ClientCertificateMode.DelayCertificate,選擇使用延遲的用戶端憑證交涉。 這只適用於 HTTP/1.1 連線,因為 HTTP/2 禁止延遲憑證重新交涉。 此 API 的呼叫端必須先緩衝要求本文,才能要求用戶端憑證:

using Microsoft.AspNetCore.Server.Kestrel.Https;
using Microsoft.AspNetCore.WebUtilities;

var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseKestrel(options =>
{
    options.ConfigureHttpsDefaults(adapterOptions =>
    {
        adapterOptions.ClientCertificateMode = ClientCertificateMode.DelayCertificate;
    });
});

var app = builder.Build();
app.Use(async (context, next) =>
{
    bool desiredState = GetDesiredState();
    // Check if your desired criteria is met
    if (desiredState)
    {
        // Buffer the request body
        context.Request.EnableBuffering();
        var body = context.Request.Body;
        await body.DrainAsync(context.RequestAborted);
        body.Position = 0;

        // Request client certificate
        var cert = await context.Connection.GetClientCertificateAsync();

        //  Disable buffering on future requests if the client doesn't provide a cert
    }
    await next(context);
});


app.MapGet("/", () => "Hello World!");
app.Run();

現在可以使用新的 OnCheckSlidingExpiration 來自訂或隱藏 Cookie 驗證滑動期限。 例如,單頁應用程式可以使用此事件,該應用程式需要定期 Ping 伺服器,而不會影響驗證工作階段。

其他

熱重新載入

使用熱重新載入,快速更新執行中的應用程式 UI 和程式碼而不遺失應用程式狀態,以獲得更快速且更具生產力的開發人員體驗。 如需詳細資訊,請參閱 ASP.NET Core 的 .NET 熱重新載入支援以及 .NET 熱重新載入進度和 Visual Studio 2022 重點摘要更新

改善的單頁應用程式 (SPA) 範本

ASP.NET Core 專案範本已針對 Angular 和 React 更新,以便為單頁應用程式使用改良模式;此模式更加靈活,並且與新式前端 Web 開發的常見模式更一致。

先前,Angular 和 React 的 ASP.NET Core 範本會在開發期間使用特製中介軟體來啟動前端架構的開發伺服器,然後將來自 ASP.NET Core 的要求透過 Proxy 傳送到開發伺服器。 啟動前端開發伺服器的邏輯專屬於對應前端架構的命令列介面。 使用此模式支援其他前端架構,意味著為 ASP.NET Core 新增額外的邏輯。

.NET 6 中針對 Angular 和 React 更新的 ASP.NET Core 範本翻轉了這種模式,並利用大多數新式前端架構開發伺服器中內建的 Proxy 支援功能。 啟動 ASP.NET Core 應用程式時,前端開發伺服器會像之前一樣啟動,但開發伺服器會設定為透過 Proxy 傳送要求至後端 ASP.NET Core 處理序。 設定 Proxy 處理的所有前端特定組態都是應用程式的一部分,而不是 ASP.NET Core。 現在,設定 ASP.NET Core 專案並與其他前端架構搭配使用變得非常簡單:為所選架構設定前端開發伺服器,以使用 Angular 和 React 中建立的模式將要求透過 Proxy 傳送至 ASP.NET Core 後端。

ASP.NET Core 應用程式的啟動程式碼不再需要特定的單頁應用程式邏輯。 在開發期間啟動前端開發伺服器的邏輯,會在執行階段由新的 Microsoft.AspNetCore.SpaProxy 套件插入至應用程式。 後援路由是使用端點路由來處理,而非使用特定的 SPA 中介軟體。

遵循此模式的範本仍然可以在 Visual Studio 中以單一專案的形式執行,或者從命令列使用 dotnet run。 發佈應用程式時,會像​​先前一樣建置 ClientApp 資料夾中的前端程式碼並收集到主機 ASP.NET Core 應用程式的 Web 根目錄中,並且當作靜態檔案使用。 範本包含的指令碼會設定前端開發伺服器,以藉由 ASP.NET Core 開發憑證來使用 HTTPS。

.NET 6 中的 HTTP/3 支援草稿

HTTP/3 目前處於草稿階段,因此可能有所變更。 未發行 ASP.NET Core 中的 HTTP/3 支援,這是 .NET 6 包含的預覽功能。

請參閱部落格文章 .NET 6 中的 HTTP/3 支援

可為 Null 的參考型別註釋

部分 ASP.NET Core 6.0 原始程式碼已套用可 NULL 性註釋

藉由利用 C# 8 中的可為 Null 功能 (新功能),ASP.NET Core 可以在處理參考型別時提高編譯時間安全性。 例如,防止 null 參考例外狀況。 已選擇使用可 NULL 性註釋的專案可能會看到來自 ASP.NET Core API 的新建置時間警告。

若要啟用可為 Null 的參考型別,請將下列屬性新增至專案檔:

<PropertyGroup>
    <Nullable>enable</Nullable>
</PropertyGroup>

如需詳細資訊,請參閱可為 Null 的參考型別

原始程式碼分析

現已新增數個 .NET 編譯器平台分析器,以檢查應用程式程式碼是否有不正確的中介軟體組態或順序、路由衝突等問題。如需詳細資訊,請參閱 ASP.NET Core 中的程式碼分析

Web 應用程式範本改進事項

Web 應用程式範本:

  • 使用新的最小裝載模型
  • 大幅減少建立應用程式所需的檔案和程式碼數目。 例如,ASP.NET Core 空白 Web 應用程式會使用四行程式碼建立一個 C# 檔案,而且是完整的應用程式。
  • Startup.csProgram.cs 整合成單一 Program.cs 檔案。
  • 使用最上層陳述式,將應用程式所需的程式碼降至最低。
  • 使用全域 using 指示詞,消除所需的 using 陳述式行數或將其降至最低。

範本產生的 Kestrel 連接埠

在專案建立期間會指派隨機連接埠供 Kestrel Web 伺服器使用。 在同一部電腦上執行多個專案時,隨機連接埠有助於將連接埠衝突降至最低。

建立專案時,產生的 Properties/launchSettings.json 檔案中會指定介於 5000-5300 與 7000-7300 之間的隨機 HTTPS 連接埠。 您可以在 Properties/launchSettings.json 檔案中變更連接埠。 如果未指定連接埠,則 Kestrel 預設為 HTTP 5000 和 HTTPS 5001 連接埠。 如需詳細資訊,請參閱設定 ASP.NET Core Kestrel Web 伺服器的端點

新的記錄預設值

appsettings.jsonappsettings.Development.json 已進行下列變更:

- "Microsoft": "Warning",
- "Microsoft.Hosting.Lifetime": "Information"
+ "Microsoft.AspNetCore": "Warning"

"Microsoft": "Warning" 變更為 "Microsoft.AspNetCore": "Warning" 會導致記錄來自 Microsoft 命名空間的所有資訊性訊息,但 Microsoft.AspNetCore除外。 例如,Microsoft.EntityFrameworkCore 現在會記錄在資訊層級。

自動新增開發人員例外狀況頁面中介軟體

開發環境中,預設會新增 DeveloperExceptionPageMiddleware。 不再需要將以下程式碼新增至 Web UI 應用程式:

if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}

支援 HttpSysServer 中的 Latin1 編碼的要求標頭

HttpSysServer 現在支援 Latin1 編碼的要求標頭,方法是將 HttpSysOptions 上的 UseLatin1RequestHeaders 屬性設定為 true

var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseHttpSys(o => o.UseLatin1RequestHeaders = true);

var app = builder.Build();

app.MapGet("/", () => "Hello World!");

app.Run();

ASP.NET Core 模組記錄包含時間戳記和 PID

IIS 的 ASP.NET Core 模組 (ANCM) (ANCM) 增強型診斷記錄包含發出記錄之處理序的時間戳記和 PID。 執行多個 IIS 背景工作處理序時,記錄時間戳記和 PID 有助於診斷 IIS 中發生的重疊處理序重新啟動問題。

產生的記錄現在類似範例輸出,如下所示:

[2021-07-28T19:23:44.076Z, PID: 11020] [aspnetcorev2.dll] Initializing logs for 'C:\<path>\aspnetcorev2.dll'. Process Id: 11020. File Version: 16.0.21209.0. Description: IIS ASP.NET Core Module V2. Commit: 96475a2acdf50d7599ba8e96583fa73efbe27912.
[2021-07-28T19:23:44.079Z, PID: 11020] [aspnetcorev2.dll] Resolving hostfxr parameters for application: '.\InProcessWebSite.exe' arguments: '' path: 'C:\Temp\e86ac4e9ced24bb6bacf1a9415e70753\'
[2021-07-28T19:23:44.080Z, PID: 11020] [aspnetcorev2.dll] Known dotnet.exe location: ''

IIS 的可設定且未使用的傳入緩衝區大小

IIS 伺服器先前只緩衝處理 64 KiB 的未使用要求本文。 64 KiB 緩衝處理導致讀取受限於大小上限,這會影響大型本文的傳入效能,例如上傳。 在 .NET 6 中,預設緩衝區大小從 64 KiB 變更為 1 MiB,如此應可改善大型上傳作業的輸送量。 根據我們的測試,過去花費 9 秒的 700 MiB 上傳作業,現在只需 2.5 秒。

較大緩衝區大小的缺點是,當應用程式無法快速讀取要求本文時,每個要求的記憶體耗用量會增加。 因此,除了變更預設緩衝區大小之外,也可設定緩衝區大小,因而應用程式能根據工作負載設定緩衝區大小。

檢視元件作為標記協助程式

請考慮具有選擇性參數的檢視元件,如下列程式碼所示:

class MyViewComponent
{
    IViewComponentResult Invoke(bool showSomething = false) { ... }
}

使用 ASP.NET Core 6 時,可叫用標記協助程式,而不需要為 showSomething 參數指定值:

<vc:my />

Angular 範本已更新為 Angular 12

適用於 Angular 的 ASP.NET Core 6.0 範本現在使用 Angular 12

React 範本已更新為 React 17

以 Json.NET 輸出格式器寫入磁碟之前的可設定緩衝區閾值

注意:除非基於相容性原因而需使用 Newtonsoft.Json 序列化程式,否則建議使用 System.Text.Json 輸出格式器。 System.Text.Json 序列化程式已完全 async,且能有效率地用於較大承載。

根據預設,Newtonsoft.Json 輸出格式器會先在記憶體中回應最多 32 KiB,再緩衝至磁碟。 這是為了避免執行同步 IO,但可能造成執行緒耗盡和應用程式死結等其他副作用。 不過,如果回應大於 32 KiB,就會發生大量磁碟 I/O。 記憶體閾值現在可透過 MvcNewtonsoftJsonOptions.OutputFormatterMemoryBufferThreshold 屬性進行設定,然後再緩衝至磁碟:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages()
            .AddNewtonsoftJson(options =>
            { 
                options.OutputFormatterMemoryBufferThreshold = 48 * 1024;
            });

var app = builder.Build();

如需詳細資訊,請參閱此 GitHub 提取要求NewtonsoftJsonOutputFormatterTest.cs 檔案。

更快速地取得和設定 HTTP 標頭

已新增新的 API,將 Microsoft.Net.Http.Headers.HeaderNames 上可用的所有通用標頭公開為 IHeaderDictionary 上的屬性,從而使 API 更容易使用。 例如,下列程式碼中的內嵌中介軟體會使用新的 API 來取得並設定要求和回應標頭:

var builder = WebApplication.CreateBuilder(args);

var app = builder.Build();

app.MapGet("/", () => "Hello World!");

app.Use(async (context, next) =>
{
    var hostHeader = context.Request.Headers.Host;
    app.Logger.LogInformation("Host header: {host}", hostHeader);
    context.Response.Headers.XPoweredBy = "ASP.NET Core 6.0";
    await next.Invoke(context);
    var dateHeader = context.Response.Headers.Date;
    app.Logger.LogInformation("Response date: {date}", dateHeader);
});

app.Run();

對於實作的標頭,實作 get 和 set 存取子時會直接前往欄位並略過查閱。 對於未實作的標頭,存取子可以略過對實作標頭的初始查閱,並且直接執行 Dictionary<string, StringValues> 查閱。 避免查閱可加快這兩種案例的存取速度。

非同步串流

ASP.NET Core 現在支援來自控制器動作的非同步串流,以及來自 JSON 格式器的回應。 從動作傳回 IAsyncEnumerable,在記憶體中的回應內容傳送之前不再對其緩衝處理。 傳回可以非同步列舉的大型資料集時,不進行緩衝有助於減少記憶體使用量。

請注意,Entity Framework Core 提供用於查詢資料庫的 IAsyncEnumerable 實作。 .NET 6 中的 ASP.NET Core 改善了對 IAsyncEnumerable 的支援,讓 ASP.NET Core 與 EF Core 搭配使用時更有效率。 例如,下列程式碼在傳送回應之前,不再將產品資料緩衝至記憶體:

public IActionResult GetMovies()
{
    return Ok(_context.Movie);
}

不過,在 EF Core 中使用延後載入時,這個新行為可能會導致列舉資料時發生並行查詢執行所造成的錯誤。 應用程式可以藉由緩衝資料來還原回先前的行為:

public async Task<IActionResult> GetMovies2()
{
    return Ok(await _context.Movie.ToListAsync());
}

如需此行為變更的其他詳細資料,請參閱相關公告

HTTP 記錄中介軟體

HTTP 記錄是新的內建中介軟體,可記錄 HTTP 要求和 HTTP 回應的相關資訊,包括標頭和全部本文:

var builder = WebApplication.CreateBuilder(args);

var app = builder.Build();
app.UseHttpLogging();

app.MapGet("/", () => "Hello World!");

app.Run();

使用先前的程式碼記錄檔資訊瀏覽至 /,類似下列輸出:

info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[1]
      Request:
      Protocol: HTTP/2
      Method: GET
      Scheme: https
      PathBase: 
      Path: /
      Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
      Accept-Encoding: gzip, deflate, br
      Accept-Language: en-US,en;q=0.9
      Cache-Control: max-age=0
      Connection: close
      Cookie: [Redacted]
      Host: localhost:44372
      User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36 Edg/95.0.1020.30
      sec-ch-ua: [Redacted]
      sec-ch-ua-mobile: [Redacted]
      sec-ch-ua-platform: [Redacted]
      upgrade-insecure-requests: [Redacted]
      sec-fetch-site: [Redacted]
      sec-fetch-mode: [Redacted]
      sec-fetch-user: [Redacted]
      sec-fetch-dest: [Redacted]
info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[2]
      Response:
      StatusCode: 200
      Content-Type: text/plain; charset=utf-8

上面的輸出是使用以下 appsettings.Development.json 檔案啟用:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning",
      "Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware": "Information"
    }
  }
}

HTTP 記錄提供下列項目的記錄:

  • HTTP 要求資訊
  • 通用屬性
  • 標頭
  • 本文
  • HTTP 回應資訊

若要設定 HTTP 記錄中介軟體,請指定 HttpLoggingOptions

using Microsoft.AspNetCore.HttpLogging;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(logging =>
{
    // Customize HTTP logging.
    logging.LoggingFields = HttpLoggingFields.All;
    logging.RequestHeaders.Add("My-Request-Header");
    logging.ResponseHeaders.Add("My-Response-Header");
    logging.MediaTypeOptions.AddText("application/javascript");
    logging.RequestBodyLogLimit = 4096;
    logging.ResponseBodyLogLimit = 4096;
});

var app = builder.Build();
app.UseHttpLogging();

app.MapGet("/", () => "Hello World!");

app.Run();

IConnectionSocketFeature

IConnectionSocketFeature 要求功能支援存取與目前要求關聯的基礎接受通訊端。 可以透過 HttpContext 上的 FeatureCollection 來進行存取。

例如,下列應用程式會在接受的通訊端上設定 LingerState 屬性:

var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
    serverOptions.ConfigureEndpointDefaults(listenOptions => listenOptions.Use((connection, next) =>
    {
        var socketFeature = connection.Features.Get<IConnectionSocketFeature>();
        socketFeature.Socket.LingerState = new LingerOption(true, seconds: 10);
        return next();
    }));
});
var app = builder.Build();
app.MapGet("/", (Func<string>)(() => "Hello world"));
await app.RunAsync();

Razor 中的泛型型別條件約束

現在使用 @typeparam 指示詞在 Razor 中定義泛型型別參數時,可以透過標準 C# 語法來指定泛型型別條件約束:

較小的 SignalR、Blazor Server 和 MessagePack 指令碼

SignalR、MessagePack 和 Blazor Server 指令碼現在明顯較小,因此可以減少下載量、減少瀏覽器解析和編譯的 JavaScript 並加快啟動速度。 大小縮減:

  • signalr.js:70%
  • blazor.server.js:45%

較小的指令碼是 Ben Adams 社群的協作成果。 如需縮減大小的詳細資訊,請參閱 Ben 的 GitHub 提取要求

啟用 Redis 分析工作階段

來自 Gabriel Lucaci 的社群協作使用 Microsoft.Extensions.Caching.StackExchangeRedis 啟用 Redis 分析工作階段:

using StackExchange.Redis.Profiling;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddStackExchangeRedisCache(options =>
{
    options.ProfilingSession = () => new ProfilingSession();
});

如需詳細資訊,請參閱 StackExchange.Redis 分析

IIS 中的陰影複製

IIS 的 ASP.NET Core 模組 (ANCM) 中新增了一項實驗性功能,以增加對陰影複製應用程式組件的支援。 目前 .NET 在 Windows 上執行時會鎖定應用程式二進位檔,因此無法在應用程式執行時取代二進位檔。 雖然建議仍要使用應用程式離線檔案,但我們發現在某些情況下 (例如 FTP 部署) 無法這麼做。

在這些情況下,請自訂 ASP.NET Core 模組處理常式設定以啟用陰影複製。 大多數情況下,ASP.NET Core 應用程式不會將 web.config 簽入您可以修改的原始程式碼控制。 在 ASP.NET Core 中,web.config 通常由 SDK 產生。 您可使用下列範例 web.config 來開始:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <!-- To customize the asp.net core module uncomment and edit the following section. 
  For more info see https://go.microsoft.com/fwlink/?linkid=838655 -->

  <system.webServer>
    <handlers>
      <remove name="aspNetCore"/>
      <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified"/>
    </handlers>
    <aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout">
      <handlerSettings>
        <handlerSetting name="experimentalEnableShadowCopy" value="true" />
        <handlerSetting name="shadowCopyDirectory" value="../ShadowCopyDirectory/" />
        <!-- Only enable handler logging if you encounter issues-->
        <!--<handlerSetting name="debugFile" value=".\logs\aspnetcore-debug.log" />-->
        <!--<handlerSetting name="debugLevel" value="FILE,TRACE" />-->
      </handlerSettings>
    </aspNetCore>
  </system.webServer>
</configuration>

IIS 中的陰影複製是實驗性功能,不保證會成為 ASP.NET Core 的一部分。 請在 此 GitHub 問題中留下對 IIS 陰影複製的意見反應。

其他資源