ASP.NET Core 6.0 の新機能

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

ASP.NET Core MVC と Razor の機能強化

最小 Api

Minimal API は、依存関係が最小限の HTTP API を作成するために設計されています。 ASP.NET Core での最小限のファイル、機能、依存関係のみを含むマイクロサービスやアプリに最適です。 詳細については、次を参照してください。

SignalR

SignalR 接続についての長期アクティビティ タグ

SignalR では、新しい Microsoft.AspNetCore.Http.Features.IHttpActivityFeature.Activity を使用して、要求アクティビティに http.long_running タグを追加します。 IHttpActivityFeature.Activity は、Azure Monitor Application Insights のような APM サービスによって、長期要求アラートの作成から SignalR 要求をフィルター処理するために使用されます。

SignalR のパフォーマンスの向上

  • HubCallerClients をハブ メソッドの呼び出しごとに割り当てるのではなく、接続ごとに 1 回割り当てます。
  • SignalRDefaultHubDispatcher.Invoke でクロージャ割り当てを回避します。 クロージャ割り当てを回避するため、パラメーターを介して、ローカルの静的関数に状態が渡されます。 詳細については、この GitHub pull request を参照してください。
  • サーバーからクライアントへのストリーミングでは、ストリーム項目ごとではなく、ストリームごとに 1 つの StreamItemMessage を割り当てます。 詳細については、この GitHub pull request を参照してください。

Razor コンパイラ

Razor コンパイラはソース ジェネレーターを使用するように更新された

Razor コンパイラは、C# ソース ジェネレーターに基づくようになりました。 ソース ジェネレーターは、コンパイル中に実行されてコンパイルされようとしている内容を検査し、プロジェクトの残りの部分と一緒にコンパイルする追加ファイルを生成します。 ソース ジェネレーターを使用すると、Razor コンパイラが簡略化されて、ビルド時間が大幅に短縮されます。

Razor コンパイラでは別個の Views アセンブリが生成されなくなった

以前の Razor コンパイラでは、別個の View アセンブリが生成される 2 段階のコンパイル プロセスを利用していました。このアセンブリには、アプリで定義されている、生成されたビューとページ (.cshtml ファイル) が含まれていました。 生成される型は、パブリックで、AspNetCore 名前空間の下にありました。

更新された Razor コンパイラでは、ビューとページの型はメイン プロジェクト アセンブリ内にビルドされます。 これらの型は、既定で、内部シールドとして AspNetCoreGeneratedDocument 名前空間内に生成されるようになりました。 この変更により、ビルドのパフォーマンスが向上して単一ファイルのデプロイが実現されており、これらの型を、ホット リロードに加えることができます。

この変更の詳細については、GitHub で、関連する発表のイシューを参照してください。

ASP.NET Core のパフォーマンスと API の強化

割り当てを減らし、スタック全体にわたるパフォーマンスを向上させるために、多くの変更が加えられました。

アイドル状態の TLS 接続のメモリ専有領域を削減

データがたまにしか送受信されない、長期 TLS 接続に関して、.NET 6 では、ASP.NET Core アプリのメモリ専有領域が大幅に削減されています。 これは、WebSocket サーバーなどのシナリオのスケーラビリティ向上に役立つはずです。 これが可能になったのは、System.IO.Pipelines、Kestrel、SslStream において多くの機能強化が行われたためです。 以降のセクションでは、メモリ専有領域の削減に寄与したいくつかの機能強化について詳しく説明します。

System.IO.Pipelines.Pipe のサイズの削減

確立されたすべての接続について、Kestrel で 2 つのパイプが割り当てられます。

  • 要求のための、アプリに対するトランスポート層。
  • 応答のための、トランスポートに対するアプリケーション層。

System.IO.Pipelines.Pipe のサイズを 368 バイトから 264 バイトに圧縮する (約 28.2% 削減) ことで、接続ごとに 208 バイト節約されています (パイプごとに 104 バイト)。

SocketSender のプール

SocketSender オブジェクト (SocketAsyncEventArgs をサブクラス化する) は、実行時に約 350 バイトになります。 接続ごとに新しい SocketSender オブジェクトを割り当てるのではなく、これらをプールすることができます。 SocketSender オブジェクトをプールできるのは、送信は通常、非常に高速であるためです。 プーリングにより、接続ごとのオーバーヘッドが減少します。 接続ごとに 350 バイトを割り当てる代わりに、有料の 350 バイトが割り当てられるのは、IOQueue ごとだけです。 競合を回避するため、割り当てはキューごとに行われます。 アイドル状態の接続が 5000 ある Microsoft の WebSocket サーバーでは、SocketSender オブジェクトについての割り当ては、約 1.75 MB (350 バイト × 5000) から約 2.8 KB (350 バイト × 8) になりました。

SslStream での 0 バイト読み取り

バッファーレス読み取りは、使用できるデータがソケット上にない場合にメモリ プールからメモリを借りることを避けるために ASP.NET Core で使用されている手法です。 この変更以前は、アイドル状態の接続が 5000 個ある WebSocket サーバーでは、TLS を使用していなければ約 200 MB、TLS を使用する場合は約 800 MB 必要でした。 これらの割り当ての一部 (接続あたり 4 KB) は Kestrel からのもので、SslStream での読み取りが完了するのを待っている間、ArrayPool<T> バッファーを保持し続ける必要がありました。 これらの接続がアイドル状態であった場合、どの読み取りも完了せず、バッファーを ArrayPool に返しません。このため ArrayPool では、より多くのメモリを割り当てるしかありません。 残りは、SslStream 自体の中で、TLS ハンドシェイク用の 4 KB バッファーと、通常読み取り用の 32 KB バッファーに割り当てられていました。 .NET 6 では、ユーザーが SslStream に対して 0 バイトの読み取りを実行し、使用できるデータがない場合、ラップされた基になっているストリームに対して、SslStream による 0 バイト読み取りが内部的に実行されます。 最善の場合 (アイドル接続)、これらの変更によって、接続ごとに 40 KB が節約されます。そして同時に、未使用のバッファーを保持し続けることなく、データを使用できるタイミングを引き続きコンシューマー (Kestrel) に通知できます。

PipeReader での 0 バイト読み取り

SslStream でサポートされるバッファーレス読み取りの導入により、StreamPipeReader に適合させる内部型である StreamPipeReader に対して 0 バイト読み取りを実行するオプションが追加されました。 Kestrel では、StreamPipeReader は、基になっている SslStreamPipeReader に適合させるために使用されます。 そのため、これらの 0 バイト読み取りセマンティクスを PipeReader に対して公開する必要がありました。

次の API を使用することで、0 バイト読み取りセマンティクスをサポートしている、基になっている任意の Stream (SslStreamNetworkStream など) に対して、0 バイト読み取りをサポートする PipeReader を作成できるようになりました。

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

SlabMemoryPool からのスラブの削除

Kestrel では、ヒープの断片化を減らすために、メモリ プールの一部として 128 KB メモリのスラブを割り当てる手法を採用していました。 スラブはその後、さらに 4 KB のブロックに分割され、Kestrel によって内部的に使用されました。 スラブは、大きなオブジェクト ヒープへの割り当てを強制的に試みて、この配列が GC によって再配置されるのを防ぐため、85 KB より大きい必要があります。 ただし、新しい GC 生成である固定オブジェクト ヒープ (POH) の導入によって、スラブにブロックを割り当てる意味がなくなっています。 Kestrel では、POH にブロックが直接割り当てられるようになったため、メモリ プールの管理に伴う複雑さが軽減されています。 この変更により、Kestrel によって使用されるメモリ プールの縮小がより簡単になるなど、今後の改善を加えることが容易になるはずです。

IAsyncDisposable のサポート

コントローラー、Razor ページ、およびビュー コンポーネントで、IAsyncDisposable を使用できるようになりました。 ファクトリとアクティベーターの関連するインターフェイスに、非同期バージョンが追加されています。

  • 新しいメソッドには、同期バージョンにデリゲートして Dispose を呼び出す既定のインターフェイス実装が用意されています。
  • これらの実装は、既定の実装をオーバーライドして、破棄を行う IAsyncDisposable 実装を処理します。
  • 両方のインターフェイスが実装されている場合、実装では IDisposable よりも IAsyncDisposable が優先されます。
  • エクステンダーでは、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());
    }

IAsyncDisposableDisposeAsync を実装する必要があります。

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

    _jsonWriter = null;
}

SignalR C++ クライアント用の Vcpkg ポート

Vcpkg は、C および C++ ライブラリ用の、クロスプラットフォームのコマンドライン パッケージ マネージャーです。 最近、SignalR C++ クライアントに CMake のネイティブ サポートを追加するため、vcpkg にポートが追加されました。 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 Server アプリの _Host.cshtml ファイルに表示されたレイアウト コンテンツに Pages/_Layout.cshtml ファイルを使用する方法など、Blazor アプリのプロジェクト テンプレートに対していくつかの変更が加えられています。 6.0 のプロジェクト テンプレートからアプリを作成するか、そのプロジェクト テンプレートの ASP.NET Core の参照ソースにアクセスすることで、変更内容を確認してください。

Blazor WebAssembly のネイティブの依存関係のサポート

Blazor WebAssembly アプリは、WebAssembly での実行用にビルドされた、ネイティブの依存関係を使用できます。 詳細については、「ASP.NET Core Blazor WebAssembly のネイティブの依存関係」を参照してください。

WebAssembly Ahead-of-Time (AOT) コンパイルとランタイムの再リンク

Blazor WebAssembly では、Ahead-Of-Time (AOT) コンパイルがサポートされています。これにより、.NET コードを直接 WebAssembly にコンパイルできます。 AOT コンパイルを使用すると、アプリのサイズが大きくなりますが、実行時のパフォーマンスが向上します。 .NET WebAssembly ランタイムを再リンクすると、未使用のランタイム コードが削除されるため、ダウンロード速度が向上します。 詳細については、「Ahead-of-Time (AOT) コンパイル」と「ランタイムの再リンク」を参照してください。

プリレンダリングされた状態を保持する

Blazor では、アプリが完全に読み込まれたときに状態を再作成する必要がなされないように、プリレンダリングされたページでの状態の保持がサポートされています。 詳細については、「ASP.NET Core Razor コンポーネントのプリレンダリングと統合を行う」を参照してください。

エラー境界

エラー境界には、UI レベルで例外を処理するための便利な方法が備わっています。 詳細については、「ASP.NET Core Blazor アプリのエラーを処理する」を参照してください。

SVG のサポート

SVG 内で任意の HTML を表示するために、<foreignObject> 要素がサポートされています。 詳細については、「ASP.NET Core Razor コンポーネント」を参照してください。

JS 相互運用でのバイト配列転送に対する Blazor Server のサポート

Blazor では、Base64 へのバイト配列のエンコードおよびデコードを回避する、最適化されたバイト配列 JS 相互運用がサポートされています。 詳細については、次のリソースを参照してください。

クエリ文字列の機能強化

クエリ文字列の操作のサポートが強化されています。 詳細については、「ASP.NET Core の Blazor ルーティングとナビゲーション」を参照してください。

複数選択へのバインド

バインドでは、<input> 要素を使用した複数オプションの選択がサポートされます。 詳細については、次のリソースを参照してください。

ヘッド (<head>) コンテンツの制御

Razor コンポーネントでは、ページのタイトル (<title> 要素) の設定やメタデータ (<meta> 要素) の変更など、ページの HTML <head> 要素のコンテンツを変更できます。 詳細については、「ASP.NET Core Blazor アプリで <head> コンテンツを制御する」を参照してください。

Angular コンポーネントと React コンポーネントを生成する

Angular や React などの Web フレームワークの 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 セレクターに基づいて 1 つの要素に 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 相互運用)」をご覧ください。

JavaScript イニシャライザー

JavaScript 初期化子によって、Blazor アプリの読み込みの前後にロジックが実行されます。 詳しくは、「ASP.NET Core Blazor JavaScript の相互運用性 (JS 相互運用)」をご覧ください。

ストリーミング JavaScript の相互運用

Blazor では、.NET と JavaScript との間で、データの直接的なストリーミングがサポートされるようになりました。 詳細については、次のリソースを参照してください。

ジェネリック型の制約

ジェネリック型のパラメーターがサポートされるようになりました。 詳細については、「ASP.NET Core Razor コンポーネント」を参照してください。

WebAssembly 配置レイアウト

制限のあるセキュリティ環境で、配置レイアウトを使用して Blazor WebAssembly アプリのダウンロードを有効にします。 詳細については、「ASP.NET Core でホストされる Blazor WebAssembly アプリの展開レイアウト」を参照してください。

新しい Blazor の記事

前のセクションで説明した Blazor の機能に加えて、以下のテーマに関する新しい Blazor の記事が公開されています。

.NET MAUI、WPF および Windows フォームで Blazor Hybrid アプリを構築する

Blazor Hybrid を使って、デスクトップとモバイルのネイティブ クライアント フレームワークを .NET および Blazor と組み合わせます。

  • .NET Multi-platform App UI (.NET MAUI) は、C# と XAML でネイティブのモバイルおよびデスクトップ アプリを作成するためのクロスプラットフォーム フレームワークです。
  • Blazor Hybrid アプリは、Windows Presentation Foundation (WPF) と Windows フォーム フレームワークを使って構築できます。

重要

Blazor Hybrid フレームワークはプレビュー段階にあり、最終リリースまで運用環境のアプリでは使用しないでください。

詳細については、次のリソースを参照してください。

Kestrel

HTTP/3 は現在ドラフト段階にあるため、変更される可能性があります。 ASP.NET Core での HTTP/3 のサポートはリリースされておらず、.NET 6 に含まれるプレビュー機能となっています。

Kestrel では、HTTP/3 をサポートするようになりました。 詳細については、「ASP.NET Core Kestrel Web サーバーで HTTP/3 を使用する」と .NET 6 での HTTP/3 のサポートに関するブログ エントリを参照してください。

選択したログ記録用の新しい Kestrel ログ記録カテゴリ

この変更以前は、すべての Kestrel でログ記録カテゴリ名 Microsoft.AspNetCore.Server.Kestrel を共有していたため、Kestrel の詳細ログ記録を有効にすると極めて高いコストがかかっていました。 Microsoft.AspNetCore.Server.Kestrel はまだ使用できますが、以下の新しいサブカテゴリを使用すると、ログ記録をより細かく制御できます。

  • Microsoft.AspNetCore.Server.Kestrel (現在のカテゴリ): ApplicationErrorConnectionHeadResponseBodyWriteApplicationNeverCompletedRequestBodyStartRequestBodyDoneRequestBodyNotEntirelyReadRequestBodyDrainTimedOutResponseMinimumDataRateNotSatisfiedInvalidResponseHeaderRemovedHeartbeatSlow
  • Microsoft.AspNetCore.Server.Kestrel.BadRequests: ConnectionBadRequestRequestProcessingErrorRequestBodyMinimumDataRateNotSatisfied
  • Microsoft.AspNetCore.Server.Kestrel.Connections: ConnectionAcceptedConnectionStartConnectionStopConnectionPauseConnectionResumeConnectionKeepAliveConnectionRejectedConnectionDisconnectNotAllConnectionsClosedGracefullyNotAllConnectionsAbortedApplicationAbortedConnection
  • Microsoft.AspNetCore.Server.Kestrel.Http2: Http2ConnectionErrorHttp2ConnectionClosingHttp2ConnectionClosedHttp2StreamErrorHttp2StreamResetAbortHPackDecodingErrorHPackEncodingErrorHttp2FrameReceivedHttp2FrameSendingHttp2MaxConcurrentStreamsReached
  • Microsoft.AspNetCore.Server.Kestrel.Http3: Http3ConnectionErrorHttp3ConnectionClosingHttp3ConnectionClosedHttp3StreamAbortHttp3FrameReceivedHttp3FrameSending

既存のルールは引き続き機能しますが、有効にするルールをよりきめ細かに選択できるようになりました。 たとえば、単に正しくない要求の 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 を作成できるようになっています。 これにより、SocketConnection で発生するすべてのパフォーマンス作業とプーリングを失うことなく、カスタムのソケットベースの IConnectionListenerFactory を構築できます。

この を使用する方法を示している、カスタム IConnectionListenerFactory のこの例SocketConnectionContextFactoryを参照してください。

Kestrel は Visual Studio の既定の起動プロファイルである

新しい dotnet Web プロジェクトの既定の起動プロファイルはすべて Kestrel です。 アプリの開発中、Kestrel の起動が大幅に高速になり、操作の応答性が高まります。

IIS Express は、Windows 認証やポート共有などのシナリオの起動プロファイルとして、引き続き使用できます。

Kestrel の localhost ポートはランダムである

詳細については、このドキュメントの「テンプレートによって Kestrel 用に生成されるポート」を参照してください。

認証と権限承認

認証サーバー

.NET 3 から .NET 5 では、SPA および Blazor アプリケーションで JWT トークンの発行をサポートするために、テンプレートの一部として IdentityServer4 を使用していました。 テンプレートには Duende Identity Serverが使用されるようになりました。

ID モデルを拡張し、既存のプロジェクトを更新しようとしている場合は、コード内の名前空間を IdentityServer4.IdentityServer から Duende.IdentityServer に更新し、それらの移行に関する指示に従う必要があります。

Duende Identity サーバーのライセンス モデルは、レシプロカル ライセンスに変更されました。運用環境で商用に使用する場合は、ライセンス料金が必要になる場合があります。 詳細については、Duende のライセンスに関するページを参照してください。

遅延クライアント証明書ネゴシエーション

開発者は、HttpsConnectionAdapterOptionsClientCertificateMode.DelayCertificate を指定することで、遅延クライアント証明書ネゴシエーションの使用をオプトインできるようになりました。 HTTP/2 では、遅延した証明書の再ネゴシエーションは禁止されているため、これは HTTP/1.1 接続でのみ機能します。 この 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();

Cookie 認証のスライド式有効期限は、新しい OnCheckSlidingExpiration を使ってカスタマイズまたは抑制できるようになりました。 たとえば、このイベントは、認証セッションに影響を与えずにサーバーに定期的に 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 からの要求をプロキシ経由で開発サーバーに送信していました。 フロントエンド開発サーバーを起動するためのロジックは、対応するフロントエンド フレームワークのコマンド ライン インターフェイスに固有のものでした。 このパターンを使用して追加のフロントエンド フレームワークをサポートすることは、ASP.NET Core に別のロジックを追加することを意味していました。

.NET 6 で Angular および React 用に更新された ASP.NET Core テンプレートでは、このやり方は転換されて、最新のフロントエンド フレームワークによって構成される開発サーバーでの、組み込みのプロキシ処理のサポートが活用されます。 ASP.NET Core アプリが起動されると、フロントエンド開発サーバーは以前と同様に起動されますが、開発サーバーは、要求をプロキシ経由でバックエンドの ASP.NET Core プロセスに送信するように構成されます。 プロキシをセットアップするためのフロントエンド固有の構成はすべて、ASP.NET Core ではなく、アプリの一部です。 他のフロントエンド フレームワークと連携するように ASP.NET Core プロジェクトを設定することが簡単になりました。Angular および React テンプレートで確立されたパターンを使用して、選択したフレームワークのフロントエンド開発サーバーを ASP.NET Core バックエンドにプロキシするように設定します。

ASP.NET Core アプリのスタートアップ コードでは、シングル ページ アプリ固有のロジックをまったく必要としなくなりました。 開発時にフロントエンド開発サーバーを起動するためのロジックは、新しい Microsoft.AspNetCore.SpaProxy パッケージによって、実行時にアプリに挿入されます。 フォールバック ルーティングは、SPA 固有のミドルウェアではなく、エンドポイント ルーティングを使用して処理されます。

このパターンに従っているテンプレートは、引き続き、Visual Studio で 1 つのプロジェクトとして実行することも、コマンド ラインから 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 アプリでは、4 行のコードが含まれる 1 つの C# ファイルが作成されますが、これは完全なアプリです。
  • Startup.csProgram.cs を 1 つの Program.cs ファイルに統合します。
  • トップレベル ステートメントを使用して、アプリに必要なコードを最小限に抑えます。
  • global using ディレクティブ を使用して、using ステートメントを不要にするか、または必要とするその行数を最小限に抑えます。

テンプレートによって Kestrel 用に生成されるポート

プロジェクトの作成時には、Kestrel Web サーバーで使用するために、ランダムなポートが割り当てられます。 ランダムなポートは、同じコンピューターで複数のプロジェクトが実行されるときに、ポートの競合を最小限するのに役立ちます。

プロジェクトが作成されるときには、生成される Properties/launchSettings.json ファイルに、5000 から 5300 の間のランダムな HTTP ポートと、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();
}

Latin1 でエンコードされた要求ヘッダーの HttpSysServer でのサポート

HttpSysServer では、HttpSysOptionsUseLatin1RequestHeaders プロパティを true に設定することによって、Latin1 でエンコードされた要求ヘッダーのデコードがサポートされるようになりました。

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) の拡張診断ログには、ログを出力するプロセスのタイムスタンプと PID が含められます。 タイムスタンプと PID をログに記録すると、複数の IIS ワーカー プロセスが実行されている場合に、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 に変更されており、大きなアップロードのスループットが向上するはずです。 Microsoft のテストでは、以前は 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 pull request と、NewtonsoftJsonOutputFormatterTest.cs ファイルを参照してください。

HTTP ヘッダーの取得と設定の高速化

Microsoft.Net.Http.Headers.HeaderNames で使用できるすべての共通ヘッダーを IHeaderDictionary のプロパティとして公開するために新しい API が追加されて、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 のサポートが強化されており、EF Core を ASP.NET 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 でのジェネリック型の制約

Razor では、@typeparam ディレクティブを使用してジェネリック型パラメーターを定義するときに、標準の C# 構文を使用してジェネリック型の制約を指定できるようになりました。

SignalR、Blazor Server、MessagePack のスクリプトが小型化

SignalR、MessagePack、Blazor Server のスクリプトが大幅に小さくなり、ダウンロード サイズがより小さく、ブラウザーによる JavaScript の解析とコンパイルはより少なく、起動はより速くなっています。 サイズの削減は次のとおりです。

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

スクリプトが小さくなったのは、Ben Adams からのコミュニティ投稿の結果です。 サイズ縮小の詳細については、Ben の GitHub pull request を参照してください。

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 での実行時にはアプリケーション バイナリをロックして、アプリの実行中にバイナリを置き換えられないようにしています。 Microsoft では、引き続きアプリのオフライン ファイルを使用することをお勧めしていますが、そうすることができない特定のシナリオがある (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 の一部になるとは保証されていない実験的機能です。 IIS シャドウ コピーに関するフィードバックは、この GitHub イシューに残してください。

その他のリソース