次の方法で共有


ASP.NET Core 9.0 の新機能

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

この記事は、.NET 9 Preview 5 用に更新されました。

Blazor

このセクションでは、Blazor の新機能について説明します。

.NET MAUIBlazor Hybrid および Web アプリ ソリューション テンプレート

新しいソリューション テンプレートを使用すると、共通の UI を備えた .NET MAUI ネイティブ クライアント アプリと Blazor Web クライアント アプリを簡単に作成できます。 このテンプレートは、コードの再利用を最大化し、Android、iOS、Mac、Windows、Web をターゲットにするクライアント アプリ開発を行う方法を示します。

このテンプレートの主な特長:

  • どの Blazor 対話型レンダリング モードを Web アプリで使用するかを選択できます。
  • Blazor Web アプリ (グローバル対話型オート レンダリング) と .NET MAUIBlazor Hybrid アプリを含む適切なプロジェクトの自動作成。
  • 作成されたプロジェクトは、共有 Razor クラス ライブラリ (RCL) を使用して、UI の Razor コンポーネントを維持します。
  • 依存関係インジェクションを使用して Blazor Hybrid アプリと Blazor Web アプリに異なるインターフェイス実装を提供する方法を示すサンプル コードが含まれています。

開始するには、.NET 9 SDK をインストールして、.NET MAUI ワークロードをインストールします。これには以下のテンプレートが含まれています。

dotnet workload install maui

次のコマンドを使用して、コマンド シェルでプロジェクト テンプレートからソリューションを作成します。

dotnet new maui-blazor-web

このテンプレートは、Visual Studio にも用意されています。

Note

現時点で、Blazor レンダリング モードがページごと/コンポーネント レベルで定義されていると例外がスローされます。 詳しくは、「BlazorWebView では ResolveComponentForRenderMode のオーバーライドを有効にする方法が必要 (dotnet/aspnetcore #51235)」をご覧ください。

詳細については、「Blazor Web アプリで .NET MAUIBlazor Hybrid アプリを構築する」を参照してください。

静的アセットの配信の最適化

MapStaticAssets は、Blazor アプリを含む ASP.NET Core アプリ内の静的アセットの配信の最適化に役立つ新しいミドルウェアです。

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

実行時にレンダリングの場所、対話機能、および割り当てられたレンダリング モードを検出する

実行時にコンポーネントの状態を照会するプロセスを簡略化するように設計された新しい API を導入しました。 この API には、次の機能があります。

  • コンポーネントの現在の実行場所を決定する: これは、コンポーネントのパフォーマンスのデバッグと最適化に特に役立ちます。
  • コンポーネントが対話型環境で実行されているかどうかを確認する: これは、環境の対話機能に基づいて異なる動作をするコンポーネントに役立ちます。
  • コンポーネントに割り当てられたレンダリング モードを取得する: レンダリング モードを理解することは、レンダリング プロセスを最適化し、コンポーネントの全体的なパフォーマンスを向上させるのに役立ちます。

サーバー側再接続エクスペリエンスの改善:

規定のサーバー側再接続エクスペリエンスに対し、以下の機能強化が行われました。

  • ユーザーが、回線が切断されたアプリに戻ると、次の再接続間隔を待たずに、すぐに再接続が試行されます。 これにより、アプリのブラウザー タブがユーザーの操作によってスリープ状態から復帰したときのユーザー エクスペリエンスが改善されます。

  • 再接続試行がサーバーに到達したがサーバーで回線が既に解放されている場合、ページの更新が自動的に行われます。 これにより、再接続が成功する可能性が高い場合に、ユーザーがページを手動で更新する必要がなくなります。

  • 再接続のタイミングでは、計算されたバックオフ戦略が使用されます。 既定では、最初の数回の再接続が短い間隔で、再試行の間隔を挟まずに試行された後に、計算された遅延が試行間に導入されます。 次の指数バックオフの例に示すように、再試行の間隔を計算する関数を指定することで、再試行の間隔の動作をカスタマイズできます。

    Blazor.start({
      circuit: {
        reconnectionOptions: {
          retryIntervalMilliseconds: (previousAttempts, maxRetries) => 
            previousAttempts >= maxRetries ? null : previousAttempts * 1000
        },
      },
    });
    
  • 既定の再接続 UI のスタイルが最新化されました。

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

Blazor Web アプリ用のシンプルな認証状態シリアル化

新しい API を使用すると、既存の Blazor Web アプリに認証を簡単に追加できます。 新しい Blazor Web アプリを、個別アカウントによる認証を使用して作成し、WebAssembly ベースの対話機能を有効にすると、そのプロジェクトでは、カスタム AuthenticationStateProvider がサーバー プロジェクトとクライアント プロジェクトの両方に含められます。

それらのプロバイダーは、ユーザーの認証状態をブラウザーに送信します。 クライアントではなくサーバーで認証を行うことで、アプリはプリレンダリング中と Blazor WebAssembly ランタイムの初期化前に認証状態にアクセスできます。

カスタムの AuthenticationStateProvider の実装は、Persistent Component State サービス (PersistentComponentState) を使用して認証状態を HTML コメントにシリアル化し、その後に WebAssembly からそれを再度読み取って新しい AuthenticationState インスタンスを作成します。

この方法は、Blazor Web アプリ プロジェクト テンプレートから開始して個別アカウント オプションを選択する場合はうまく機能しますが、既存プロジェクトに認証を追加する場合には、大量のコードを自力で実装またはコピーする必要があります。 そこで現在は、この機能を追加する手段として、サーバー プロジェクトとクライアント プロジェクトの両方から呼び出せる以下の API が用意されています。これらは現在、Blazor Web アプリ プロジェクト テンプレートの一部となっています。

  • AddAuthenticationStateSerialization: サーバー上の認証状態をシリアル化するために必要なサービスを追加します。
  • AddAuthenticationStateDeserialization: ブラウザーの認証状態を逆シリアル化するために必要なサービスを追加します。

既定では、この API がシリアル化するのは、ブラウザーでアクセスするためのサーバー側の名前とロールの要求だけです。 オプションを AddAuthenticationStateSerialization に渡して、すべての要求を含めることができます。

詳細については、** 記事の以下のセクションを参照してください。

グローバルにインタラクティブ Blazor Web アプリに静的サーバー側レンダリング (SSR) ページを追加する

.NET 9 のリリースにより、グローバルなインタラクティビティを採用するアプリに静的 SSR ページを追加するアプローチが簡単になりました。

このアプローチが役に立つのは、インタラクティブ サーバーまたは WebAssembly レンダリングを使用して動作できない特定のページがアプリにある場合のみです。 たとえば、HTTP cookie の読み取り/書き込みに依存し、インタラクティブ レンダリングの代わりに要求/応答サイクルでのみ動作できるページには、このアプローチを採用します。 インタラクティブ レンダリングを使用するページでは、静的 SSR レンダリングを強制的に使用しないでください。静的 SSR レンダリングは、エンド ユーザーにとって効率と応答性が低いからです。

@attributeRazor ディレクティブに割り当てられた新しい [ExcludeFromInteractiveRouting] 属性を使用して Razor コンポーネント ページをマークします。

@attribute [ExcludeFromInteractiveRouting]

この属性を適用すると、インタラクティブ ルーティングでページへのナビゲーションが終了します。 インバウンド ナビゲーションでは、インタラクティブ ルーティングを使用してページを解決するのではなく、ページ全体の再読み込みが強制的に実行されます。 ページ全体の再読み込みでは、最上位のルート コンポーネント (通常は App コンポーネント (App.razor)) がサーバーから再レンダリングするよう強制されるため、アプリは別の最上位レベルのレンダリング モードに切り替えることができます。

HttpContext.AcceptsInteractiveRouting 拡張メソッドを使用すると、このコンポーネントは [ExcludeFromInteractiveRouting] が現在のページに適用されているかどうかを検出できます。

App コンポーネントでは、次の例のパターンが使用されます。

  • [ExcludeFromInteractiveRouting] の注釈が付けられていないページは、グローバル インタラクティビティを使用した InteractiveServer レンダリング モードに既定で設定されます。 InteractiveServerInteractiveWebAssembly または InteractiveAuto に置き換えて、別の既定のグローバル レンダリング モードを指定できます。
  • [ExcludeFromInteractiveRouting] の注釈が付けられたページは、静的 SSR を採用します (PageRenderMode には null が割り当てられます)。
<!DOCTYPE html>
<html>
<head>
    ...
    <HeadOutlet @rendermode="@PageRenderMode" />
</head>
<body>
    <Routes @rendermode="@PageRenderMode" />
    ...
</body>
</html>

@code {
    [CascadingParameter]
    private HttpContext HttpContext { get; set; } = default!;

    private IComponentRenderMode? PageRenderMode
        => HttpContext.AcceptsInteractiveRouting() ? InteractiveServer : null;
}

HttpContext.AcceptsInteractiveRouting 拡張メソッドを使用する代わりに、HttpContext.GetEndpoint()?.Metadata を使用してエンドポイント メタデータを手動で読み取る方法があります。

この機能は、「ASP.NET Core Blazor レンダリング モード」のリファレンス ドキュメントで説明されています。

コンストラクターの挿入

Razor コンポーネントではコンストラクターの挿入をサポートしています。

次の例では、部分 (コードビハインド) クラスで、プライマリ コンストラクターを使用して NavigationManager サービスを挿入します。

public partial class ConstructorInjection(NavigationManager navigation)
{
    protected NavigationManager Navigation { get; } = navigation;
}

詳細については、「ASP.NET Core Blazor の依存関係の挿入」を参照してください。

対話型サーバー コンポーネントの Websocket 圧縮

既定の場合、対話型サーバー コンポーネントでは WebSocket 接続の圧縮を有効にし、frame-ancestorsコンテンツ セキュリティ ポリシー (CSP) ディレクティブを 'self' に設定します。これは、圧縮が有効になっている場合または WebSocket コンテキストの構成が提供されている場合にのみ、アプリの提供元の <iframe> にアプリを埋め込むことを許可します。

圧縮を無効にするには、ConfigureWebSocketOptionsnull に設定します。こうすると、攻撃対象のアプリの脆弱性は低くなりますが、パフォーマンスが低下するおそれがあります。

.AddInteractiveServerRenderMode(o => o.ConfigureWebSocketOptions = null)

'none' を指定 (単一引用符が必要) してより厳格な frame-ancestors CSP を構成します。これで WebSocket 圧縮が可能になりますが、ブラウザーでアプリを <iframe> に埋め込むことはできなくなります。

.AddInteractiveServerRenderMode(o => o.ContentSecurityFrameAncestorsPolicy = "'none'")

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

Blazor でキーボード コンポジション イベントを処理する

新しい KeyboardEventArgs.IsComposing プロパティは、キーボード イベントがコンポジション セッションの一部であるかどうかを表します。 キーボード イベントのコンポジション状態を追跡することは、国際的な文字入力方式を処理するために重要です。

OverscanCount パラメーターを QuickGrid に追加しました

QuickGrid コンポーネントは、仮想化が有効な場合に表示領域の前後でレンダリングされる追加の行数を指定する OverscanCount プロパティを公開するようになりました。

既定の OverscanCount は 3 です。 次の例では、OverscanCount を 4 に増加します。

<QuickGrid ItemsProvider="itemsProvider" Virtualize="true" OverscanCount="4">
    ...
</QuickGrid>

SignalR

このセクションでは、SignalR の新機能について説明します。

SignalR ハブでのポリモーフィック型のサポート

ハブ メソッドは、派生クラスではなく基底クラスを受け入れて、ポリモーフィックなシナリオを有効にできるようになりました。 ポリモーフィズムを許可するには、基本型に注釈を付ける必要があります。

public class MyHub : Hub
{
    public void Method(JsonPerson person)
    {
        if (person is JsonPersonExtended)
        {
        }
        else if (person is JsonPersonExtended2)
        {
        }
        else
        {
        }
    }
}

[JsonPolymorphic]
[JsonDerivedType(typeof(JsonPersonExtended), nameof(JsonPersonExtended))]
[JsonDerivedType(typeof(JsonPersonExtended2), nameof(JsonPersonExtended2))]
private class JsonPerson
{
    public string Name { get; set; }
    public Person Child { get; set; }
    public Person Parent { get; set; }
}

private class JsonPersonExtended : JsonPerson
{
    public int Age { get; set; }
}

private class JsonPersonExtended2 : JsonPerson
{
    public string Location { get; set; }
}

最小 Api

このセクションでは、最小 API の新機能について説明します。

InternalServerErrorInternalServerError<TValue>TypedResults に追加しました

この TypedResults クラスは、厳密に型指定された HTTP 状態コードベースの応答を最小限の API から返すのに役立つ手段です。 TypedResults には、エンドポイントから "500 内部サーバー エラー" 応答を返すファクトリ メソッドと型が含まれるようになりました。 500 応答を返す例を次に示します。

var app = WebApplication.Create();

app.MapGet("/", () => TypedResults.InternalServerError("Something went wrong!"));

app.Run();

OpenAPI

OpenAPI ドキュメント生成の組み込みサポート

OpenAPI 仕様は、HTTP API を記述するための標準です。 この標準により、開発者は、クライアント ジェネレーター、サーバー ジェネレーター、テスト ツール、ドキュメントなどに接続できる API の形状を定義できます。 .NET 9 プレビューでは、ASP.NET Core は、Microsoft.AspNetCore.OpenApi パッケージを使用して、コントローラー ベースまたは最小限の API を表す OpenAPI ドキュメントを生成するための組み込みサポートを提供します。

次の強調されているコードでは、次が呼び出されます。

  • 必要な依存関係をアプリの DI コンテナーに登録するための AddOpenApi
  • 必要な OpenAPI エンドポイントをアプリのルートに登録するための MapOpenApi
var builder = WebApplication.CreateBuilder();

builder.Services.AddOpenApi();

var app = builder.Build();

app.MapOpenApi();

app.MapGet("/hello/{name}", (string name) => $"Hello {name}"!);

app.Run();

次のコマンドを使用して、Microsoft.AspNetCore.OpenApi パッケージをプロジェクトにインストールします。

dotnet add package Microsoft.AspNetCore.OpenApi --prerelease

アプリを実行し、openapi/v1.json に移動して、生成された OpenAPI ドキュメントを表示します。

OpenAPI ドキュメント

OpenAPI ドキュメントは、Microsoft.Extensions.ApiDescription.Server パッケージを追加することで、ビルド時に生成することもできます。

dotnet add package Microsoft.Extensions.ApiDescription.Server --prerelease

アプリのプロジェクト ファイルに、次を追加します。

<PropertyGroup>
  <OpenApiDocumentsDirectory>$(MSBuildProjectDirectory)</OpenApiDocumentsDirectory>
  <OpenApiGenerateDocuments>true</OpenApiGenerateDocuments>
</PropertyGroup>

dotnet build を実行し、プロジェクト ディレクトリで生成された JSON ファイルを調べます。

ビルド時の OpenAPI ドキュメントの生成

ASP.NET Core の組み込みの OpenAPI ドキュメント生成は、さまざまなカスタマイズとオプションのサポートを提供しています。 これは、ドキュメント トランスフォーマーと操作トランスフォーマーを提供し、同じアプリケーションに対する複数の OpenAPI ドキュメントを管理する機能を持ちます。

ASP.NET Core の新しい OpenAPI ドキュメント機能の詳細については、新しい Microsoft.AspNetCore.OpenApi ドキュメントを参照してください。

認証と権限承認

このセクションでは、認証と認可の新機能について説明します。

OIDC と OAuth パラメーターのカスタマイズ

OAuth および OIDC 認証ハンドラーには、通常はリダイレクト クエリ文字列の一部として含まれる認可メッセージ パラメーターを簡単にカスタマイズするための AdditionalAuthorizationParameters オプションが追加されました。 .NET 8 以前でこれを行うには、カスタム ハンドラー内のカスタム OnRedirectToIdentityProvider コールバックまたはオーバーライドされた BuildChallengeUrl メソッドが必要です。 .NET 8 コードの例を次に示します。

builder.Services.AddAuthentication().AddOpenIdConnect(options =>
{
    options.Events.OnRedirectToIdentityProvider = context =>
    {
        context.ProtocolMessage.SetParameter("prompt", "login");
        context.ProtocolMessage.SetParameter("audience", "https://api.example.com");
        return Task.CompletedTask;
    };
});

上記の例は、次に示すコードに簡略化できるようになりました。

builder.Services.AddAuthentication().AddOpenIdConnect(options =>
{
    options.AdditionalAuthorizationParameters.Add("prompt", "login");
    options.AdditionalAuthorizationParameters.Add("audience", "https://api.example.com");
});

HTTP.sys 拡張認証フラグを構成する

Windows 認証の処理方法を最適化するために、HTTP.sys AuthenticationManager で新しい EnableKerberosCredentialCaching および CaptureCredentials プロパティを使用することで、HTTP_AUTH_EX_FLAG_ENABLE_KERBEROS_CREDENTIAL_CACHING および HTTP_AUTH_EX_FLAG_CAPTURE_CREDENTIAL HTTP.sys フラグを構成できるようになりました。 次に例を示します。

webBuilder.UseHttpSys(options =>
{
    options.Authentication.Schemes = AuthenticationSchemes.Negotiate;
    options.Authentication.EnableKerberosCredentialCaching = true;
    options.Authentication.CaptureCredentials = true;
});

その他

以下のセクションでは、その他の新機能について説明します。

新しい HybridCache ライブラリ

HybridCache API は、既存の IDistributedCache および IMemoryCache API のいくつかのギャップを埋めます。 また、次のような新しい機能も追加されます。

  • 同じ作業の並列フェッチを防ぐための "スタンピード" 保護
  • 構成可能なシリアル化。

HybridCache は、既存の IDistributedCacheIMemoryCache の使用に完全に取って代わるように設計されており、新しいキャッシュ コードを追加するための簡単な API を提供します。 これは、インプロセス キャッシュとアウトプロセス キャッシュの両方に対応する統合 API を提供します。

HybridCache API がどのように簡略化されているかを確認するには、IDistributedCache を使用するコードと比較してください。 IDistributedCache を使用するとどのようになるかの例を次に示します。

public class SomeService(IDistributedCache cache)
{
    public async Task<SomeInformation> GetSomeInformationAsync
        (string name, int id, CancellationToken token = default)
    {
        var key = $"someinfo:{name}:{id}"; // Unique key for this combination.
        var bytes = await cache.GetAsync(key, token); // Try to get from cache.
        SomeInformation info;
        if (bytes is null)
        {
            // Cache miss; get the data from the real source.
            info = await SomeExpensiveOperationAsync(name, id, token);

            // Serialize and cache it.
            bytes = SomeSerializer.Serialize(info);
            await cache.SetAsync(key, bytes, token);
        }
        else
        {
            // Cache hit; deserialize it.
            info = SomeSerializer.Deserialize<SomeInformation>(bytes);
        }
        return info;
    }

    // This is the work we're trying to cache.
    private async Task<SomeInformation> SomeExpensiveOperationAsync(string name, int id,
        CancellationToken token = default)
    { /* ... */ }
}

シリアル化などを含め、毎回やるべき作業が多数存在します。 また、キャッシュ ミスのシナリオでは、複数の同時実行スレッドを扱うことになる可能性があり、すべてのスレッドでキャッシュ ミスが発生し、すべてのスレッドで基になるデータをフェッチし、すべてのスレッドでそれをシリアル化し、すべてのスレッドでそのデータをキャッシュに送信する場合があります。

HybridCache を使用してこのコードを簡略化して改善するには、まず新しいライブラリ Microsoft.Extensions.Caching.Hybrid を追加する必要があります。

<PackageReference Include="Microsoft.Extensions.Caching.Hybrid" Version="9.0.0" />

IDistributedCache 実装を登録する場合と同様に、HybridCache サービスを登録します。

services.AddHybridCache(); // Not shown: optional configuration API.

キャッシュに関するほとんどの問題を HybridCache にオフロードできるようになりました。

public class SomeService(HybridCache cache)
{
    public async Task<SomeInformation> GetSomeInformationAsync
        (string name, int id, CancellationToken token = default)
    {
        return await cache.GetOrCreateAsync(
            $"someinfo:{name}:{id}", // Unique key for this combination.
            async cancel => await SomeExpensiveOperationAsync(name, id, cancel),
            token: token
        );
    }
}

Microsoft は、依存関係の挿入を使用して HybridCache 抽象クラスの具体的な実装を提供していますが、これは、開発者が API のカスタム実装を提供できるようにすることを意図しています。 HybridCache 実装は、同時操作の処理を含む、キャッシュに関連するすべての処理を扱います。 ここでの cancel トークンは、確認できる呼び出し元 (つまり、token) の取り消しだけでなく、すべての同時呼び出し元の結合された取り消しを表します。

キャプチャした変数やインスタンスごとのコールバックによるオーバーヘッドを回避するために、TState パターンを使用して、高スループットのシナリオをさらに最適化できます。

public class SomeService(HybridCache cache)
{
    public async Task<SomeInformation> GetSomeInformationAsync(string name, int id, CancellationToken token = default)
    {
        return await cache.GetOrCreateAsync(
            $"someinfo:{name}:{id}", // unique key for this combination
            (name, id), // all of the state we need for the final call, if needed
            static async (state, token) =>
                await SomeExpensiveOperationAsync(state.name, state.id, token),
            token: token
        );
    }
}

HybridCache は、Redis など使用を使用して、セカンダリ アウトプロセス キャッシュ用として構成された IDistributedCache 実装 (存在する場合) を使用します。 ただし、IDistributedCache がなくても、HybridCache サービスは引き続きインプロセス キャッシュと "スタンピード" 保護を提供します。

オブジェクトの再利用に関する注意事項

IDistributedCache を使用する一般的な既存のコードでは、キャッシュからオブジェクトを取得するたびに、逆シリアル化が行われます。 この動作は、各同時実行呼び出し元が、その他のインスタンスとは対話できない、オブジェクトの個別のインスタンスを取得することを意味します。 この結果、同じオブジェクト インスタンスに同時に変更を加えるリスクがなくなるため、スレッド セーフになります。

HybridCache の使用の多くは既存の IDistributedCache コードから適応されるため、HybridCache は、コンカレンシーのバグが発生しないように既定でこの動作を保持します。 ただし、次の特定のユース ケースは本質的にスレッド セーフです。

  • キャッシュされる型が不変である場合。
  • コードで型が変更されない場合。

このような場合、次の方法により、インスタンスを再利用しても安全であることを HybridCache に通知します。

  • 型を sealed としてマークします。 C# の sealed キーワードは、クラスを継承できないことを意味します。
  • それに [ImmutableObject(true)] 属性を追加します。 [ImmutableObject(true)] 属性は、オブジェクトの作成後にその状態を変更できないことを示します。

インスタンスを再利用することで、HybridCache は、呼び出しごとの逆シリアル化に関連する CPU とオブジェクトの割り当てのオーバーヘッドを削減できます。 この結果、キャッシュされたオブジェクトが大きいか頻繁にアクセスされるシナリオでパフォーマンスが向上する可能性があります。

その他の HybridCache 機能

IDistributedCache と同様に、HybridCache は、RemoveKeyAsync メソッドを使用したキーによる削除をサポートしています。

HybridCache には、byte[] の割り当てを回避するために、IDistributedCache 実装用の省略可能な API も用意されています。 この機能は、Microsoft.Extensions.Caching.StackExchangeRedis および Microsoft.Extensions.Caching.SqlServer パッケージのプレビュー バージョンによって実装されます。

シリアル化は、サービスの登録の一環として構成され、AddHybridCache 呼び出しからチェーンされる WithSerializer および .WithSerializerFactory メソッドを介した型固有シリアライザーと汎用シリアライザーがサポートされます。 既定では、このライブラリによって stringbyte[] が内部的に処理され、その他すべてに System.Text.Json が使用されますが、protobuf、xml またはその他を使用することもできます。

HybridCache は、.NET Framework 4.7.2 および .NET Standard 2.0 までの古い .NET ランタイムをサポートしています。

HybridCache に関する詳細については、「ASP.NET Core の HybridCache ライブラリ」を参照してください

開発者例外ページの機能強化

ASP.NET Core 開発者例外ページ は、開発中にアプリがハンドルされない例外をスローすると、表示されます。 開発者例外ページには、例外と要求に関する詳細な情報が表示されます。

プレビュー 3 では、開発者例外ページにエンドポイント メタデータが追加されました。 ASP.NET Core では、エンドポイント メタデータを使用して、ルーティング、応答キャッシュ、レート制限、OpenAPI 生成などのエンドポイント動作を制御します。 次の画像は、開発者例外ページの Routing セクションの新しいメタデータ情報を示しています。

開発者例外ページの新しいメタデータ情報

開発者例外ページのテスト中に、小幅の質の向上が確認されました。 これらは、プレビュー 4 で提供されています。

  • テキスト折り返しの改善。 長い cookie、クエリ文字列の値、メソッド名にブラウザーの水平スクロール バーが追加されなくなりました。
  • 最新のデザインで使用されている、より大きなテキスト。
  • より一貫性のあるテーブル サイズ。

次のアニメーション画像は、新しい開発者例外ページを示しています。

新しい開発者例外ページ

ディクショナリのデバッグの機能強化

ディクショナリやその他のキー値コレクションのデバッグ表示のレイアウトが改善されました。 キーは、値と連結されるのではなく、デバッガーのキー列に表示されます。 次の図に、デバッガーでのディクショナリの新旧の表示を示します。

以前:

以前のデバッガー エクスペリエンス

以後:

新しいデバッガー エクスペリエンス

ASP.NET Core には、多くのキー値コレクションがあります。 この改善されたデバッグ エクスペリエンスは、次に適用されます。

  • HTTP ヘッダー
  • クエリ文字列
  • フォーム
  • Cookies
  • データの表示
  • ルート データ
  • 機能

IIS でのアプリのリサイクル中の 503 の修正

既定では現在、IIS にリサイクルまたはシャットダウンが通知されてから、ANCM がマネージド サーバーにシャットダウンを開始するよう指示するまでに 1 秒の遅延があります。 遅延は、ANCM_shutdownDelay 環境変数または shutdownDelay ハンドラー設定を使用して構成できます。 どちらの値もミリ秒単位です。 遅延は主に、次の場合のレースの可能性を減らすためです。

  • IIS が、新しいアプリへの要求のキューを開始していません。
  • ANCM が、古いアプリに入ってくる新しい要求の拒否を開始します。

CPU 使用率が高いマシンやマシンの速度が低下する場合は、この値を調整して 503 の可能性を減らすことができます。

shutdownDelay の設定の例:

<aspNetCore processPath="dotnet" arguments="myapp.dll" stdoutLogEnabled="false" stdoutLogFile=".logsstdout">
  <handlerSettings>
    <!-- Milliseconds to delay shutdown by.
    this doesn't mean incoming requests will be delayed by this amount,
    but the old app instance will start shutting down after this timeout occurs -->
    <handlerSetting name="shutdownDelay" value="5000" />
  </handlerSettings>
</aspNetCore>

この修正は、ホスティング バンドルから取得され、グローバルにインストールされた ANCM モジュール内にあります。

静的 Web アセットの配信の最適化

高パフォーマンスの Web アプリを作成するには、ブラウザーへのアセット配信を最適化する必要があります。 これには、次のような多くの側面が含まれます。

MapStaticAssets は、アプリ内の静的アセットの配信を最適化するのに役立つ新しいミドルウェアです。 これは、Blazor、Razor Pages、MVC など、すべての UI フレームワークで動作するように設計されています。 これは通常、UseStaticFiles のドロップイン置換です。

MapStaticAssets は、ビルドおよび発行時のプロセスを組み合わせて動作することで、アプリ内のすべての静的リソースに関する情報を収集します。 この情報は、これらのファイルをブラウザーに効率的に提供するために、ランタイム ライブラリによって利用されます。

MapStaticAssets は、ほとんどの状況で UseStaticFiles を置き換えることができます。ただし、ビルドおよび発行時にアプリが認識しているアセットを提供するために最適化されています。 アプリがディスクや埋め込みリソースなど、他の場所からアセットを提供する場合は、UseStaticFiles を使用する必要があります。

MapStaticAssets には、UseStaticFiles にはない次のような利点があります。

  • アプリ内のすべてのアセットのビルド時の圧縮:
    • 開発中は gzip、発行中は gzip + brotli です。
    • すべてのアセットは、アセットのサイズを最小限に抑えることを目標に圧縮されます。
  • コンテンツ ベースの ETags: 各リソースの Etags は、コンテンツの SHA-256 ハッシュの Base64 エンコードされた文字列です。 これにより、ブラウザーがファイルを再ダウンロードするのは、その内容が変更された場合のみになります。

次の表は、既定の Razor Pages テンプレートの CSS および JS ファイルの元のサイズと圧縮されたサイズを示しています。

ファイル オリジナル Compressed % 削減
bootstrap.min.css 163 17.5 89.26%
jquery.js 89.6 28 68.75%
bootstrap.min.js 78.5 20 74.52%
合計 331.1 65.5 80.20%

次の表は、Fluent UI Blazor コンポーネント ライブラリを使用した場合の元のサイズと圧縮されたサイズを示しています。

ファイル オリジナル Compressed % 削減
fluent.js 384 73 80.99%
fluent.css 94 11 88.30%
合計 478 84 82.43%

合計で 478 KB の非圧縮サイズが 84 KB に圧縮されています。

次の表は、MudBlazorBlazor コンポーネント ライブラリを使用した場合の元のサイズと圧縮されたサイズを示しています。

ファイル オリジナル Compressed 削減
MudBlazor.min.css 541 37.5 93.07%
MudBlazor.min.js 47.4 9.2 80.59%
合計 588.4 46.7 92.07%

MapStaticAssets を使用すると、最適化が自動的に行われます。 新しい JavaScript や CSS などにより、ライブラリが追加または更新されると、アセットはビルドの一部として最適化されます。 最適化は、帯域幅が狭かったり接続の信頼性が低かったりすることがあるモバイル環境で特に役立ちます。

サーバー上での動的圧縮の有効化と MapStaticAssets の使用の比較

MapStaticAssets には、サーバー上での動的圧縮と比べて次のような利点があります。

  • サーバー固有の構成がないため、より簡単です。
  • アセットがビルド時に圧縮されるため、パフォーマンスがさらに高くなります。
  • 開発者は、アセットが最小サイズになるように、ビルド プロセス中により多くの時間を費やすことができます。

MudBlazor の圧縮を IIS の動的圧縮と MapStaticAssets の場合で比較した次の表について検討してください。

IIS gzip MapStaticAssets MapStaticAssets による削減
≅ 90 37.5 59%