ASP.NET Core 8.0 的新功能

本文會重點說明 ASP.NET Core 8.0 最重要的變更,附有相關文件的連結。

Blazor

完整堆疊 Web UI

使用 .NET 8 版本時,Blazor 是一個完整堆疊 Web UI 架構,可用來開發以元件或頁面層級轉譯內容的應用程式:

  • 靜態伺服器轉譯 (也稱為靜態伺服器端轉譯、靜態 SSR),以在伺服器上產生靜態 HTML。
  • 互動式伺服器轉譯 (也稱為互動式伺服器端轉譯、互動式 SSR),以透過在伺服器上預先轉譯來產生互動式元件。
  • 互動式 WebAssembly 轉譯 (也稱為用戶端轉譯、CSR,一律假設為互動式),以透過在伺服器上預先轉譯而在用戶端上產生互動式元件。
  • 互動式自動轉譯,以在一開始就使用伺服器端 ASP.NET Core 執行階段來進行內容轉譯和互動。 在下載 Blazor 套件組合並啟動 WebAssembly 執行階段後,會使用用戶端上的 .NET WebAssembly 執行階段來進行後續的轉譯和互動。 互動式自動轉譯通常可提供最快的應用程式啟動體驗。

根據預設,互動式轉譯模式也會預先轉譯內容。

如需詳細資訊,請參閱下列文章:

Blazor 文件中的範例皆已更新,可用於 Blazor Web Apps。 Blazor Server 範例會留在適用版本為 .NET 7 或更早版本的內容中。

關於使用靜態伺服器端轉譯 (靜態 SSR) 的類別庫的新文章

我們已新增了一篇新文章,討論在 Razor 類庫 (RCL) 中使用靜態伺服器端轉譯 (靜態 SSR) 進行元件庫的撰寫。

如需詳細資訊,請參閱使用靜態伺服器端轉譯 (靜態 SSR) 的 ASP.NET Core Razor 類別庫 (RCL) (英文)。

有關 HTTP 快取問題的新文章

我們已新增了一篇新文章,討論在主要版本之間升級 Blazor 應用程式時可能出現的一些常見 HTTP 快取問題,以及如何解決 HTTP 快取問題。

如需詳細資訊,請參閱在升級 ASP.NET Core Blazor 應用程式時避免 HTTP 快取問題 (英文)。

新增 Blazor Web 應用程式範本

我們引進了新的 Blazor 專案範本:Blazor Web 應用程式 範本。 新的範本提供單一起點,可使用 Blazor 元件來建置任何樣式的 Web UI。 此範本結合了現有 Blazor Server 和 Blazor WebAssembly 主控模型的優點與 .NET 8 中新增的 Blazor 功能:靜態伺服器端轉譯 (靜態 SSR)、串流轉譯、增強的導覽和表單處理,以及以個別元件方式使用 Blazor Server 或 Blazor WebAssembly 以新增互動功能的能力。

在將各種 Blazor 主控模型統一為 .NET 8 中的單一模型過程中,我們也將 Blazor 專案範本數目合併在一起。 我們已移除 Blazor Server 範本,並且已從 Blazor WebAssembly 範本中移除 ASP.NET Core Hosted 選項。 這兩個案例都是以使用 Blazor Web 應用程式範本時的選項來表示。

注意

.NET 8 中仍支援現有的 Blazor Server 和 Blazor WebAssembly 應用程式。 您可以選擇性地更新這些應用程式,以使用新的完整堆疊 Web UI Blazor 功能。

如需新 Blazor Web 應用程式範本的相關詳細資訊,請參閱下列文章:

適用於 Blazor Web Apps 的新 JS 初始設定式

針對 Blazor Server、Blazor WebAssembly 和 Blazor Hybrid 應用程式:

  • beforeStart 會用於自訂載入程序、記錄層級和其他選項等工作。
  • afterStarted 會用於註冊 Blazor 事件接聽程式和自訂事件類型等工作。

在 Blazor Web 應用程式中,預設不會叫用上述舊版 JS 初始設定式。 Blazor Web Apps 會使用一組新的 JS 初始設定式:beforeWebStartafterWebStartedbeforeServerStartafterServerStartedbeforeWebAssemblyStartafterWebAssemblyStarted

如需詳細資訊,請參閱 ASP.NET Core Blazor 啟動

分割預先轉譯和整合的指引

在舊版 .NET 中,我們是在單一文章中討論預先轉譯和整合。 為了簡化並聚焦討論範圍,我們將這兩個主題分割為下列新文章,並已針對 .NET 8 進行更新:

在 Blazor Web 應用程式中保存元件狀態

您可以使用現有的 PersistentComponentState 服務,在 Blazor Web 應用程式中保存及讀取元件狀態。 這對於在預先轉譯期間保存元件狀態很有用。

Blazor Web Apps 會自動保存預先轉譯期間所建立的任何已註冊應用程式層級狀態,因此不必再保存元件狀態標籤協助程式

表單處理和模型繫結

Blazor 元件現在可以處理提交的表單要求,包括模型繫結及驗證要求資料。 元件可以使用標準 HTML <form> 標記或使用現有的 EditForm 元件,以個別表單處理常式實作表單。

Blazor 中的表單模型繫結會接受資料合約屬性 (例如 [DataMember][IgnoreDataMember]),以自訂表單資料繫結至模型的方式。

.NET 8 中包含新的防偽支援。 新的 AntiforgeryToken 元件會將防偽權杖轉譯為隱藏欄位,而新的 [RequireAntiforgeryToken] 屬性會啟用防偽保護。 如果防偽檢查失敗,則會傳回 400 (錯誤的要求) 回應,而不會處理表單。 依預設,表單會根據 Editform 啟用新的防偽功能,且可以手動套用至標準 HTML 表單。

如需詳細資訊,請參閱 ASP.NET Core Blazor 表單概觀

增強的瀏覽和表單處理

每當使用者導覽至新頁面或提交表單時,靜態伺服器端轉譯 (靜態 SSR) 通常會執行完整頁面重新整理。 在 .NET 8 中,Blazor 可以攔截要求並改為執行擷取要求,以增強頁面瀏覽和表單處理。 Blazor 接著會將轉譯的回應內容修補到瀏覽器 DOM 中,以處理轉譯的回應內容。 增強的瀏覽和表單處理不需要完整頁面重新整理並可保留更多頁面狀態,因此頁面載入更快且更順暢。 載入指令碼 (blazor.web.js) 時,預設會啟用增強的 Blazor 瀏覽。 特定表單可以選擇性地啟用增強型表單處理。

新的增強型瀏覽 API 可讓您呼叫 NavigationManager.Refresh(bool forceLoad = false) 來重新整理目前的頁面。

如需詳細資訊,請參閱 Blazor路由一文的下列章節:

關於使用 JS Interop 的增強式導覽進行靜態轉譯的新文章

某些應用程式依賴 JS Interop 來執行每個頁面專屬的初始化工作。 在使用 Blazor 的增強式導覽功能搭配執行 JS Interop 初始化工作的靜態轉譯頁面時,每次進行增強式頁面導覽時,頁面專屬的 JS 可能不會如預期般再次執行。 有新文章會說明如何在 Blazor Web Apps 中解決此案例:

具有靜態伺服器端轉譯 (靜態 SSR) 的 ASP.NET Core Blazor JavaScript

串流轉譯

使用靜態伺服器端轉譯 (靜態 SSR) 搭配 Blazor 時,您現在可以在回應串流上串流內容更新。 串流轉譯可以改善執行長時間執行非同步工作的頁面使用者體驗,以便在內容可供使用時,立即完整轉譯。

例如,若要轉譯頁面,您可能需要進行長時間執行的資料庫查詢或 API 呼叫。 一般而言,在轉譯頁面時執行的非同步工作必須在傳送轉譯的回應之前完成,這可能會使載入頁面產生延遲。 串流轉譯一開始會在非同步作業執行時,以預留位置內容轉譯整個頁面。 非同步作業完成之後,更新的內容會傳送至相同回應連線上的用戶端,並修補為 DOM。 這種方法的優點是,應用程式的主要配置會儘快轉譯,並在內容就緒時立即更新頁面。

如需詳細資訊,請參閱 ASP.NET Core Razor 元件轉譯

將索引鍵服務插入元件

Blazor 現在支援使用 [Inject] 屬性插入索引鍵服務。 索引鍵允許在使用相依性插入時,限制服務的註冊和取用範圍。 使用新的 InjectAttribute.Key 屬性來指定服務要插入的索引鍵:

[Inject(Key = "my-service")]
public IMyService MyService { get; set; }

@injectRazor 指示詞不支援此版本的索引鍵服務,但未來的 .NET 版本會透過更新 @inject 以支援索引鍵服務 (dotnet/razor #9286) 來追蹤工作。

如需詳細資訊,請參閱 ASP.NET Core Blazor 相依性插入

以串聯參數的形式存取 HttpContext

您現在可以從靜態伺服器元件存取目前 HttpContext 做為串聯參數:

[CascadingParameter]
public HttpContext? HttpContext { get; set; }

若要檢查及修改標頭或其他屬性,從靜態伺服器元件存取 HttpContext 可能很有用。

如需將 HttpContext 狀態、存取和重新整理權杖傳遞至元件的範例,請參閱伺服器端 ASP.NET Core Blazor 其他安全性案例

轉譯 ASP.NET Core 以外的 Razor 元件

您現在可以轉譯 HTTP 要求內容以外的 Razor 元件。 您可以直接將 Razor 元件以 HTML 轉譯成字串或串流,而不受 ASP.NET Core 主控環境影響。 這對於您要產生 HTML 片段的案例很方便,例如產生電子郵件或靜態網站內容的案例。

如需詳細資訊,請參閱轉譯 ASP.NET Core 以外的 Razor 元件

區段支援

Blazor 中新的 SectionOutletSectionContent 元件可新增支援,指定稍後可填入內容的輸出。 區段通常可用來定義配置中的預留位置,然後由特定頁面加以填入。 會以唯一的名稱或使用唯一的物件識別碼來參考區段。

如需詳細資訊,請參閱 ASP.NET Core Blazor 區段

錯誤頁面支援

Blazor Web Apps 可以定義自訂錯誤頁面,以搭配 ASP.NET Core 例外狀況處理中介軟體使用。 Blazor Web App 專案範本包含預設錯誤頁面 (Components/Pages/Error.razor),其內容類別似 MVC 和 Razor Pages 應用程式中所使用的錯誤頁面。 當轉譯錯誤頁面以回應例外狀況處理中介軟體的要求時,即使啟用互動功能,錯誤頁面一律會轉譯為靜態伺服器元件。

8.0 中的 Error.razor 參考來源

QuickGrid

Blazor QuickGrid 元件已不再是實驗性元件,現在是屬於 .NET 8 中的 Blazor 架構。

QuickGrid 是高效能格線元件,可用於以表格式格式顯示資料。 QuickGrid 的建置方式是以簡單且方便的方式來顯示您的資料,同時仍提供強大的功能,例如排序、篩選、分頁和虛擬化。

如需詳細資訊,請參閱 ASP.NET Core Blazor QuickGrid 元件

路由至具名元素

Blazor 現在支援使用用戶端路由,以使用標準 URL 片段瀏覽至頁面上的特定 HTML 元素。 如果您使用標準 id 屬性來指定 HTML 元素的識別碼,當 URL 片段符合元素識別碼時,Blazor 會正確地捲動至該元素。

如需詳細資訊,請參閱 ASP.NET Core Blazor 路由和瀏覽

根層級串聯值

可以登錄整個元件階層的根層級串聯值。 支援更新通知的具名串聯值和訂用帳戶。

如需詳細資訊,請參閱 ASP.NET Core Blazor 串聯值和參數

虛擬化空白內容

當元件已載入且 Items 為空白或者 ItemsProviderResult<T>.TotalItemCount 為零時,請使用元件上的 VirtualizeEmptyContent 參數來提供內容。

如需詳細資訊,請參閱 ASP.NET Core Razor 元件虛擬化

沒有剩餘的互動式伺服器元件時關閉線路

互動式伺服器元件會使用與稱為線路的瀏覽器即時連線來處理 Web UI 事件。 轉譯根互動式伺服器元件時,會設定線路及其相關聯的狀態。 當頁面上沒有剩餘的互動式伺服器元件時,線路會關閉並釋放伺服器資源。

監視 SignalR 線路活動

您現在可以使用 CircuitHandler 上的新 CreateInboundActivityHandler 方法來監視伺服器端應用程式中的輸入線路活動。 輸入線路活動是從瀏覽器傳送至伺服器的任何活動,例如 UI 事件或 JavaScript-to-.NET Interop 呼叫。

如需詳細資訊,請參閱 ASP.NET Core BlazorSignalR 指引

使用 Jiterpreter 加快執行階段效能

Jiterpreter 是 .NET 8 中新的執行階段功能,可在 WebAssembly 上執行時啟用部分 Just-In-Time 編譯支援,以達到改善的執行階段效能。

如需詳細資訊,請參閱裝載和部署 ASP.NET Core Blazor WebAssembly

預先 (AOT) SIMD 和例外狀況處理

Blazor WebAssembly 預先 (AOT) 編譯現在預設會使用 WebAssembly 固定寬度 SIMDWebAssembly 例外狀況處理來改善執行階段效能。

如需詳細資訊,請參閱下列文章:

網頁式 Webcil 封裝

Webcil 是 .NET 元件的網頁式封裝,可移除原生 Windows 執行特有的內容,以避免部署至封鎖下載或使用 .dll 檔案的環境時發生問題。 Blazor WebAssembly 應用程式預設會啟用 Webcil。

如需詳細資訊,請參閱裝載和部署 ASP.NET Core Blazor WebAssembly

注意

在 .NET 8 發行之前,ASP.NET Core 裝載式 Blazor WebAssembly 應用程式的部署配置中的指導可解決會阻止用戶端以多部分統合方法下載和執行 DLL 的環境。 在 .NET 8 或更新版本中,Blazor 會使用 Webcil 檔案格式解決此問題。 .NET 8 或更新版本中的 Blazor 應用程式不支援使用實驗性 NuGet 套件進行多部分統合 (如 WebAssembly 部署配置一文所述)。 如需詳細資訊,請參閱增強 Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle 套件以定義自訂套件組合格式 (dotnet/aspnetcore #36978)。 如果您想要在 .NET 8 或更新版本的應用程式中繼續使用多部分套件組合套件,則可以使用本文中的指導來建立自己的多部分統合 NuGet 套件,但這不會受到 Microsoft 支援。

Blazor WebAssembly 偵錯改進

在 WebAssembly 上偵錯 .NET 時,偵錯工具現在會從 Visual Studio 喜好設定中設定的符號位置下載符號資料。 這可改善應用程式使用 NuGet 套件的偵錯體驗。

您現在可以使用 Firefox 對 Blazor WebAssembly 應用程式進行偵錯。 偵錯 Blazor WebAssembly 應用程式需要設定瀏覽器以進行遠端偵錯,然後透過 .NET WebAssembly 偵錯 Proxy,使用瀏覽器開發人員工具連線到瀏覽器。 目前不支援從 Visual Studio 偵錯 Firefox。

如需詳細資訊,請參閱偵錯 ASP.NET Core Blazor 應用程式

內容安全性原則 (CSP) 相容性

指定內容安全性原則 (CSP) 時,Blazor WebAssembly 不再需要啟用 unsafe-eval 指令碼來源。

如需詳細資訊,請參閱針對 ASP.NET Core Blazor 強制執行內容安全性原則

處理 Razor 元件生命週期外攔截到的例外狀況

在 Razor 元件中使用 ComponentBase.DispatchExceptionAsync 來處理元件生命週期呼叫堆疊外擲出的例外狀況。 這可讓元件的程式碼將例外狀況視為生命週期方法例外狀況。 之後,Blazor 錯誤處理機制 (例如錯誤界限) 可以處理例外狀況。

如需詳細資訊,請參閱處理 ASP.NET Core Blazor 應用程式中的錯誤

設定 .NET WebAssembly 執行階段

現在可以將 .NET WebAssembly 執行階段設定為 Blazor 啟動。

如需詳細資訊,請參閱 ASP.NET Core Blazor 啟動

HubConnectionBuilder 中設定連線逾時

設定中樞連線逾時的先前因應措施可以取代為正式的 SignalR 中樞連線建立器逾時設定。

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

專案範本流出 Open Iconic

Blazor 專案範本不再相依於圖示的 Open Iconic

支援對話方塊取消和關閉事件

Blazor 現在支援 dialog HTML 元素上的 cancelclose 事件。

在以下範例中:

  • 當使用 [關閉] 按鈕關閉 my-dialog 對話方塊時,會呼叫 OnClose
  • 當使用 Esc 鍵取消對話方塊時,會呼叫 OnCancel。 當使用 Esc 鍵關閉 HTML 對話方塊時,就會觸發 cancelclose 事件。
<div>
    <p>Output: @message</p>

    <button onclick="document.getElementById('my-dialog').showModal()">
        Show modal dialog
    </button>

    <dialog id="my-dialog" @onclose="OnClose" @oncancel="OnCancel">
        <p>Hi there!</p>

        <form method="dialog">
            <button>Close</button>
        </form>
    </dialog>
</div>

@code {
    private string? message;

    private void OnClose(EventArgs e) => message += "onclose, ";

    private void OnCancel(EventArgs e) => message += "oncancel, ";
}

BlazorIdentity UI

當您選擇 [個別帳戶] 的驗證選項時,Blazor 支援產生完整 Blazor 型 Identity UI。 您可以從 Visual Studio 在 Blazor Web Apps 的新專案對話方塊中選取 [個別帳戶] 選項,也可以在建立新專案時,從命令列傳遞設定為 Individual-au|--auth 選項。

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

使用 ASP.NET Core Identity 保護 Blazor WebAssembly

Blazor 文件會裝載新的文章和範例應用程式,以涵蓋如何使用 ASP.NET Core Identity 來保護獨立 Blazor WebAssembly 應用程式。

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

使用 Yarp 的 Blazor Server 路由

使用 Yarp 的 Blazor Server 路由和深層連結可在 .NET 8 中正確運作。

如需詳細資訊,請參閱從 ASP.NET Core 7.0 移轉到 8.0

Blazor Hybrid

下列文章會記載 .NET 8 中的 Blazor Hybrid 變更:

從查詢字串中提供時不再需要 [Parameter] 屬性

從查詢字串中提供參數時不再需要 [Parameter] 屬性:

- [Parameter]
  [SupplyParameterFromQuery]

SignalR

設定伺服器逾時和 Keep-Alive 間隔的新方法

ServerTimeout (預設值:30 秒) 和 KeepAliveInterval (預設值:15 秒) 可以直接在 HubConnectionBuilder 上設定。

JavaScript 用戶端的先前方法

下列範例顯示值指派,這些值是 ASP.NET Core 7.0 或更舊版本中預設值的兩倍:

var connection = new signalR.HubConnectionBuilder()
  .withUrl("/chatHub")
  .build();

connection.serverTimeoutInMilliseconds = 60000;
connection.keepAliveIntervalInMilliseconds = 30000;

JavaScript 用戶端的新方法

下列範例顯示指派值的新方法,這些值是 ASP.NET Core 8.0 或更新版本中預設值的兩倍:

var connection = new signalR.HubConnectionBuilder()
  .withUrl("/chatHub")
  .withServerTimeout(60000)
  .withKeepAlive(30000)
  .build();

Blazor Server 應用程式的 JavaScript 用戶端先前方法

下列範例顯示值指派,這些值是 ASP.NET Core 7.0 或更舊版本中預設值的兩倍:

Blazor.start({
  configureSignalR: function (builder) {
    let c = builder.build();
    c.serverTimeoutInMilliseconds = 60000;
    c.keepAliveIntervalInMilliseconds = 30000;
    builder.build = () => {
      return c;
    };
  }
});

伺服器端 Blazor 應用程式 JavaScript 用戶端的新方法

下列範例會示範針對 Blazor Web Apps 和 Blazor Server 來指派值的新方法,這些值是 ASP.NET Core 8.0 或更新版本中預設值的兩倍。

Blazor Web 應用程式:

Blazor.start({
  circuit: {
    configureSignalR: function (builder) {
      builder.withServerTimeout(60000).withKeepAliveInterval(30000);
    }
  }
});

Blazor Server:

Blazor.start({
  configureSignalR: function (builder) {
    builder.withServerTimeout(60000).withKeepAliveInterval(30000);
  }
});

.NET 用戶端的先前方法

下列範例顯示值指派,這些值是 ASP.NET Core 7.0 或更舊版本中預設值的兩倍:

var builder = new HubConnectionBuilder()
    .WithUrl(Navigation.ToAbsoluteUri("/chathub"))
    .Build();

builder.ServerTimeout = TimeSpan.FromSeconds(60);
builder.KeepAliveInterval = TimeSpan.FromSeconds(30);

builder.On<string, string>("ReceiveMessage", (user, message) => ...

await builder.StartAsync();

.NET 用戶端的新方法

下列範例顯示指派值的新方法,這些值是 ASP.NET Core 8.0 或更新版本中預設值的兩倍:

var builder = new HubConnectionBuilder()
    .WithUrl(Navigation.ToAbsoluteUri("/chathub"))
    .WithServerTimeout(TimeSpan.FromSeconds(60))
    .WithKeepAliveInterval(TimeSpan.FromSeconds(30))
    .Build();

builder.On<string, string>("ReceiveMessage", (user, message) => ...

await builder.StartAsync();

SignalR 具狀態重新連線

SignalR 具狀態重新連線可減少用戶端在網路連線中暫時中斷連線的感知停機時間,例如切換網路連線或短暫的存取中斷。

具狀態重新連線藉由以下方式達成此目的:

  • 暫時緩衝伺服器和用戶端上的資料。
  • 確認伺服器和用戶端都已接收到訊息 (ACK-ing)。
  • 辨識連線何時傳回,並重新執行連線關閉時可能已傳送的訊息。

具狀態重新連線可在 ASP.NET Core 8.0 和更高版本中使用。

選擇在伺服器中樞端點和用戶端上進行具狀態重新連線:

  • 更新伺服器中樞端點組態以啟用 AllowStatefulReconnects 選項:

    app.MapHub<MyHub>("/hubName", options =>
    {
        options.AllowStatefulReconnects = true;
    });
    

    您也可以全域設定伺服器允許的緩衝區大小上限 (以位元組為單位),或透過 StatefulReconnectBufferSize 選項來設定特定中樞:

    全域設定 StatefulReconnectBufferSize 選項:

    builder.AddSignalR(o => o.StatefulReconnectBufferSize = 1000);
    

    針對特定中樞設定 StatefulReconnectBufferSize 選項:

    builder.AddSignalR().AddHubOptions<MyHub>(o => o.StatefulReconnectBufferSize = 1000);
    

    StatefulReconnectBufferSize 選項是選擇性的,預設為 100,000 個位元組。

  • 更新 JavaScript 或 TypeScript 用戶端程式碼以啟用 withStatefulReconnect 選項:

    const builder = new signalR.HubConnectionBuilder()
      .withUrl("/hubname")
      .withStatefulReconnect({ bufferSize: 1000 });  // Optional, defaults to 100,000
    const connection = builder.build();
    

    bufferSize 選項是選擇性的,預設為 100,000 個位元組。

  • 更新 .NET 用戶端程式碼以啟用 WithStatefulReconnect 選項:

      var builder = new HubConnectionBuilder()
          .WithUrl("<hub url>")
          .WithStatefulReconnect();
      builder.Services.Configure<HubConnectionOptions>(o => o.StatefulReconnectBufferSize = 1000);
      var hubConnection = builder.Build();
    

    StatefulReconnectBufferSize 選項是選擇性的,預設為 100,000 個位元組。

如需詳細資訊,請參閱設定具狀態重新連線

最小 API

本節說明基本 API 的新功能。 另請參閱原生 AOT 一節,以取得與基本 API 相關的詳細資訊。

使用者覆寫文化特性

從 ASP.NET Core 8.0 開始,RequestLocalizationOptions.CultureInfoUseUserOverride 屬性可讓應用程式決定是否使用非預設的 Windows 設定做為 CultureInfoDateTimeFormatNumberFormat 屬性。 這不會對 Linux 造成任何影響。 這會直接對應至 UseUserOverride

    app.UseRequestLocalization(options =>
    {
        options.CultureInfoUseUserOverride = false;
    });

繫結至表單

現在支援使用 [FromForm] 屬性明確繫結至表單值。 以 [FromForm] 繫結至要求的參數包含防偽權杖。 處理要求時,防偽權杖會經過驗證。

也支援使用 IFormCollectionIFormFileIFormFileCollection 類型對表單的推斷繫結。 OpenAPI 中繼資料會推斷為表單參數,可支援與 Swagger UI 的整合。

如需詳細資訊,請參閱

現在支援從表單繫結:

  • 集合,例如清單字典
  • 複雜類型,例如 TodoProject

如需詳細資訊,請參閱繫結至表單中的集合和複雜類型

使用基本 API 的防偽

此版本新增了一個中介軟體來驗證防偽權杖,可用來減輕跨網站偽造要求攻擊。 呼叫 AddAntiforgery 以在 DI 中註冊防偽服務。 在 DI 容器中註冊防偽服務時,WebApplicationBuilder 會自動新增中介軟體。 防偽權杖可用來減輕跨網站偽造要求攻擊

var builder = WebApplication.CreateBuilder();

builder.Services.AddAntiforgery();

var app = builder.Build();

app.UseAntiforgery();

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

app.Run();

防偽中介軟體:

只有在下列狀況下,才會驗證防偽權杖:

  • 端點包含實作 IAntiforgeryMetadata 的中繼資料,其中 RequiresValidation=true
  • 與端點相關聯的 HTTP 方法是相關的 HTTP 方法。 相關方法是 TRACE、OPTIONS、HEAD 和 GET 以外的所有 HTTP 方法
  • 要求與有效的端點相關聯。

如需詳細資訊,請參閱使用基本 API 進行防偽

ObjectPool 中新增 IResettable 介面

Microsoft.Extensions.ObjectPool 支援在記憶體中共用物件執行個體。 如果將值配置或初始化的成本很高,應用程式可以使用物件集區。

在此版本中,我們會新增 IResettable 介面,使物件集區更容易使用。 重複使用的類型通常需要重設為每次使用之間的預設狀態。 將 IResettable 類型傳回物件集區時,會自動重設。

如需詳細資訊,請參閱 ObjectPool 範例

原生 AOT

已新增 .NET 原生預先 (AOT) 支援。 使用 AOT 發佈的應用程式可大幅提升效能:應用程式的大小更小、記憶體的使用量更少,以及啟動時間更快。 gRPC、基本 API 和背景工作角色服務應用程式目前支援原生 AOT。 如需詳細資訊,請參閱原生 AOT 的 ASP.NET Core 支援教學課程:使用原生 AOT 發佈 ASP.NET Core 應用程式。 如需 ASP.NET Core 與原生 AOT 相容性已知問題的相關資訊,請參閱 GitHub 問題 dotnet/core #8288

程式庫和原生 AOT

ASP.NET Core 專案中所使用的許多熱門程式庫,在以原生 AOT 為目標的專案中使用時,目前會有一些相容性問題,例如:

  • 使用反映來檢查及探索類型。
  • 有條件地在執行階段載入程式庫。
  • 即時產生程式碼以實作功能。

您必須更新使用這些動態功能的程式庫,才能使用原生 AOT。 您可以使用 Roslyn 來源產生器之類的工具來加以更新。

建議想要支援原生 AOT 的程式庫作者:

新增專案範本

新的 ASP.NET Core Web API (原生 AOT) 專案範本 (簡短名稱 webapiaot) 會建立已啟用 AOT 發佈的專案。 如需詳細資訊,請參閱 Web API (原生 AOT) 範本

新增 CreateSlimBuilder 方法

Web API (原生 AOT) 範本中使用的 CreateSlimBuilder() 方法會使用執行應用程式所需的最低 ASP.NET Core 功能來初始化 WebApplicationBuilderCreateSlimBuilder 方法包含下列功能,這些功能通常需要有效率的開發體驗:

  • appsettings.jsonappsettings.{EnvironmentName}.json 的 JSON 檔案組態。
  • 使用者祕密組態。
  • 主控台記錄。
  • 記錄設定。

如需詳細資訊,請參閱 CreateSlimBuilder 方法

新增 CreateEmptyBuilder 方法

有另一個新的 WebApplicationBuilder Factory 方法,可用來建置只包含必要功能的小型應用程式:WebApplication.CreateEmptyBuilder(WebApplicationOptions options)。 此 WebApplicationBuilder 是在沒有內建行為時所建立。 其所建置的應用程式只包含明確設定的服務與中介軟體。

以下是使用此 API 來建立小型 Web 應用程式的範例:

var builder = WebApplication.CreateEmptyBuilder(new WebApplicationOptions());
builder.WebHost.UseKestrelCore();

var app = builder.Build();

app.Use(async (context, next) =>
{
    await context.Response.WriteAsync("Hello, World!");
    await next(context);
});

Console.WriteLine("Running...");
app.Run();

在 linux-x64 電腦上使用 .NET 8 Preview 7 以原生 AOT 發佈此程式碼會導致約 8.5 MB 的獨立原生可執行檔。

使用可設定的 HTTPS 支援減少應用程式大小

針對不需要 HTTPS 或 HTTP/3 支援的應用程式,我們已進一步降低原生 AOT 二進位大小。 不使用 HTTPS 或 HTTP/3 適用於在 TLS 終止 Proxy 後方執行的應用程式 (例如裝載在 Azure 上)。 新的 WebApplication.CreateSlimBuilder 方法預設會省略這項功能。 您可以呼叫 builder.WebHost.UseKestrelHttpsConfiguration() (針對 HTTPS) 或 builder.WebHost.UseQuic() (針對 HTTP/3) 來加以新增。 如需詳細資訊,請參閱 CreateSlimBuilder 方法

JS編譯器所產生 IAsyncEnumerable<T> 類型的 ON 序列化

新功能已新增至 System.Text.Json,可更妥善地支援原生 AOT。 這些新功能會為 System.Text.Json 的來源產生模式新增功能,因為 AOT 不支援反映。

其中一項新功能支援 C# 編譯器所實作 JS 實作的 IAsyncEnumerable<T>ON 序列化。 此支援會在設定為發佈原生 AOT 的 ASP.NET Core 專案中開啟其使用。

此 API 適用於路由處理常式使用 yield return 來非同步傳回列舉的案例。 例如,若要具體化資料庫查詢中的資料列。 如需詳細資訊,請參閱 .NET 8 Preview 4 公告中的無法辨別類型支援

如需 System.Text.Json 來源產生中其他改善的相關資訊,請參閱 .NET 8 中的序列化改善

針對修剪警告標註的最上層 API

現在會標註無法可靠地與原生 AOT 搭配運作的子系統進入點。 從啟用原生 AOT 的應用程式呼叫這些方法時,系統會提供警告。 例如,下列程式碼會在叫用 AddControllers 時產生警告,因為此 API 不是安全修剪,且原生 AOT 並不支援。

Visual Studio 視窗,顯示關於 AddControllers 方法的 IL2026 警告訊息,訊息內容指出 MVC 目前不支援原生 AOT。

要求委派產生器

為了讓基本 API 與原生 AOT 相容,我們引進了要求委派產生器 (RDG)。 RDG 是一種來源產生器,會執行 RequestDelegateFactory (RDF) 的功能。 也就是說,其會將各種 MapGet()MapPost() 和與其類似的呼叫轉換成與指定路由相關聯的 RequestDelegate 執行個體。 但是,RDG 在啟動時不會在應用程式中的記憶體內執行,而是 RDG 會在編譯時間加以執行,並直接在專案中產生 C# 程式碼。 RDG:

  • 移除此程式碼的執行階段產生。
  • 確保 API 中使用的類型可由原生 AOT 工具鏈以靜態方式進行分析。
  • 確保不會將必要的程式碼修剪掉。

我們正在努力確保 RDG 盡可能支援最多的基本 API 功能,從而與原生 AOT 相容。

啟用以原生 AOT 發佈時,會自動在專案中啟用 RDG。 即使未使用原生 AOT,仍可在專案檔中設定 <EnableRequestDelegateGenerator>true</EnableRequestDelegateGenerator>,以手動方式啟用 RDG。 這在一開始評估專案的原生 AOT 整備程度,或在減少應用程式的啟動時間時很有用。

使用攔截器提升效能

要求委派產生器會使用新的 C# 12 攔截器編譯器功能,以支援在執行階段使用靜態產生變數來攔截對基本 API 對應方法的呼叫。 使用攔截器會導致以 PublishAot 編譯的應用程式啟動效能增加。

編譯時間所產生基本 API 中的記錄和例外狀況處理

在執行階段產生的基本 API 支援在參數繫結失敗時自動記錄 (或在開發環境中擲回例外狀況)。 .NET 8 引進了透過要求委派產生器 (RDG) 在編譯時間產生的相同 API 支援。 如需詳細資訊,請參閱編譯時間所產生基本 API 中的記錄和例外狀況處理

AOT 和 System.Text.Json

基本 API 已針對使用 System.Text.Json 接收及傳回 JSON 承載進行最佳化,因此也適用 JSON 和原生 AOT 的相容性需求。 原生 AOT 相容性需要使用 System.Text.Json 來源產生器。 所有接受為基本 API 中要求委派或從要求委派傳回參數的類型,都必須在透過 ASP.NET Core 相依性插入註冊的 JsonSerializerContext 上進行設定,例如:

// Register the JSON serializer context with DI
builder.Services.ConfigureHttpJsonOptions(options =>
{
    options.SerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonSerializerContext.Default);
});

...

// Add types used in the minimal API app to source generated JSON serializer content
[JsonSerializable(typeof(Todo[]))]
internal partial class AppJsonSerializerContext : JsonSerializerContext
{

}

如需關於 TypeInfoResolverChain API 的詳細資訊,請參閱下列資源:

程式庫和原生 AOT

許多適用於 ASP.NET Core 專案的通用程式庫,如今在以原生 AOT 為目標的專案中使用時,會有一些相容性問題。 熱門程式庫通常會仰賴 .NET 反映的動態功能來檢查及探索類型、在執行階段有條件地載入程式庫,以及即時產生程式碼以實作其功能。 您必須更新這些程式庫,才能使用 Roslyn 來源產生器之類的工具來使用原生 AOT。

對於想要深入了解如何準備原生 AOT 程式庫的程式庫作者,建議您從將其程式庫準備好進行修剪及深入了解原生 AOT 相容性需求開始。

Kestrel 和 HTTP.sys 伺服器

Kestrel 和 HTTP.sys 有數個新功能。

Kestrel 中具名管道的支援

具名管道是 Windows 應用程式之間建置內含式通訊 (IPC) 的熱門技術。 您現在可以使用 .NET、Kestrel 和具名管道來建置 IPC 伺服器。

var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
    serverOptions.ListenNamedPipe("MyPipeName");
});

如需此功能的詳細資訊,以及如何使用 .NET 和 gRPC 來建立 IPC 伺服器和用戶端,請參閱與 gRPC 的處理程序間通訊

具名管道傳輸的效能改善

我們已改善具名管道連線效能。 Kestrel 的具名管道傳輸現在會平行接受連線,並重複使用 NamedPipeServerStream 執行個體。

建立 100,000 個連線的時間:

  • 之前:5.916 秒
  • 之後:2.374 秒

macOS 上的 HTTP/2 over TLS (HTTPS) 支援 Kestrel

.NET 8 將 Application-Layer Protocol Negotiation (ALPN) 的支援新增至 macOS。 ALPN 是 TLS 功能,用來交涉連線將使用的 HTTP 通訊協定。 例如,ALPN 允許瀏覽器和其他 HTTP 用戶端要求 HTTP/2 連線。 此功能特別適用於需要 HTTP/2 的 gRPC 應用程式。 如需詳細資訊,請參閱搭配 ASP.NET Core Kestrel 網頁伺服器使用 HTTP/2

Kestrel 中的憑證檔案監看

reloadOnChange 傳遞至 KestrelServerOptions.Configure() 時,系統現在會監視透過路徑所設定的 TLS 憑證是否有變更。 憑證檔案變更的處理方式與所設定路徑的變更相同 (亦即會重新載入端點)。

請注意,由於檔案刪除是暫時性的,因此不會追蹤檔案刪除,如果檔案刪除不是暫時性的,則伺服器會損毀。

未使用指定 HTTP 通訊協定時的警告

如果 TLS 已停用,且 HTTP/1.x 可供使用,則即使已指定 HTTP/2 和 HTTP/3,也會加以停用。 這可能會造成一些令人討厭的意外,因此我們已新增警告輸出,在狀況發生時告知您。

HTTP_PORTSHTTPS_PORTS 組態金鑰

通常只會向應用程式和容器提供要接聽的連接埠 (例如 80),而沒有主機或路徑等其他條件約束。 HTTP_PORTSHTTPS_PORTS 是新的組態金鑰,允許指定 Kestrel 和 HTTP.sys 伺服器的接聽連接埠。 這些可能會使用 DOTNET_ASPNETCORE_ 環境變數前置詞進行定義,或直接透過任何其他組態輸入 (例如 appsettings.json) 進行指定。 每個都是以分號分隔的連接埠值清單。 例如:

ASPNETCORE_HTTP_PORTS=80;8080
ASPNETCORE_HTTPS_PORTS=443;8081

這是下列的速記,會指定配置 (HTTP 或 HTTPS) 和任何主機或 IP:

ASPNETCORE_URLS=http://*:80/;http://*:8080/;https://*:443/;https://*:8081/

如需詳細資訊,請參閱設定 ASP.NET Core Kestrel 網頁伺服器的端點ASP.NET Core 中的 HTTP.sys 網頁伺服器實作

ITlsHandshakeFeature 中的 SNI 主機名稱

伺服器名稱指示 (SNI) 主機名稱現在會在 ITlsHandshakeFeature 介面的 HostName 屬性中公開。

SNI 是 TLS 交握程序的一部分。 其可讓用戶端指定當伺服器裝載多個虛擬主機或網域時,他們嘗試連線的主機名稱。 若要在交握程序期間呈現正確的安全性憑證,伺服器必須知道針對每個要求選取的主機名稱。

主機名稱通常只會在 TLS 堆疊內處理,並用來選取相符的憑證。 但是將主機名稱公開,應用程式中的其他元件即可將該資訊用於如診斷、速率限制、路由和計費等目的。

公開主機名稱適用於管理數千個 SNI 繫結的大型服務。 這項功能可大幅提升客戶呈報期間的偵錯效率。 提高透明度可加速解決問題,並增強服務可靠性。

如需詳細資訊,請參閱 ITlsHandshakeFeature.HostName

IHttpSysRequestTimingFeature

IHttpSysRequestTimingFeature 在使用 HTTP.sys 伺服器使用 IIS 的內含式裝載時,會提供要求的詳細計時資訊:

IHttpSysRequestTimingFeature.TryGetTimestamp 會擷取所提供計時類型的時間戳記:

using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.HttpSys;
var builder = WebApplication.CreateBuilder(args);

builder.WebHost.UseHttpSys();

var app = builder.Build();

app.Use((context, next) =>
{
    var feature = context.Features.GetRequiredFeature<IHttpSysRequestTimingFeature>();

    var loggerFactory = context.RequestServices.GetRequiredService<ILoggerFactory>();
    var logger = loggerFactory.CreateLogger("Sample");

    var timingType = HttpSysRequestTimingType.RequestRoutingEnd;

    if (feature.TryGetTimestamp(timingType, out var timestamp))
    {
        logger.LogInformation("Timestamp {timingType}: {timestamp}",
                                          timingType, timestamp);
    }
    else
    {
        logger.LogInformation("Timestamp {timingType}: not available for the "
                                           + "current request",    timingType);
    }

    return next(context);
});

app.MapGet("/", () => Results.Ok());

app.Run();

如需詳細資訊,請參閱使用 IHttpSysRequestTimingFeature 取得詳細的計時資訊,以及使用 IIS 的計時資訊和內含式裝載

HTTP.sys:選擇加入核心模式回應緩衝

在某些情況下,具有高延遲的大量小型寫入可能會對 HTTP.sys 造成顯著的效能影響。 這項影響是因為 HTTP.sys 實作中缺少 Pipe 緩衝區。 為了改善這些案例中的效能,已將回應緩衝處理的支援新增至 HTTP.sys。 將 HttpSysOptions.EnableKernelResponseBuffering 設定為 true,以啟用緩衝處理。

回應緩衝處理應該由執行同步 I/O 或非同步 I/O 的應用程式啟用,且一次不超過一個未處理的寫入。 在這些案例中,回應緩衝可大幅改善高延遲連線的輸送量。

使用非同步 I/O 且一次可能有多個未完成寫入的應用程式應該使用此旗標。 啟用此旗標可能會導致 HTTP.Sys 的 CPU 和記憶體使用量較高。

驗證和授權

ASP.NET Core 8 會將新功能新增至驗證和授權。

Identity API 端點

MapIdentityApi<TUser> 是新的擴充方法,可新增兩個 API 端點 (/register/login)。 MapIdentityApi 的主要目標是讓開發人員輕鬆地在 JavaScript 型單頁應用程式 (SPA) 或 Blazor 應用程式中,使用 ASP.NET Core Identity 進行驗證。 MapIdentityApi 會新增更適合 SPA 應用程式和非瀏覽器應用程式的 JSON API 端點,而不是使用 ASP.NET Core Identity (以 Razor Pages 為基礎) 所提供的預設 UI。 如需詳細資訊,請參閱 Identity API 端點

IAuthorizationRequirementData

在 ASP.NET Core 8 之前,請將參數化授權原則新增至需要的端點,以實作:

  • AuthorizeAttribute (適用於每個原則)。
  • AuthorizationPolicyProvider 以處理字串型合約中的自訂原則。
  • AuthorizationRequirement (適用於原則)。
  • AuthorizationHandler (適用於每個需求)。

例如,請考慮下列針對 ASP.NET Core 7.0 撰寫的範例:

using AuthRequirementsData.Authorization;
using Microsoft.AspNetCore.Authorization;

var builder = WebApplication.CreateBuilder();

builder.Services.AddAuthentication().AddJwtBearer();
builder.Services.AddAuthorization();
builder.Services.AddControllers();
builder.Services.AddSingleton<IAuthorizationPolicyProvider, MinimumAgePolicyProvider>();
builder.Services.AddSingleton<IAuthorizationHandler, MinimumAgeAuthorizationHandler>();

var app = builder.Build();

app.MapControllers();

app.Run();
using Microsoft.AspNetCore.Mvc;

namespace AuthRequirementsData.Controllers;

[ApiController]
[Route("api/[controller]")]
public class GreetingsController : Controller
{
    [MinimumAgeAuthorize(16)]
    [HttpGet("hello")]
    public string Hello() => $"Hello {(HttpContext.User.Identity?.Name ?? "world")}!";
}
using Microsoft.AspNetCore.Authorization;
using System.Globalization;
using System.Security.Claims;

namespace AuthRequirementsData.Authorization;

class MinimumAgeAuthorizationHandler : AuthorizationHandler<MinimumAgeRequirement>
{
    private readonly ILogger<MinimumAgeAuthorizationHandler> _logger;

    public MinimumAgeAuthorizationHandler(ILogger<MinimumAgeAuthorizationHandler> logger)
    {
        _logger = logger;
    }

    // Check whether a given MinimumAgeRequirement is satisfied or not for a particular
    // context.
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
                                               MinimumAgeRequirement requirement)
    {
        // Log as a warning so that it's very clear in sample output which authorization
        // policies(and requirements/handlers) are in use.
        _logger.LogWarning("Evaluating authorization requirement for age >= {age}",
                                                                    requirement.Age);

        // Check the user's age
        var dateOfBirthClaim = context.User.FindFirst(c => c.Type ==
                                                                 ClaimTypes.DateOfBirth);
        if (dateOfBirthClaim != null)
        {
            // If the user has a date of birth claim, check their age
            var dateOfBirth = Convert.ToDateTime(dateOfBirthClaim.Value, CultureInfo.InvariantCulture);
            var age = DateTime.Now.Year - dateOfBirth.Year;
            if (dateOfBirth > DateTime.Now.AddYears(-age))
            {
                // Adjust age if the user hasn't had a birthday yet this year.
                age--;
            }

            // If the user meets the age criterion, mark the authorization requirement
            // succeeded.
            if (age >= requirement.Age)
            {
                _logger.LogInformation("Minimum age authorization requirement {age} satisfied",
                                         requirement.Age);
                context.Succeed(requirement);
            }
            else
            {
                _logger.LogInformation("Current user's DateOfBirth claim ({dateOfBirth})" +
                    " does not satisfy the minimum age authorization requirement {age}",
                    dateOfBirthClaim.Value,
                    requirement.Age);
            }
        }
        else
        {
            _logger.LogInformation("No DateOfBirth claim present");
        }

        return Task.CompletedTask;
    }
}

這裡有完整的範例,位於 AspNetCore.Docs.Samples 存放庫中。

ASP.NET Core 8 引進 IAuthorizationRequirementData 介面。 IAuthorizationRequirementData 介面可讓屬性定義指定與授權原則相關聯的需求。 使用 IAuthorizationRequirementData 時,可以使用較少的程式碼撰寫上述自訂授權原則程式碼。 更新的 Program.cs 檔案:

  using AuthRequirementsData.Authorization;
  using Microsoft.AspNetCore.Authorization;
  
  var builder = WebApplication.CreateBuilder();
  
  builder.Services.AddAuthentication().AddJwtBearer();
  builder.Services.AddAuthorization();
  builder.Services.AddControllers();
- builder.Services.AddSingleton<IAuthorizationPolicyProvider, MinimumAgePolicyProvider>();
  builder.Services.AddSingleton<IAuthorizationHandler, MinimumAgeAuthorizationHandler>();
  
  var app = builder.Build();
  
  app.MapControllers();
  
  app.Run();

更新的 MinimumAgeAuthorizationHandler

using Microsoft.AspNetCore.Authorization;
using System.Globalization;
using System.Security.Claims;

namespace AuthRequirementsData.Authorization;

- class MinimumAgeAuthorizationHandler : AuthorizationHandler<MinimumAgeRequirement>
+ class MinimumAgeAuthorizationHandler : AuthorizationHandler<MinimumAgeAuthorizeAttribute>
{
    private readonly ILogger<MinimumAgeAuthorizationHandler> _logger;

    public MinimumAgeAuthorizationHandler(ILogger<MinimumAgeAuthorizationHandler> logger)
    {
        _logger = logger;
    }

    // Check whether a given MinimumAgeRequirement is satisfied or not for a particular
    // context
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
-                                              MinimumAgeRequirement requirement)
+                                              MinimumAgeAuthorizeAttribute requirement)
    {
        // Remaining code omitted for brevity.

您可以在這裡找到完整的更新範例。

如需新範例的詳細檢查,請參閱使用 IAuthorizationRequirementData 的自訂授權原則

保護 Swagger UI 端點

現在可以在生產環境中呼叫 MapSwagger().RequireAuthorization 來保護 Swagger UI 端點。 如需詳細資訊,請參閱保護 Swagger UI 端點

其他

下列各節說明 ASP.NET Core 8 中的其他新功能。

相依性插入中的索引鍵服務支援

「索引鍵服務」是指使用索引鍵註冊和擷取相依性插入服務的機制。 服務會藉由呼叫 AddKeyedSingleton (或 AddKeyedScopedAddKeyedTransient) 進行註冊,以與索引鍵建立關聯。 藉由指定具有 [FromKeyedServices] 屬性的索引鍵來存取已註冊的服務。 下列程式碼示範如何使用索引鍵服務:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddKeyedSingleton<ICache, BigCache>("big");
builder.Services.AddKeyedSingleton<ICache, SmallCache>("small");
builder.Services.AddControllers();

var app = builder.Build();

app.MapGet("/big", ([FromKeyedServices("big")] ICache bigCache) => bigCache.Get("date"));
app.MapGet("/small", ([FromKeyedServices("small")] ICache smallCache) =>
                                                               smallCache.Get("date"));

app.MapControllers();

app.Run();

public interface ICache
{
    object Get(string key);
}
public class BigCache : ICache
{
    public object Get(string key) => $"Resolving {key} from big cache.";
}

public class SmallCache : ICache
{
    public object Get(string key) => $"Resolving {key} from small cache.";
}

[ApiController]
[Route("/cache")]
public class CustomServicesApiController : Controller
{
    [HttpGet("big-cache")]
    public ActionResult<object> GetOk([FromKeyedServices("big")] ICache cache)
    {
        return cache.Get("data-mvc");
    }
}

public class MyHub : Hub
{
    public void Method([FromKeyedServices("small")] ICache cache)
    {
        Console.WriteLine(cache.Get("signalr"));
    }
}

適用於具有 ASP.NET Core 後端的 SPA 應用程式的 Visual Studio 專案範本

Visual Studio 專案範本現在是建立具有 ASP.NET Core 後端的單頁應用程式 (SPA) 的建議方法。 會提供一些根據 JavaScript 架構 AngularReactVue 來建立應用程式的範本。 這些範本會:

  • 建立一個包含前端專案和後端專案的 Visual Studio 解決方案。
  • 使用 Visual Studio 的 JavaScript 和 TypeScript 專案類型 (.esproj) 來開發前端專案。
  • 使用 ASP.NET Core 專案來開發後端專案。

如需 Visual Studio 範本以及如何存取舊版範本的詳細資訊,請參閱 ASP.NET Core 中單一頁面應用程式 (SPA) 的概觀

支援泛型屬性

現在可在更簡潔的泛型變體中使用先前需要 Type 參數的屬性。 這可藉由支援 C# 11 中的泛型屬性來達成。 例如,標註動作回應類型的語法可以修改如下:

[ApiController]
[Route("api/[controller]")]
public class TodosController : Controller
{
  [HttpGet("/")]
- [ProducesResponseType(typeof(Todo), StatusCodes.Status200OK)]
+ [ProducesResponseType<Todo>(StatusCodes.Status200OK)]
  public Todo Get() => new Todo(1, "Write a sample", DateTime.Now, false);
}

下列屬性支援泛型變體:

  • [ProducesResponseType<T>]
  • [Produces<T>]
  • [MiddlewareFilter<T>]
  • [ModelBinder<T>]
  • [ModelMetadataType<T>]
  • [ServiceFilter<T>]
  • [TypeFilter<T>]

ASP.NET Core 應用程式中的程式碼分析

您可在 ASP.NET Core 8.0 中使用下表中顯示的新分析器。

診斷識別碼 中斷或不中斷 描述
ASP0016 不中斷 請勿從 RequestDelegate 傳回值
ASP0019 不中斷 建議使用 IHeaderDictionary.Append 或索引子
ASP0020 不中斷 路由參數所參考的複雜類型必須是可剖析的
ASP0021 不中斷 BindAsync 方法的傳回類型必須是 ValueTask<T>
ASP0022 不中斷 路由處理常式之間偵測到路由衝突
ASP0023 不中斷 MVC:路由處理常式之間偵測到路由衝突
ASP0024 不中斷 路由處理常式具有多個參數具有 [FromBody] 屬性
ASP0025 不中斷 使用 AddAuthorizationBuilder

路由工具

ASP.NET Core 是以路由為基礎而建置。 基本 API、Web API、Razor 頁面,以及 Blazor 全都使用路由來自訂 HTTP 要求對應至程式碼的方式。

在 .NET 8 中,我們已投資一套新功能,讓路由更容易學習和使用。 這些新功能包括:

如需詳細資訊,請參閱 .NET 8 中的路由工具

ASP.NET Core 計量

計量是一段時間回報的度量,最常用來監視應用程式的健康情況及產生警示。 例如,報告 HTTP 要求失敗的計數器可能會顯示在儀表板中,或在失敗通過閾值時產生警示。

此預覽會使用 System.Diagnostics.Metrics,在整個 ASP.NET Core 中新增新的計量。 Metrics 是用於報告及收集應用程式相關資訊的新式 API。

相較於現有的事件計數器,計量提供許多改善:

  • 具有計數器、量測計和長條圖的新類型度量。
  • 具有多維度值的強大報告。
  • 與 OpenTelemetry 標準一致,整合到更廣泛的雲端原生生態系統中。

已新增 ASP.NET Core 裝載、Kestrel 和 SignalR 的計量。 如需詳細資訊,請參閱 System.Diagnostics.Metrics

IExceptionHandler

IExceptionHandler 是一個新的介面,可讓開發人員回撥以處理中央位置的已知例外狀況。

IExceptionHandler 實作會呼叫 IServiceCollection.AddExceptionHandler<T> 來進行註冊。 您可以新增多個實作,並以已註冊的順序呼叫這些實作。 如果例外處理常式處理要求,其可能會傳回 true 以停止處理。 如果任何例外處理常式未處理例外狀況,則控制項會回復為中介軟體的預設行為和選項。

如需詳細資訊,請參閱 IExceptionHandler

改良的偵錯體驗

偵錯自訂屬性已新增至諸如 HttpContextHttpRequestHttpResponseClaimsPrincipalWebApplication 等類型。 這些類型的增強偵錯工具顯示可讓您在 IDE 偵錯工具中更輕鬆地尋找重要資訊。 下列螢幕擷取畫面顯示這些屬性在偵錯工具顯示 HttpContext 中的差異。

.NET 7:

.NET 7 中 HttpContext 類型的無用偵錯工具顯示。

.NET 8:

.NET 8 中 HttpContext 類型的有用偵錯工具顯示。

WebApplication 的偵錯工具顯示會醒目提示重要資訊,例如已設定的端點、中介軟體和 IConfiguration 值。

.NET 7:

.NET 7 中 WebApplication 類型的無用偵錯工具顯示。

.NET 8:

.NET 8 中 WebApplication 類型的有用偵錯工具顯示。

如需關於 .NET 8 中偵錯改善的詳細資訊,請參閱:

IPNetwork.ParseTryParse

IPNetwork 上新增的 ParseTryParse 方法,可使用 CIDR 標記法中的輸入字串或「斜線標記法」來建立 IPNetwork

以下是 IPv4 範例:

// Using Parse
var network = IPNetwork.Parse("192.168.0.1/32");
// Using TryParse
bool success = IPNetwork.TryParse("192.168.0.1/32", out var network);
// Constructor equivalent
var network = new IPNetwork(IPAddress.Parse("192.168.0.1"), 32);

以下是 IPv6 的範例:

// Using Parse
var network = IPNetwork.Parse("2001:db8:3c4d::1/128");
// Using TryParse
bool success = IPNetwork.TryParse("2001:db8:3c4d::1/128", out var network);
// Constructor equivalent
var network = new IPNetwork(IPAddress.Parse("2001:db8:3c4d::1"), 128);

Redis 型輸出快取

ASP.NET Core 8 新增使用 Redis 做為輸出快取分散式快取的支援。 輸出快取這項功能可讓應用程式快取基本 API 端點、控制器動作或 Razor 頁面的輸出。 如需詳細資訊,請參閱輸出快取

路由之後尋找中介軟體的最短路徑

當路由符合端點時,通常會讓其餘中介軟體管線在叫用端點邏輯之前執行。 服務可以篩選出管線早期已知的要求來減少資源使用量。 使用 ShortCircuit 擴充方法可讓路由立即叫用端點邏輯,然後結束要求。 例如,指定的路由可能不需要通過驗證或 CORS 中介軟體。 下列範例會尋找符合 /short-circuit 路由要求的最短路徑:

app.MapGet("/short-circuit", () => "Short circuiting!").ShortCircuit();

使用 MapShortCircuit 方法,將 URL 前置詞的參數陣列傳遞給多個路由,以一次設定多個路由的最短路徑。 例如,瀏覽器和 Bot 通常會探查伺服器的已知路徑,例如 robots.txtfavicon.ico。 如果應用程式沒有這些檔案,則一行程式碼即可設定這兩個路由:

app.MapShortCircuit(404, "robots.txt", "favicon.ico");

如需詳細資訊,請參閱路由之後尋找中介軟體的最短路徑

HTTP 記錄中介軟體擴充性

HTTP 記錄中介軟體有數個新功能:

  • HttpLoggingFields.Duration:啟用時,中介軟體會在要求和回應結束時發出新的記錄,以測量處理所需的時間總計。 這個新欄位已新增至 HttpLoggingFields.All 集合。
  • HttpLoggingOptions.CombineLogs:啟用時,中介軟體會將所有已啟用要求和回應的記錄合併到最後的一個記錄。 單一記錄訊息包括要求、要求本文、回應、回應本文和持續時間。
  • IHttpLoggingInterceptor:可實作和註冊 (使用 AddHttpLoggingInterceptor) 服務的新介面,以接收個別要求和個別回應回撥,以自訂要記錄哪些詳細資料。 任何端點專屬的記錄設定都會先套用,然後可以在這些回呼中加以覆寫。 實作可以:
    • 檢查要求和回應。
    • 啟用或停用任何 HttpLoggingFields
    • 調整要記錄多少要求或回應本文。
    • 在記錄中新增自訂欄位。

如需詳細資料,請參閱 .NET Core 與 ASP.NET Core 中的 HTTP 記錄

ProblemDetails 中的新 API,以支援更具復原性的整合

在 .NET 7 中,引進了 ProblemDetails 服務,以改善產生符合 ProblemDetails 規格的錯誤回應體驗。 在 .NET 8 中,新增了新的 API,讓您可更輕鬆地在 IProblemDetailsService 無法產生 ProblemDetails 時實作後援行為。 下列範例將示範如何使用新的 TryWriteAsync API:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddProblemDetails();

var app = builder.Build();

app.UseExceptionHandler(exceptionHandlerApp =>
{
    exceptionHandlerApp.Run(async httpContext =>
    {
        var pds = httpContext.RequestServices.GetService<IProblemDetailsService>();
        if (pds == null
            || !await pds.TryWriteAsync(new() { HttpContext = httpContext }))
        {
            // Fallback behavior
            await httpContext.Response.WriteAsync("Fallback: An error occurred.");
        }
    });
});

app.MapGet("/exception", () =>
{
    throw new InvalidOperationException("Sample Exception");
});

app.MapGet("/", () => "Test by calling /exception");

app.Run();

如需詳細資訊,請參閱 IProblemDetailsService 後援

其他資源