ASP.NET Core 8.0 の新機能

この記事では、ASP.NET Core 8.0 の最も大きな変更点について説明します。また、関連するドキュメントへのリンクも示します。

Blazor

フル スタック Web UI

.NET 8 のリリースでは、Blazor は、コンポーネント レベルまたはページ レベルでコンテンツをレンダリングするアプリを開発するためのフルスタック Web UI フレームワークとなっており、次の機能が備わっています。

  • サーバー上で静的 HTML を生成する静的サーバー レンダリング ("静的サーバー側レンダリング" または静的 SSR とも呼ばれます)。
  • サーバー上でプリレンダリングを使って対話型コンポーネントを生成する対話型サーバー レンダリング ("対話型サーバー側レンダリング" または対話型 SSR とも呼ばれます)。
  • サーバーでのプリレンダリングを使ってクライアント上で対話型コンポーネントを生成する対話型 WebAssembly レンダリング ("クライアント側レンダリング" または CSR とも呼ばれ、常に対話型と見なされます)。
  • コンテンツのレンダリングと対話機能に対してサーバー側の ASP.NET Core ランタイムを最初に使う対話型自動レンダリング。 Blazor バンドルがダウンロードされて WebAssembly ランタイムがアクティブになった後、それ以降のレンダリングと対話機能には、クライアント上の .NET WebAssembly ランタイムが使われます。 対話型自動レンダリングでは、通常、最も速いアプリ起動エクスペリエンスが提供されます。

また、対話型レンダリング モードでは、既定でコンテンツがプリレンダリングされます。

詳細については、次の記事を参照してください。

Blazor ドキュメント全体の例は、Blazor Web アプリでの使用に関するものに更新されています。 Blazor Server の例は、.NET 7 以前のバージョンのコンテンツに残っています。

静的サーバー側レンダリング (静的 SSR) でのクラス ライブラリに関する新しい記事

静的サーバー側レンダリング (静的 SSR) の場合の Razor クラス ライブラリ (RCL) でのコンポーネント ライブラリの作成について説明する新しい記事が追加されました。

詳しくは、「ASP.NET Core の Razor クラス ライブラリ (RCL) と静的サーバー側レンダリング (静的 SSR)」をご覧ください。

HTTP キャッシュの問題に関する新しい記事

メジャー バージョン間で Blazor アプリをアップグレードするときに発生する可能性がある HTTP キャッシュに関する一般的な問題と、HTTP キャッシュの問題に対処する方法について説明する新しい記事が追加されました。

詳しくは、「ASP.NET Core Blazor アプリをアップグレードするときに HTTP キャッシュの問題を回避する」をご覧ください。

新しい Blazor Web アプリ テンプレート

Blazor Web App テンプレートという、新しい Blazor プロジェクト テンプレートが導入されました。 新しいテンプレートでは、Blazor コンポーネントを使って任意のスタイルの Web UI を構築するための一つの出発点が提供されます。 このテンプレートにより、既存の Blazor Server および Blazor WebAssembly ホスティング モデルの長所と、.NET 8 で新しく追加された Blazor の機能 (静的サーバー側レンダリング (静的 SSR)、ストリーミング レンダリング、ナビゲーションとフォーム処理の強化、コンポーネントごとに Blazor Server または Blazor WebAssembly を使ってインタラクティビティを追加する機能) が組み合わされます。

.NET 8 でさまざまな Blazor ホスティング モデルを 1 つのモデルに統合する取り組みの一環として、Blazor プロジェクト テンプレートの数も統合されています。 Blazor Server テンプレートが削除され、Blazor WebAssembly テンプレートから ASP.NET Core Hosted オプションが削除されました。 どちらのシナリオも、Blazor Web アプリ テンプレートを使うときのオプションによって表されます。

Note

既存の Blazor Server アプリと Blazor WebAssembly アプリは、.NET 8 でも引き続きサポートされます。 必要に応じて、新しいフルスタック Web UI Blazor 機能を使うようにこれらのアプリを更新できます。

新しい Blazor Web アプリ テンプレートについて詳しくは、次の記事を参照してください。

Blazor Web アプリ用の新しい JS 初期化子

Blazor Server、Blazor WebAssembly、および Blazor Hybrid アプリの場合:

  • beforeStart は、読み込みプロセス、ログ レベル、その他のオプションのカスタマイズなどのタスクに使われます。
  • afterStarted は、Blazor イベント リスナーやカスタム イベントの種類の登録などのタスクに使われます。

以前のレガシ JS 初期化子は、Blazor Web アプリにおいては既定では呼び出されません。 Blazor Web アプリでは、次の新しい JS 初期化子のセットが使われます: beforeWebStartafterWebStartedbeforeServerStartafterServerStartedbeforeWebAssemblyStartafterWebAssemblyStarted

詳しくは、「ASP.NET Core Blazor の起動」をご覧ください。

プリレンダリングと統合のガイダンスの分割

.NET の以前のリリースでは、プリレンダリングと統合のことを 1 つの記事で説明していました。 簡潔にし、対象を絞るため、.NET 8 に関する更新では次の新しい記事にテーマを分けました。

Blazor Web アプリでコンポーネントの状態を保持する

既存の PersistentComponentState サービスを使用して、Blazor Web アプリでコンポーネントの状態を保持および読み取ることができます。 これは、プリレンダリング中にコンポーネントの状態を保持するのに役立ちます。

Blazor Web アプリでは、プリレンダリング中に作成される登録済みのアプリ レベルの状態が自動的に保持されるので、コンポーネントの状態保持タグ ヘルパーは必要はありません。

フォーム処理とモデル バインド

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 スクリプト (blazor.web.js) が読み込まれるときに既定で有効になります。 強化されたフォーム処理は、必要に応じて特定のフォームに対して有効にできます。

新しい拡張ナビゲーション API を使用すると、 NavigationManager.Refresh(bool forceLoad = false)を呼び出して現在のページを更新できます。

詳しくは、Blazor の "ルーティング" に関する記事の次のセクションをご覧ください。

JS 相互運用のための強化されたナビゲーションでの静的レンダリングに関する新しい記事

一部のアプリは、JS 相互運用に依存して、各ページに固有の初期化タスクを実行します。 JS 相互運用の初期化タスクを実行する静的にレンダリングされたページで Blazor の強化されたナビゲーション機能を使うと、ページ固有の JS が、強化されたページ ナビゲーションが発生するたびに予期したとおりに再度実行されないことがあります。 新しい記事では、Blazor Web アプリでこのシナリオに対処する方法が説明されています。

ASP.NET Core Blazor JavaScript と静的サーバー側レンダリング (静的 SSR)

ストリーミング レンダリング

Blazor で静的サーバー側レンダリング (静的 SSR) を使うときに、応答ストリームでコンテンツの更新をストリーミングできるようになりました。 ストリーミング レンダリングでは、完全にレンダリングするために長時間の非同期タスクを実行するページのユーザー エクスペリエンスを、コンテンツをレンダリング可能になり次第レンダリングすることで改善できます。

たとえば、ページをレンダリングするために、実行時間の長いデータベース クエリや 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 の新しい SectionOutlet および SectionContent コンポーネントにより、後で入力できるコンテンツのアウトレットを指定するためのサポートが追加されます。 セクションは、多くの場合、後で特定のページで入力されるレイアウトのプレースホルダーを定義するために使われます。 セクションは、一意の名前または一意のオブジェクト ID を使って参照されます。

詳しくは、「ASP.NET Core Blazor セクション」を参照してください。

エラー ページのサポート

Blazor Web アプリでは、ASP.NET Core 例外処理ミドルウェアで使用するカスタム エラー ページを定義できます。 Blazor Web アプリ プロジェクト テンプレートには、既定のエラー ページ (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 が 0 の場合に、Virtualize コンポーネントの新しい EmptyContent パラメーターを使ってコンテンツを指定できます。

詳しくは、「ASP.NET Core Razor コンポーネントの仮想化」をご覧ください。

対話型サーバー コンポーネントが残っていない場合に回線を閉じる

対話型サーバー コンポーネントでは、回線と呼ばれるブラウザーとのリアルタイム接続を使用して Web UI イベントが処理されます。 ルート対話型サーバー コンポーネントがレンダリングされるときに、回線とそれに関連付けられている状態が設定されます。 ページ上に対話型サーバー コンポーネントが残っていない場合、その回線は閉じて、サーバー リソースを解放します。

SignalR 回線アクティビティを監視する

CircuitHandler の新しい CreateInboundActivityHandler メソッドを使って、サーバー側アプリの受信回線アクティビティを監視できるようになりました。 受信回線アクティビティとは、UI イベントや JavaScript から .NET への相互運用呼び出しなど、ブラウザーからサーバーに送信されるすべてのアクティビティです。

詳しくは、ASP.NET Core BlazorSignalR ガイダンスを参照してください。

Jiterpreter によるランタイム パフォーマンスの向上

Jiterpreter は、.NET 8 の新しいランタイム機能です。これにより、WebAssembly で実行するときに部分的な Just-In-Time (JIT) コンパイルがサポートされ、ランタイム パフォーマンスが向上します。

詳しくは、「ASP.NET Core Blazor WebAssembly のホストと展開」をご覧ください。

Ahead-Of-Time (AOT) SIMD と例外処理

Blazor WebAssembly の Ahead-Of-Time (AOT) コンパイルでは、既定で WebAssembly 固定幅 SIMDWebAssembly 例外処理が使われるようになり、ランタイム パフォーマンスが向上します。

詳細については、次の記事を参照してください。

Web 対応 Webcil パッケージ

Webcil は、.NET アセンブリの Web 対応パッケージです。ネイティブ Windows 実行に固有のコンテンツを削除し、.dll ファイルのダウンロードや使用がブロックされる環境に展開する際の問題を回避します。 Webcil は Blazor WebAssembly アプリに対して既定で有効になっています。

詳しくは、「ASP.NET Core Blazor WebAssembly のホストと展開」をご覧ください。

Note

.NET 8 のリリースより前は、「ASP.NET Core でホストされる Blazor WebAssembly アプリの展開レイアウト」のガイダンスにおいて、マルチパート バンドル アプローチでクライアントによる DLL のダウンロードと実行をブロックする環境が対処されています。 .NET 8 以降では、Blazor は Webcil ファイル形式を使用してこの問題に対処します。 "WebAssembly の展開レイアウト" の記事で説明されている実験的な NuGet パッケージを使用したマルチパート バンドルは、.NET 8 以降の Blazor アプリではサポートされていません。 詳しくは、「カスタム バンドル形式を定義するように Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle パッケージを拡張する (dotnet/aspnetcore #36978)」をご覧ください。 .NET 8 以降のアプリでマルチパート バンドル パッケージを引き続き使いたい場合は、その記事のガイダンスを使って独自にマルチパート バンドルの NuGet パッケージを作成できますが、Microsoft ではそれはサポートされません。

Blazor WebAssembly のデバッグの機能強化

.NET on WebAssembly をデバッグするときに、デバッガーは Visual Studio のユーザー設定で構成されているシンボルの場所からシンボル データをダウンロードするようになりました。 これにより、NuGet パッケージを使うアプリのデバッグ エクスペリエンスが向上します。

Firefox を使って Blazor WebAssembly アプリをデバッグできるようになりました。 Blazor WebAssembly アプリをデバッグするには、リモート デバッグ用にブラウザーを構成してから、.NET WebAssembly デバッグ プロキシを介してブラウザー開発者ツールを使ってブラウザーに接続する必要があります。 現在のところ、Visual Studio からの Firefox のデバッグはサポートされていません。

詳細については、「ASP.NET Core Blazor アプリをデバッグする」を参照してください。

コンテンツ セキュリティ ポリシー (CSP) の互換性

Blazor WebAssembly では、コンテンツ セキュリティ ポリシー (CSP) を指定するときに、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 に依存しなくなりました。

dialog の cancel および close イベントのサポート

Blazor では、dialog HTML 要素の cancelclose イベントがサポートされるようになりました。

次に例を示します。

  • OnClose は、[閉じる] ボタンを使用して my-dialog ダイアログを閉じるときに呼び出されます。
  • OnCancel は、Esc キーを使用してダイアログが取り消されたときに呼び出されます。 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 アプリの新しいプロジェクト ダイアログで [個別のアカウント] のオプションを選ぶか、新しいプロジェクトを作成するときにコマンド ラインから 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 以前の既定値の 2 倍の値の代入を示しています。

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

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

JavaScript クライアントの新しいアプローチ

次の例は、ASP.NET Core 8.0 以降の既定値の 2 倍の値を代入する "新しいアプローチ" を示しています。

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

Blazor Server アプリの JavaScript クライアントの以前のアプローチ

次の例は、ASP.NET Core 7.0 以前の既定値の 2 倍の値の代入を示しています。

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 以降で既定値の 2 倍の値を代入する "新しいアプローチ" を示しています。

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 以前の既定値の 2 倍の値の代入を示しています。

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 以降の既定値の 2 倍の値を代入する "新しいアプローチ" を示しています。

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 の新機能について説明します。 最小 API について詳しくは、Native AOT に関するセクションも参照してください。

ユーザー オーバーライド カルチャ

ASP.NET Core 8.0 以降では、RequestLocalizationOptions.CultureInfoUseUserOverride プロパティを使用すると、CultureInfoDateTimeFormat プロパティと NumberFormat プロパティに既定以外の Windows 設定を使用するかどうかがアプリによって判断されます。 これは、Linux には影響しません。 これは UseUserOverrideに直接対応します。

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

フォームへのバインド

[FromForm] 属性を使用したフォーム値への明示的なバインドがサポートされるようになりました。 [FromForm] を使用して要求にバインドされたパラメーターには、偽造防止トークンが含まれます。 偽造防止トークンは、要求が処理されるときに検証されます。

IFormCollectionIFormFile、および IFormFileCollection 型を使用したフォームへの推定バインディングもサポートされています。 Swagger UI との統合をサポートするために、フォーム パラメーターに対して OpenAPI メタデータが推論されます。

詳細については次を参照してください:

フォームからのバインドは、次のものでサポートされるようになりました。

  • コレクション (例: ListDictionary など)
  • 複合型 (例: Todo または Project など)

詳細については、「フォームからコレクションと複合型にバインドする」を参照してください。

最小限の API を使用した偽造防止

このリリースでは、クロスサイト リクエスト フォージェリ攻撃を軽減するために使用される偽造防止トークンを検証するためのミドルウェアが追加されました。 AddAntiforgery を呼び出して、DI に偽造防止サービスを登録します。 WebApplicationBuilder では、DI コンテナーに偽造防止サービスが登録されている場合に、ミドルウェアが自動的に追加されます。 偽造防止トークンは、クロスサイト 要求 フォージェリ攻撃 を軽減するために使用されます。

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 ネイティブ Ahead-Of-Time (AOT) のサポートが追加されました。 AOT を使用して公開されるアプリは、アプリのサイズが小さくなり、メモリの使用量が減り、起動時間が短縮されるため、パフォーマンスが大幅に向上します。 ネイティブ AOT は現在、gRPC、Minimal API、worker サービス アプリでサポートされています。 詳細については、「Native AOT の ASP.NET Core サポート」と「チュートリアル: ASP.NET Core アプリを Native AOT を使用して発行する」を参照してください。 ASP.NET Core と Native AOT の互換性に関する既知の問題については、GitHub issue dotnet/core #8288 を参照してください。

ライブラリと Native AOT

現在、ASP.NET Core プロジェクトで使用される一般的なライブラリの多くは、ネイティブ AOT をターゲットとするプロジェクトで使われる場合に次のような互換性の問題があります。

  • リフレクションの利用により、型が検査して検出される。
  • 実行時にライブラリが条件付きで読み込まれる。
  • 機能を実装するためのコードがすぐに生成される。

ネイティブ AOT を使用するには、これらの動的機能を使用するライブラリを更新する必要があります。 Roslyn ソース ジェネレーターなどのツールを使用して更新できます。

ネイティブ AOT のサポートを希望するライブラリ作成者には、次のことをおすすめします。

新しいプロジェクト テンプレート

新しい ASP.NET Core Web API (Native AOT) プロジェクト テンプレート (短縮名 webapiaot) では、AOT 発行が有効になっているプロジェクトが作成されます。 詳細については、「Web API (Native AOT) テンプレート」を参照してください。

新しい CreateSlimBuilder メソッド

Web API (Native AOT) テンプレートで使用される CreateSlimBuilder() メソッドは、アプリの実行に必要な最小限の ASP.NET Core 機能を使用して WebApplicationBuilder を初期化します。 CreateSlimBuilder メソッドには、効率的な開発エクスペリエンスに通常必要な次の機能が含まれています。

  • appsettings.jsonappsettings.{EnvironmentName}.json の JSON ファイルの構成。
  • ユーザー シークレットの構成。
  • コンソールのログ。
  • ログの構成。

詳細については、「CreateSlimBuilder メソッド」を参照してください。

新しい CreateEmptyBuilder メソッド

必要な機能のみを含む小さなアプリを構築するための、新しいもう 1 つの WebApplicationBuilder ファクトリ メソッドがあります (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 を使用して Native AOT でこのコードを発行すると、約 8.5 MB の自己完結型ネイティブ実行可能ファイルが作成されます。

構成可能な HTTPS サポートによるアプリ サイズの縮小

HTTPS または HTTP/3 のサポートが必要ないアプリの Native AOT バイナリのサイズがさらに縮小されました。 HTTPS または HTTP/3 の不使用は、TLS 終端プロキシの背後で実行されるアプリでは一般的です (Azure でホストされている場合など)。 新しい WebApplication.CreateSlimBuilder メソッドでは、既定でこの機能が省略されます。 追加するには、builder.WebHost.UseKestrelHttpsConfiguration() (HTTPS) または builder.WebHost.UseQuic() (HTTP/3) を呼び出します。 詳細については、「CreateSlimBuilder メソッド」を参照してください。

コンパイラによって生成された IAsyncEnumerable<T> 型の JSON シリアル化

Native AOT のサポートを充実させるために、System.Text.Json に新機能が追加されました。 AOT ではリフレクションがサポートされていないため、当該新機能によって、System.Text.Json のソース生成モード用の機能が追加されます。

この新機能の 1 つは、C# コンパイラによって実装される IAsyncEnumerable<T> 実装の JSON シリアル化をサポートすることです。 このサポートにより、Native AOT を発行するように構成された ASP.NET Core プロジェクト内での使用が可能になります。

この API は、ルート ハンドラーで yield return を使用して列挙型を非同期的に返すというシナリオで役立ちます。 たとえば、データベース クエリからの行を具体化する場合です。 詳細については、.NET 8 Preview 4 のお知らせにある「speakable でない型のサポート」を参照してください。

System.Text.Json ソース生成でのその他の機能強化については、.NET 8 でのシリアル化の機能強化に関するページを参照してください。

トリミングの警告の注釈が付けられる最上位の API

Native AOT での動作が不安定であるサブシステムへのメイン エントリ ポイントに注釈が付けられるようになりました。 Native AOT が有効になっているアプリケーションからこれらのメソッドが呼び出されると、警告が表示されます。 たとえば、次のコードを実行すると、AddControllers の呼び出し時に警告が生成されます。この API はトリミング セーフではなく、Native AOT でサポートされていないからです。

AddControllers メソッドに対して、現在、MVC で Native AOT がサポートされていないことを示す IL2026 警告メッセージが表示されている Visual Studio ウィンドウ。

要求デリゲート ジェネレーター

Minimal API を Native AOT と互換性があるものにするために、Request Delegate Generator (RDG) を導入しています。 RDG は、RequestDelegateFactory (RDF) の動作を行うソース ジェネレーターです。 つまり、さまざまな MapGet()MapPost() などの呼び出しを、指定されたルートに関連付けられている RequestDelegate インスタンスに変換します。 しかし、起動時にアプリケーションでメモリ内で実行するのではなく、RDG ではコンパイル時にそれを実行し、C# コードをプロジェクトに直接生成します。 RDG では、次のことが行われます。

  • このコードのランタイム生成が削除されます。
  • API で使用される型を確実に Native AOT ツール チェーンで静的に分析できるようにします。
  • 必要なコードが決してトリミングされないようにします。

私たちは、できるだけ多くの Minimal API 機能が RDG でサポートされ、Native AOT と互換性があるようにするために取り組んでいます。

Native AOT を使用する発行が有効になっている場合、RDG はプロジェクトで自動的に有効になります。 プロジェクト ファイルで <EnableRequestDelegateGenerator>true</EnableRequestDelegateGenerator> を設定することで、Native AOT を使用しない場合でも、RDG を手動で有効にすることができます。 これは、Native AOT に対するプロジェクトの準備状況を最初に評価するときや、アプリの起動時間を短縮するために便利な場合があります。

インターセプターを使用したパフォーマンスの向上

要求デリゲート ジェネレーターは、新しい C# 12 のインターセプター コンパイラ機能を使って、実行時に静的に生成されるバリアントを用いた Minimal API Map メソッドの呼び出しのインターセプトをサポートします。 インターセプターを使用すると、PublishAot でコンパイルされたアプリの起動パフォーマンスが向上します。

コンパイル時に生成された最小 API でのログと例外処理

実行時に生成された最小 API では、パラメーター バインドが失敗したときの自動ログ (または開発環境での例外のスロー) がサポートされます。 .NET 8 では、Request Delegate Generator (RDG) を介して、コンパイル時に生成された API に対して同じサポートが導入されています。 詳しくは、「コンパイル時に生成された最小 API でのログと例外処理」を参照してください。

AOT と System.Text.Json

Minimal API は、System.Text.Json を使用して JSON ペイロードを受信して返すように最適化されているため、JSON と Native 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 について詳しくは、次のリソースを参照してください。

ライブラリと Native AOT

現在、ASP.NET Core プロジェクトで使用できる一般的なライブラリの多くは、Native AOT をターゲットとするプロジェクトで使われる場合に互換性の問題がいくつかあります。 一般的なライブラリでは、多くの場合、.NET リフレクションの動的機能に依存して型を検査および検出し、実行時にライブラリを条件付きで読み込み、その機能を実装するコードをすぐに生成します。 Roslyn ソース ジェネレーターなどのツールを使用して Native AOT を操作するには、これらのライブラリを更新する必要があります。

Native AOT 用にライブラリを準備する方法についてさらに学習したいライブラリ作成者には、まず、トリミング用のライブラリを準備し、Native 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 秒

Kestrel での macOS の HTTP/2 over TLS (HTTPS) のサポート

.NET 8 では、macOS に対するアプリケーション レイヤー プロトコル ネゴシエーション (ALPN) のサポートが追加されています。 ALPN は、接続時にどの HTTP プロトコルを使用するかをネゴシエートするために使用される TLS 機能です。 たとえば、ALPN を使用すると、ブラウザーやその他の HTTP クライアントで HTTP/2 接続を要求できます。 この機能は、HTTP/2 を必要とする gRPC アプリで特に役立ちます。 詳細については、「ASP.NET Core Kestrel Web サーバーで HTTP/2 を使用する」を参照してください。

Kestrel での証明書ファイルの監視

パスで構成された TLS 証明書は、reloadOnChangeKestrelServerOptions.Configure() に渡されたときに変更が監視されるようになりました。 証明書ファイルに対する変更は、構成されたパスに対する変更と同じように扱われます (つまり、エンドポイントが再読み込みされます)。

ファイルの削除は一時的に発生し、一時的でない場合はサーバーがクラッシュするため、特に追跡されないことに注意してください。

指定された HTTP プロトコルが使用されない場合の警告

TLS が無効で、HTTP/1.x が使用可能な場合、HTTP/2 と HTTP/3 は、指定されている場合でも無効になります。 これによって予期しないことが発生する可能性があるため、発生時に通知するために警告出力を追加しました。

HTTP_PORTS および HTTPS_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 Web サーバーのエンドポイントを構成する」および「ASP.NET Core での HTTP.sys Web サーバーの実装」を参照してください。

ITlsHandshakeFeature の SNI ホスト名

Server Name Indication (SNI) ホスト名が、ITlsHandshakeFeature インターフェイスの HostName プロパティで公開されるようになりました。

SNI は TLS ハンドシェイク プロセスの一部です。 これにより、サーバーが複数の仮想ホストまたはドメインをホストしている場合に、クライアントが接続しようとしているホスト名を指定できます。 ハンドシェイク プロセス中に正しいセキュリティ証明書を提示するには、サーバーが要求ごとに選択されたホスト名を認識している必要があります。

通常、ホスト名は TLS スタック内でのみ処理され、一致する証明書を選択するために使用されます。 しかし、それを公開することで、アプリ内の他のコンポーネントは、診断、レート制限、ルーティング、課金などの目的でその情報を使用できます。

ホスト名を公開することは、何千もの SNI バインディングを管理する大規模なサービスにとって有用です。 この機能は、顧客エスカレーション時のデバッグ効率を大幅に向上させることができます。 透明性の向上により、問題解決の高速化とサービスの信頼性の向上が可能になります。

詳細については、ITlsHandshakeFeature.HostName を確認してください。

IHttpSysRequestTimingFeature

IHttpSysRequestTimingFeature では、HTTP.sys サーバーと、IIS を使用したインプロセス ホスティングを使う場合の要求の詳細なタイミング情報が提供されます。

  • タイムスタンプは、QueryPerformanceCounter を使用して取得されます。
  • タイムスタンプの頻度は、QueryPerformanceFrequency を使用して取得できます。
  • タイミングのインデックスを HttpSysRequestTimingType にキャストして、タイミングが何を表しているのかを把握できます。
  • タイミングを現在の要求に利用できない場合、値は 0 になることがあります。

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.EnableKernelResponseBufferingtrue に設定して、バッファリングを有効にします。

応答バッファリングは、同期 I/O を実行するアプリで、または非同期 I/O で未処理の書き込みを一度に 1 つしか実行しないアプリで有効にする必要があります。 これらのシナリオでは、応答バッファリングにより、待機時間の長い接続に対してスループットが大幅に向上する場合があります。

非同期 I/O を使うアプリや、未処理の書き込みを一度に複数実行する場合があるアプリでは、このフラグを使用しないでください このフラグを有効にすると、HTTP.Sys による CPU とメモリの使用率が高くなる可能性があります。

認証と承認

ASP.NET Core 8 では、認証と認可に新しい機能が追加されます。

Identity API エンドポイント

MapIdentityApi<TUser> は、2 つの API エンドポイント (/register/login) を追加する新しい拡張メソッドです。 MapIdentityApi の主な目標は、開発者が JavaScript ベースのシングル ページ アプリ (SPA) または Blazor アプリでの認証に ASP.NET Core Identity を簡単に使用できるようにすることです。 Razor Pages に基づき ASP.NET Core Identity によって提供される既定の UI を使う代わりに、MapIdentityApi では、SPA アプリとブラウザー以外のアプリにより適した JSON API エンドポイントが追加されます。 詳しくは、「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 のその他の新機能について説明します。

依存関係の挿入でのキー付きサービスのサポート

キー付きサービスとは、キーを使用して依存関係の挿入 (DI) サービスを登録および取得する仕組みのことです。 サービスは、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 ソリューションを作成します。
  • JavaScript には Visual Studio プロジェクトの種類を使用し、フロントエンドには 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 で使用できます。

診断 ID 破壊的または非破壊的 説明
ASP0016 非破壊的 RequestDelegate から値を返さない
ASP0019 非破壊的 IHeaderDictionary.Append またはインデクサーの使用を提案する
ASP0020 非破壊的 ルート パラメーターによって参照される複合型は解析可能である必要がある
ASP0021 非破壊的 BindAsync メソッドの戻り値の型は ValueTask<T> である必要がある
ASP0022 非破壊的 ルート ハンドラー間で検出されたルートの競合
ASP0023 非破壊的 MVC: ルート ハンドラー間で検出されたルートの競合
ASP0024 非破壊的 ルート ハンドラーには [FromBody] 属性を持つ複数のパラメーターがある
ASP0025 非破壊的 AddAuthorizationBuilder を使用する

ルート ツール

ASP.NET Core はルーティングに基づいています。 最小 API、Web API、Razor Pages、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.Parse および TryParse

IPNetwork の新しい Parse メソッドと TryParse メソッドに、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 Page の出力をキャッシュできるようにする機能です。 詳細については、「出力キャッシュ」を参照してください。

ルーティング後のミドルウェアのショートサーキット

ルーティングがエンドポイントと一致する場合、通常は、エンドポイントのロジックを呼び出す前にミドルウェア パイプラインの残りの部分を実行できます。 サービスでは、パイプラインの早い段階で既知の要求を除外することで、リソースの使用量を削減できます。 ShortCircuit 拡張メソッドを使って、ルーティングですぐにエンドポイントのロジックを呼び出した後、要求を終了するようにします。 たとえば、ある特定のルートでは認証や CORS ミドルウェアを経由する必要がない場合があります。 次の例では、/short-circuit ルートに一致する要求をショートサーキットします。

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

MapShortCircuit メソッドを使って、URL プレフィックスの params 配列を渡すことで、複数のルートのショートサーキットを一度に設定します。 たとえば、ブラウザーやボットでは、サーバーで robots.txtfavicon.ico などの既知のパスを調べることがよくあります。 アプリにこれらのファイルがない場合、1 行のコード行で両方のルートを構成できます。

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

詳しくは、「ルーティング後のミドルウェアのショートサーキット」を参照してください。

HTTP ログ ミドルウェアの拡張性

HTTP ログ ミドルウェアには、いくつかの新機能があります。

  • HttpLoggingFields.Duration: 有効にすると、ミドルウェアによって、処理にかかった合計時間を測定する新しいログが要求と応答の最後に出力されます。 この新しいフィールドは、HttpLoggingFields.All セットに追加されます。
  • HttpLoggingOptions.CombineLogs: 有効にすると、ミドルウェアによって、要求と応答に対して有効なすべてのログが最終的に 1 つのログに統合されます。 1 つのログ メッセージには、要求、要求本文、応答、応答本文、期間が含まれます。
  • IHttpLoggingInterceptor: ログする詳細をカスタマイズするための、要求ごとおよび応答ごとのコールバックを処理するために実装して登録できる (AddHttpLoggingInterceptor を使います) サービス用の新しいインターフェイスです。 エンドポイント固有のログ設定が最初に適用され、その後これらのコールバックでオーバーライドできます。 実装では、次のことができます。
    • 要求または応答を検査する。
    • 任意の HttpLoggingFields を有効または無効にする。
    • ログされる要求本文または応答本文の量を調整する。
    • ログにカスタム フィールドを追加する。

詳細については、.NET Core と ASP.NET Core での HTTP ログ記録に関する記事を参照してください。

回復性の高い統合をサポートする ProblemDetails の新しい API

.NET 7 では、ProblemDetails の仕様 に準拠するエラー応答を生成するためのエクスペリエンスを向上させるために、ProblemDetails サービスが導入されました。 .NET 8 では、IProblemDetailsService を使って ProblemDetails を生成できない場合にフォールバック動作を簡単に実装できるように、新しい API が追加されました。 次の例は、新しい 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 フォールバック」を参照してください

その他のリソース