次の方法で共有


ASP.NET Core Blazor のレンダー モード

この記事では、コンパイル時または実行時の Blazor Web App での Razor コンポーネントのレンダリングの制御について説明します。

このガイダンスは、スタンドアロン Blazor WebAssembly アプリには適用されません。 Blazor WebAssembly アプリは、クライアント側の WebAssembly ベースのランタイムを介してクライアント上でレンダリングのみを行い、レンダリング モードの概念はありません。 レンダリング モードが Blazor WebAssembly アプリのコンポーネントに適用されている場合、レンダリング モードの指定はコンポーネントのレンダリングに影響しません。

レンダー モード

Blazor Web App のすべてのコンポーネントは、レンダー モードを採用して、使用するホスティング モデル、レンダリング場所、対話型かどうかを判断します。

次の表は、Blazor Web App で Razor コンポーネントをレンダリングするために使用できるレンダー モードを示しています。 コンポーネントにレンダリング モードを適用するには、コンポーネント インスタンスまたはコンポーネント定義で @rendermode ディレクティブを使います。 この記事の後半では、レンダー モードのシナリオごとに例を示します。

名前 説明 レンダーの場所 Interactive
静的サーバー 静的サーバー側レンダリング (静的 SSR) [サーバー] いいえ
対話型サーバー Blazor Server を使用した対話型サーバー側レンダリング (対話型 SSR)。 [サーバー] はい
対話型 WebAssembly Blazor WebAssembly を使用したクライアント側レンダリング (CSR)†。 クライアント はい
対話型自動 最初に Blazor Server、その後 Blazor バンドルのダウンロード後の後続のアクセスに CSR を使用する、対話型 SSR。 サーバー、その後クライアント はい

†クライアント側レンダリング (CSR) は対話型と見なされます。 ""対話型" クライアント側レンダリング" と ""対話型" CSR" は業界や Blazor のドキュメントでは使用されません。

対話型コンポーネントではプリレンダリングが既定で有効になっています。 プリレンダリングの制御に関するガイダンスについては、この記事の後半で説明します。 クライアントとサーバーのレンダリングの概念に関する一般的な業界用語については、「ASP.NET Core Blazor の基礎」をご覧ください。

次の例では、いくつかの基本的な Razor コンポーネント機能を使用してコンポーネントのレンダー モードを設定する方法を示します。

レンダー モードの動作をローカルでテストするには、Blazor Web App プロジェクト テンプレートから作成されたアプリに次のコンポーネントを配置します。 アプリを作成するときに、ドロップダウン メニューからオプション (Visual Studio) を選択するか、CLI オプション (.NET CLI) を適用して、サーバー側とクライアント側の両方のインタラクティビティを有効にします。 Blazor Web App の作成方法に関するガイダンスについては、「ASP.NET Core Blazor 用のツール」を参照してください。

対話型レンダー モードのサポートを有効にする

Blazor Web App は、対話型レンダー モードをサポートするように構成する必要があります。 次の拡張機能は、アプリの作成時に Blazor Web App プロジェクト テンプレートから作成されたアプリに対して自動的に適用されます。 個々のコンポーネントは、アプリの Program ファイルでコンポーネント サービスとエンドポイントを構成した後、「レンダー モード」セクションに従ってレンダー モードを宣言する必要があります。

Razor コンポーネントのサービスは、AddRazorComponents を呼び出すことによって追加されます。

コンポーネント ビルダー拡張機能:

  • AddInteractiveServerComponents によって、対話型サーバー コンポーネントのレンダリングをサポートするサービスが追加されます。
  • AddInteractiveWebAssemblyComponents によって、対話型 WebAssembly コンポーネントのレンダリングをサポートするサービスが追加されます。

MapRazorComponents は使用可能なコンポーネントを検出し、アプリのルート コンポーネント (読み込む最初のコンポーネント) を特定します。これは既定では App コンポーネント (App.razor) です。

エンドポイント規則ビルダー拡張機能:

Note

次の例での API の配置に関する説明については、Blazor Web App プロジェクト テンプレートから生成されたアプリの Program ファイルを調べてください。 Blazor Web App の作成方法に関するガイダンスについては、「ASP.NET Core Blazor 用のツール」を参照してください。

例 1: 次の Program ファイルの API は、対話型 SSR を有効にするためのサービスと構成を追加します。

builder.Services.AddRazorComponents()
    .AddInteractiveServerComponents();
app.MapRazorComponents<App>()
    .AddInteractiveServerRenderMode();

例 2: 次の Program ファイルの API は、対話型 WebAssembly レンダリング モードを有効にするためのサービスと構成を追加します。

builder.Services.AddRazorComponents()
    .AddInteractiveWebAssemblyComponents();
app.MapRazorComponents<App>()
    .AddInteractiveWebAssemblyRenderMode();

例 3: 次の Program ファイルの API は、対話型サーバー、対話型 WebAssembly、対話型自動レンダリング モードを有効にするためのサービスと構成を追加します。

builder.Services.AddRazorComponents()
    .AddInteractiveServerComponents()
    .AddInteractiveWebAssemblyComponents();
app.MapRazorComponents<App>()
    .AddInteractiveServerRenderMode()
    .AddInteractiveWebAssemblyRenderMode();

Blazor は、Blazor WebAssembly ホスティング モデルを使用して、対話型 WebAssembly レンダリング モードを使用するコンポーネントをダウンロードして実行します。 これらのコンポーネントの Blazor WebAssembly ホスティングを設定するには、別のクライアント プロジェクトが必要です。 クライアント プロジェクトには、Blazor WebAssembly ホストのスタートアップ コードが含まれており、ブラウザーで実行するための .NET ランタイムを設定します。 Blazor Web App テンプレートでは、WebAssembly のインタラクティビティを有効にするオプションを選択すると、このクライアント プロジェクトが自動的に追加されます。 対話型 WebAssembly レンダリング モードを使用するコンポーネントは、クライアント プロジェクトからビルドする必要があるため、ダウンロードしたアプリ バンドルに含められます。

コンポーネント インスタンスにレンダー モードを適用する

コンポーネント インスタンスにレンダー モードを適用するには、コンポーネントが使用される場所の @rendermodeRazor ディレクティブ属性を使用します。

次の例では、対話型サーバー側レンダリング (対話型 SSR) が Dialog コンポーネント インスタンスに適用されます。

<Dialog @rendermode="InteractiveServer" />

Note

Blazor テンプレートには、より短い @rendermode 構文のためにアプリの _Imports ファイル (Components/_Imports.razor) の RenderMode の静的 using ディレクティブが含まれています。

@using static Microsoft.AspNetCore.Components.Web.RenderMode

上のディレクティブがない場合、コンポーネントは @rendermode 構文で静的な RenderMode クラスを指定する必要があります。

<Dialog @rendermode="RenderMode.InteractiveServer" />

また、カスタムの構成で直接インスタンス化されたカスタム レンダリング モード インスタンスを参照することもできます。 詳しくは、この記事で後述する「カスタムの短縮形レンダリング モード」セクションをご覧ください。

コンポーネント定義にレンダー モードを適用する

コンポーネントのレンダー モードを定義の一部として指定するには、@rendermodeRazor ディレクティブ とそれに対応するレンダー モード属性を使用します。

@page "..."
@rendermode InteractiveServer

コンポーネント定義にレンダー モードを適用することは、特定のページにレンダー モードを適用するときによく使用されます。 ルーティング可能なページは、そのページをレンダリングした Router コンポーネントと同じレンダリング モードを使用します。

技術的には、@rendermode は Razor "ディレクティブ" であり、Razor "ディレクティブ属性" でもあります。 セマンティクスは似ていますが、違いがあります。 @rendermode ディレクティブはコンポーネント定義に対するものなので、参照されるレンダリング モード インスタンスは静的である必要があります。 @rendermode ディレクティブ属性は、任意のレンダリング モード インスタンスを受け取ることができます。

Note

コンポーネント作成者は、コンポーネントの実装を特定のレンダー モードに結合しないようにする必要があります。 代わりに、コンポーネント作成者は通常、任意のレンダー モードまたはホスティング モデルをサポートするようにコンポーネントを設計する必要があります。 コンポーネントの実装では、実行されている場所 (サーバーまたはクライアント) に関する想定を回避し、静的にレンダリングするときは適切に品質を下げる必要があります。 コンポーネントが直接インスタンス化されていない場合 (ルーティング可能なページ コンポーネントなど)、またはすべてのコンポーネント インスタンスのレンダー モードを指定する場合は、コンポーネント定義でレンダー モードを指定することが必要になる場合があります。

アプリ全体にレンダリング モードを適用する

アプリ全体のレンダリング モードを設定するには、アプリのコンポーネント階層の、ルート コンポーネントではない最上位の対話型コンポーネントで、レンダリング モードを指定します。

Note

ルート コンポーネントを対話型にすること (App コンポーネントなど) はサポートされていません。 そのため、アプリ全体のレンダリング モードを App コンポーネントで直接設定することはできません。

Blazor Web App プロジェクト テンプレートに基づくアプリの場合、アプリ全体に割り当てられるレンダリング モードは、通常、App コンポーネント (Components/App.razor) で Routes コンポーネントが使われる場所で指定されます。

<Routes @rendermode="InteractiveServer" />

Router コンポーネントは、ルーティングするページに自身のレンダー モードを伝達します。

また、通常は、HeadOutlet コンポーネントで同じインタラクティブ レンダー モードを設定する必要があります。これは、プロジェクト テンプレートから生成された Blazor Web App の App コンポーネントにも含まれます。

<HeadOutlet @rendermode="InteractiveServer" />

対話型クライアント側 (WebAssembly または自動) レンダリング モードを採用し、Routes コンポーネントを介してアプリ全体でレンダリング モードを有効にするアプリの場合:

  • サーバー アプリの Components/Layout フォルダーにあるレイアウト ファイルとナビゲーション ファイルを、.Client プロジェクトの Layout フォルダーに配置または移動します。 .Client プロジェクトに Layout フォルダーが存在しない場合は作成します。
  • サーバー アプリの Components/Pages フォルダーにあるコンポーネントを、.Client プロジェクトの Pages フォルダーに配置または移動します。 .Client プロジェクトに Pages フォルダーが存在しない場合は作成します。
  • サーバー アプリの Components フォルダーにある Routes コンポーネントを、.Client プロジェクトのルート フォルダーに配置または移動します。

Blazor Web App の作成時にグローバルな対話機能を有効にするには:

  • Visual Studio: [Interactivity location] (対話機能の場所) ドロップダウン リストを [グローバル] に設定します。
  • .NET CLI: -ai|--all-interactive オプションを使います。

詳しくは、「ASP.NET Core Blazor 用のツール」をご覧ください。

プログラムでレンダリング モードを適用する

プロパティとフィールドで、レンダー モードを割り当てることができます。

このセクションで説明する 2 つ目のアプローチでは、コンポーネント インスタンスごとにレンダリング モードを設定します。これは、グローバル対話型アプリで 1 つ以上のコンポーネントに静的 SSR を採用する必要があるアプリ仕様の場合に特に便利です。 このシナリオについては、この記事の後半の「グローバル対話型アプリの静的 SSR ページ」セクションで取り上げます。

コンポーネント定義でレンダー モードを設定する

コンポーネントの定義では、プライベート フィールドを使ってレンダリング モードを定義できます。

@rendermode pageRenderMode

...

@code {
    private static IComponentRenderMode pageRenderMode = InteractiveServer;
}

コンポーネント インスタンスでレンダー モードを設定する

次の例では、すべての要求に対して対話型サーバー側レンダリング (対話型 SSR) を適用しています。

<Routes @rendermode="PageRenderMode" />

...

@code {
    private IComponentRenderMode? PageRenderMode => InteractiveServer;
}

レンダリング モードの伝達について詳しくは、この記事の後半の「レンダー モードの伝達」セクションをご覧ください。 「グローバル対話型アプリの静的 SSR ページ」セクションでは、前のアプローチを使用してグローバル対話型アプリで静的 SSR を採用する方法を示しています。

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

ComponentBase.RendererInfoComponentBase.AssignedRenderMode プロパティを使用すると、アプリはコンポーネントの場所、対話機能、および割り当てられたレンダリング モードに関する詳細を検出できます。

  • RendererInfo.Name は、コンポーネントが実行されている場所を返します。
    • Static: サーバー (SSR) 上にあり、対話はできません。
    • Server: サーバー (SSR) 上にあり、プリレンダリング後に対話できます。
    • WebAssembly: クライアント (CSR) 上にあり、プリレンダリング後に対話できます。
    • WebView: ネイティブ デバイス上にあり、プリレンダリング後に対話できます。
  • RendererInfo.IsInteractive は、レンダリング時にコンポーネントが対話機能をサポートしているかどうかを示します。 値は、対話的にレンダリングする場合は true、プリレンダリングまたは静的 SSR (RendererInfo.NameStatic) の場合は false になります。
  • ComponentBase.AssignedRenderMode は、コンポーネントの割り当てられたレンダリング モードを公開します。
    • Interactive Server の場合 InteractiveServer
    • Interactive Auto の場合 InteractiveAuto
    • Interactive WebAssembly の場合 InteractiveWebAssembly

コンポーネントは、これらのプロパティを使用して、場所や対話機能の状態に応じてコンテンツをレンダリングします。 たとえば、プリレンダリング中にフォームを無効にし、コンポーネントが対話型になったときに有効にすることができます。

<EditForm Model="Movie" ...>
    <fieldset disabled="@disabled">

        ...

        <button type="submit" >Save</button>
    </fieldset>
</EditForm>

@code {
    private bool disabled = true;

    [SupplyParameterFromForm]
    private Movie? Movie { get; set; }

    protected override async Task OnInitializedAsync()
    {
        Movie ??= await ...;

        if (RendererInfo.IsInteractive)
        {
            disabled = false;
        }
    }
}

次の例では、コンポーネントが静的にレンダリングされる場合に、通常の HTML アクションの実行をサポートするようにマークアップをレンダリングする方法を示します。

@if (AssignedRenderMode is null)
{
    // The render mode is Static Server
    <form action="/movies">
        <input type="text" name="titleFilter" />
        <input type="submit" value="Search" />
    </form>
}
else
{
    // The render mode is Interactive Server, WebAssembly, or Auto
    <input @bind="titleFilter" />
    <button @onclick="FilterMovies">Search</button>
}

前の例の場合:

  • AssignedRenderMode の値が null の場合、コンポーネントは静的 SSR を採用します。 Blazor イベント処理は、静的 SSR を使用するブラウザーでは機能しないため、コンポーネントは、ユーザーの <input> 値に設定された titleFilter クエリ文字列を含むフォーム (GET 要求) を送信します。 Movie コンポーネント (/movie) は、クエリ文字列を読み取り、titleFilter の値を処理して、フィルター処理された結果でコンポーネントをレンダリングできます。
  • それ以外の場合、レンダリング モードは、InteractiveServerInteractiveWebAssembly、または InteractiveAuto のいずれかです。 コンポーネントは、イベント ハンドラー デリゲート (FilterMovies) と <input> 要素 (titleFilter) にバインドされた値を使用して、バックグラウンド SignalR 接続経由でムービーを対話的にフィルター処理できます。

Blazor Web App の Blazor ドキュメントの例

Blazor Web App を使用する場合、Blazor ドキュメントのほとんどのサンプル コンポーネントを機能させ、記事で説明されている概念を実証するには、インタラクティビティが必要です。 記事で提供されているサンプル コンポーネントをテストする場合は、アプリがグローバル インタラクティビティを採用しているか、コンポーネントが対話型レンダリング モードを採用していることを確認してください。

プリレンダリング

プリレンダリングは、レンダリングされたコントロールのイベント ハンドラーを有効にせずに、最初にサーバーにページ コンテンツをレンダリングするプロセスです。 サーバーは、最初の要求に応じてできるだけ早くページの HTML UI を出力します。これにより、アプリはユーザーに対してより応答性が高くなります。 プリレンダリングでは、検索エンジンによってページ ランクの計算に使用される初期 HTTP 応答のコンテンツをレンダリングすることで、検索エンジンの最適化 (SEO) を向上させることもできます。

対話型コンポーネントではプリレンダリングが既定で有効になっています。

対話型ルーティングの内部ナビゲーションでは、サーバーに新しいページ コンテンツを要求する必要はありません。 そのため、内部ページ要求 (拡張ナビゲーションの場合を含む) では、プリレンダリングは行われません。 詳細については、「静的ルーティングと対話型ルーティング」、「対話型ルーティングとプリレンダリング」、「ナビゲーションとフォーム処理の強化」を参照してください。

次の手法を使用したプリレンダリングの無効化は、最上位レベルのレンダリング モードでのみ効果があります。 親コンポーネントでレンダリング モードが指定されている場合、その子のプリレンダリング設定は無視されます。 この動作は、2025 年 11 月の .NET 10 リリースで考えられる変更について調査中です。

"コンポーネント インスタンス" のプリレンダリングを無効にするには、値が falseprerender フラグを、レンダリング モードに渡します。

  • <... @rendermode="new InteractiveServerRenderMode(prerender: false)" />
  • <... @rendermode="new InteractiveWebAssemblyRenderMode(prerender: false)" />
  • <... @rendermode="new InteractiveAutoRenderMode(prerender: false)" />

"コンポーネント定義" でプリレンダリングを無効にするには:

  • @rendermode @(new InteractiveServerRenderMode(prerender: false))
  • @rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))
  • @rendermode @(new InteractiveAutoRenderMode(prerender: false))

アプリ全体でプリレンダリングを無効にするには、アプリのコンポーネント階層の、ルート コンポーネントではない最上位の対話型コンポーネントで、レンダリング モードを指定します。

Blazor Web App プロジェクト テンプレートに基づくアプリの場合、アプリ全体に割り当てられるレンダリング モードは、App コンポーネント (Components/App.razor) で Routes コンポーネントが使われる場所で指定されます。 次の例では、プリレンダリングを無効にして、アプリのレンダリング モードを対話型サーバーに設定しています。

<Routes @rendermode="new InteractiveServerRenderMode(prerender: false)" />

また、App コンポーネントの HeadOutletコンポーネント のプリレンダリングを無効にします:

<HeadOutlet @rendermode="new InteractiveServerRenderMode(prerender: false)" />

ルート コンポーネント (App コンポーネントなど) をルート コンポーネントの定義ファイル (.razor) の先頭にある @rendermode ディレクティブと対話形式にすることはサポートされていません。 そのため、プリレンダリングを App コンポーネントで直接無効にすることはできません。

静的サーバー側レンダリング (静的 SSR)

コンポーネントは静的サーバー側レンダリング (静的 SSR) を使用します。 コンポーネントが応答ストリームにレンダリングされ、インタラクティビティは有効になっていません。

次の例では、コンポーネントのレンダリング モードの指定はなく、コンポーネントはその親からレンダリング モードを継承します。 先祖コンポーネントがレンダリング モードを指定していないため、次のコンポーネントはサーバー上で静的にレンダリングされます。 ボタンはインタラクティブではなく、選択された場合に UpdateMessage メソッドを呼び出しません。 message の値は変更されず、コンポーネントは UI イベントに応答して再レンダリングされません。

RenderMode1.razor:

@page "/render-mode-1"

<button @onclick="UpdateMessage">Click me</button> @message

@code {
    private string message = "Not updated yet.";

    private void UpdateMessage()
    {
        message = "Somebody updated me!";
    }
}

上記のコンポーネントを Blazor Web App でローカルで使用する場合は、サーバー プロジェクトの Components/Pages フォルダーにコンポーネントを配置します。 サーバー プロジェクトはソリューションのプロジェクトであり、名前の末尾が .Client ではありません。 アプリが実行されている場合は、ブラウザーのアドレス バーで /render-mode-1 に移動します。

静的 SSR である間、Razor コンポーネント ページ要求は、サーバー側の ASP.NET Core ミドルウェア パイプライン要求の処理によって、ルーティングと承認のために処理されます。 Razor コンポーネントはサーバー側の要求の処理中にレンダリングされないため、ルーティングと承認のための専用の Blazor 機能は動作しません。 静的 SSR である間に使用できない Routes コンポーネントの Blazor ルーター機能には、次のような表示が含まれます。

アプリがルートレベルの対話機能を示す場合、サーバー側の ASP.NET Core 要求の処理は最初の静的 SSR の後に関与しません。つまり、上記の Blazor 機能は期待どおりに動作します。

静的 SSR による拡張ナビゲーションでは、JavaScript を読み込むときに特別な注意が必要です。 詳細については、「静的サーバー側レンダリング (静的 SSR) を使用した ASP.NET Core Blazor JavaScript」を参照してください。

対話型サーバー側レンダリング (対話型 SSR)

対話型サーバー側レンダリング (対話型 SSR) では、Blazor Server を使用して、サーバーからコンポーネントが対話形式でレンダリングされます。 ユーザー操作は、ブラウザーとのリアルタイム接続を介して処理されます。 サーバー コンポーネントがレンダリングされると、回線接続が確立されます。

次の例では、コンポーネント定義に @rendermode InteractiveServer を追加することで、レンダリング モードが対話型 SSR に設定されています。 このボタンを選択すると、UpdateMessage メソッドが呼び出されます。 message の値が変更され、コンポーネントが再レンダリングされて UI 内のメッセージが更新されます。

RenderMode2.razor:

@page "/render-mode-2"
@rendermode InteractiveServer

<button @onclick="UpdateMessage">Click me</button> @message

@code {
    private string message = "Not updated yet.";

    private void UpdateMessage()
    {
        message = "Somebody updated me!";
    }
}

上記のコンポーネントを Blazor Web Appで使用する場合は、サーバー プロジェクトの Components/Pages フォルダーにコンポーネントを配置します。 サーバー プロジェクトはソリューションのプロジェクトであり、名前の末尾が .Client ではありません。 アプリが実行されている場合は、ブラウザーのアドレス バーで /render-mode-2 に移動します。

クライアント側レンダリング (CSR)

クライアント側レンダリング (CSR) では、Blazor WebAssembly を使用してコンポーネントがクライアント上で対話形式でレンダリングされます。 WebAssembly コンポーネントが最初にレンダリングされるときに、.NET ランタイムとアプリ バンドルがダウンロードされ、キャッシュされます。 CSR を使用するコンポーネントは、Blazor WebAssembly ホストを設定する別のクライアント プロジェクトからビルドする必要があります。

次の例では、@rendermode InteractiveWebAssembly を使用してレンダリング モードが CSR に設定されています。 このボタンを選択すると、UpdateMessage メソッドが呼び出されます。 message の値が変更され、コンポーネントが再レンダリングされて UI 内のメッセージが更新されます。

RenderMode3.razor:

@page "/render-mode-3"
@rendermode InteractiveWebAssembly

<button @onclick="UpdateMessage">Click me</button> @message

@code {
    private string message = "Not updated yet.";

    private void UpdateMessage()
    {
        message = "Somebody updated me!";
    }
}

上記のコンポーネントを Blazor Web App でローカルで使用する場合は、クライアント プロジェクトの Pages フォルダーにコンポーネントを配置します。 クライアント プロジェクトはソリューションのプロジェクトであり、名前の末尾が .Client です。 アプリが実行されている場合は、ブラウザーのアドレス バーで /render-mode-3 に移動します。

自動 (Auto) レンダリング

自動 (Auto) レンダリングでは、実行時にコンポーネントをレンダリングする方法が決まります。 コンポーネントは、最初は、Blazor Server ホスティング モデルを使用して、対話型サーバー側レンダリング (対話型 SSR) でレンダリングされます。 .NET ランタイムとアプリ バンドルがバックグラウンドでクライアントにダウンロードされ、キャッシュされるため、以降のアクセスで使用できます。

自動レンダリング モードでは、ページに既に存在するコンポーネントのレンダリング モードが動的に変更されることはありません。 自動レンダリング モードは、コンポーネントでどの種類のインタラクティビティが使われるかを最初に決定して、その後、コンポーネントがページ上にある限りその種類のインタラクティビティが維持されます。 この最初の決定における 1 つの要素は、WebAssembly/サーバーのインタラクティビティを備えたコンポーネントがページ上に既に存在するかどうかを考慮することです。 自動モードでは、既存の対話型コンポーネントのレンダリング モードと一致するレンダリング モードが優先的に選ばれます。 自動モードが既存のインタラクティビティ モードの使用を優先する理由は、既存のランタイムと状態を共有しない新しい対話型ランタイムの導入を避けるためです。

自動レンダー モードを使用するコンポーネントは、Blazor WebAssembly ホストを設定する別のクライアント プロジェクトからビルドする必要があります。

次の例では、コンポーネントはプロセス全体を通してインタラクティブです。 このボタンを選択すると、UpdateMessage メソッドが呼び出されます。 message の値が変更され、コンポーネントが再レンダリングされて UI 内のメッセージが更新されます。 最初は、コンポーネントはサーバーからインタラクティブにレンダリングされますが、その後のアクセスでは、.NET ランタイムとアプリ バンドルがダウンロードされてキャッシュされた後にクライアントからレンダリングされます。

RenderMode4.razor:

@page "/render-mode-4"
@rendermode InteractiveAuto

<button @onclick="UpdateMessage">Click me</button> @message

@code {
    private string message = "Not updated yet.";

    private void UpdateMessage()
    {
        message = "Somebody updated me!";
    }
}

上記のコンポーネントを Blazor Web App でローカルで使用する場合は、クライアント プロジェクトの Pages フォルダーにコンポーネントを配置します。 クライアント プロジェクトはソリューションのプロジェクトであり、名前の末尾が .Client です。 アプリが実行されている場合は、ブラウザーのアドレス バーで /render-mode-4 に移動します。

レンダー モードの伝達

レンダー モードは、コンポーネント階層の下に伝達されます。

レンダー モードを適用するためのルール:

  • 既定のレンダー モードは静的です。
  • 対話型サーバー、(InteractiveServer)、対話型 WebAssembly (InteractiveWebAssembly)、対話型自動 (InteractiveAuto) の各レンダリング モードは、コンポーネントから使用でき、兄弟コンポーネントに異なるレンダリング モードを使用することもできます。
  • 子コンポーネントで別のインタラクティブ レンダー モードに切り替えることはできません。 たとえば、サーバー コンポーネントを WebAssembly コンポーネントの子にすることはできません。
  • 静的な親からインタラクティブな子コンポーネントに渡されるパラメーターは、JSON シリアル化可能である必要があります。 つまり、静的な親コンポーネントからインタラクティブな子コンポーネントにレンダー フラグメントや子コンテンツを渡すことはできません。

次の例では、ルーティング不可能な非ページ SharedMessage コンポーネントを使用しています。 レンダー モードに依存しない SharedMessage コンポーネントでは、@attribute ディレクティブによるレンダー モードは適用されません。 Blazor Web App でこれらのシナリオをテストする場合は、アプリの Components フォルダーに次のコンポーネントを配置します。

SharedMessage.razor:

<p>@Greeting</p>

<button @onclick="UpdateMessage">Click me</button> @message

<p>@ChildContent</p>

@code {
    private string message = "Not updated yet.";

    [Parameter]
    public RenderFragment? ChildContent { get; set; }

    [Parameter]
    public string Greeting { get; set; } = "Hello!";

    private void UpdateMessage()
    {
        message = "Somebody updated me!";
    }
}

レンダー モードの継承

SharedMessage コンポーネントが静的にレンダリングされる親コンポーネントに配置されている場合、SharedMessage コンポーネントも静的にレンダリングされ、インタラクティブではありません。 ボタンは UpdateMessage を呼び出さず、メッセージは更新されません。

RenderMode5.razor:

@page "/render-mode-5"

<SharedMessage />

SharedMessage コンポーネントがレンダー モードを定義するコンポーネントに配置されている場合、適用されたレンダー モードが継承されます。

次の例では、SharedMessage コンポーネントはクライアントへの SignalR 接続でインタラクティブです。 ボタンが UpdateMessage を呼び出し、メッセージが更新されます。

RenderMode6.razor:

@page "/render-mode-6"
@rendermode InteractiveServer

<SharedMessage />

レンダー モードが異なる子コンポーネント

次の例では、SharedMessage コンポーネントの両方がプリレンダリングされ、ページがブラウザーに表示されるときに表示されます。

  • 対話型サーバー側レンダリング (対話型 SSR) を使用する最初の SharedMessage コンポーネントは、SignalR 回線が確立された後に対話型になります。
  • クライアント側レンダリング (CSR) を使用する 2 つ目の SharedMessage コンポーネントは、Blazor アプリ バンドルがダウンロードされ、.NET ランタイムがクライアントでアクティブになった "後" に対話型になります。

RenderMode7.razor:

@page "/render-mode-7"

<SharedMessage @rendermode="InteractiveServer" />
<SharedMessage @rendermode="InteractiveWebAssembly" />

シリアル化可能なパラメーターを持つ子コンポーネント

次の例では、パラメーターを受け取るインタラクティブな子コンポーネントを示しています。 パラメーターはシリアル化可能である必要があります。

RenderMode8.razor:

@page "/render-mode-8"

<SharedMessage @rendermode="InteractiveServer" Greeting="Welcome!" />

子コンテンツやレンダリング フラグメントなどのシリアル化不可能なコンポーネント パラメーターはサポートされていません。 次の例では、子コンテンツを SharedMessage コンポーネントに渡すことで、ランタイム エラーが発生します。

RenderMode9.razor:

@page "/render-mode-9"

<SharedMessage @rendermode="InteractiveServer">
    Child content
</SharedMessage>

エラー:

System.InvalidOperationException: rendermode 'InteractiveServerRenderMode' を使って、パラメーター 'ChildContent' をコンポーネント 'SharedMessage' に渡すことはできません。 これは、パラメーターがデリゲート型 'Microsoft.AspNetCore.Components.RenderFragment' であるためです。これは任意のコードであり、シリアル化できません。

上記の制限を回避するには、パラメーターを持たない別のコンポーネントで子コンポーネントをラップします。 これは、Router コンポーネントをラップするために Routes コンポーネント (Components/Routes.razor) を使用する Blazor Web App プロジェクト テンプレートで利用されるアプローチです。

WrapperComponent.razor:

<SharedMessage>
    Child content
</SharedMessage>

RenderMode10.razor:

@page "/render-mode-10"

<WrapperComponent @rendermode="InteractiveServer" />

前の例の場合:

  • 子コンテンツは SharedMessage コンポーネントに渡され、ランタイム エラーは生成されません。
  • SharedMessage コンポーネントは、サーバー上でインタラクティブにレンダリングされます。

親と異なるレンダー モードを持つ子コンポーネント

子コンポーネントに対して、親のレンダー モードとは異なるインタラクティブ レンダー モードを適用しないでください。

次のコンポーネントでは、コンポーネントのレンダリング時にランタイム エラーが発生します。

RenderMode11.razor:

@page "/render-mode-11"
@rendermode InteractiveServer

<SharedMessage @rendermode="InteractiveWebAssembly" />

エラー:

Cannot create a component of type 'BlazorSample.Components.SharedMessage' because its render mode 'Microsoft.AspNetCore.Components.Web.InteractiveWebAssemblyRenderMode' is not supported by Interactive Server rendering.

グローバル対話型アプリの静的 SSR ページ

アプリの仕様により、静的サーバー側レンダリング (静的 SSR) を採用し、サーバー上でのみ実行することが求められる一方で、アプリの rest では対話型レンダー モードが使用される場合があります。

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

@attributeRazor ディレクティブで割り当てられた[ExcludeFromInteractiveRouting]属性を持つ任意のRazor コンポーネント ページをマークします。

@attribute [ExcludeFromInteractiveRouting]

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

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

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

<!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;
}

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

レンダー モードを細かく制御するには 2 つの方法があります。それぞれについて、次のサブセクションで説明します。

  • 静的 SSR コンポーネントの領域 (フォルダー): 静的 SSR を採用し、同じルート パス プレフィックスを共有する必要があるコンポーネントを含むアプリの領域 (フォルダー) があります。 アプリは、フォルダーへのパスに基づいて App コンポーネント内の Routes コンポーネントにレンダー モードを設定することで、レンダー モードをグローバルに制御します。

  • アプリ全体に分散した静的 SSR コンポーネント: 静的 SSR を採用し、サーバー上でのみ実行する必要があるコンポーネントが、アプリの周囲のさまざまな場所に分散しています。 静的 SSR 専用のコンポーネントは 1 つのフォルダーに含まれておらず、共通のルート パス プレフィックスを共有していません。 アプリは、コンポーネント インスタンスの @rendermode ディレクティブを使用してレンダー モードを設定することで、コンポーネントごとにレンダー モードを制御します。 App コンポーネントでリフレクションを使用して、Routes コンポーネントのレンダー モードを設定します。

どちらの場合も、静的 SSR を採用する必要があるコンポーネントは、ページ全体の再読み込みも強制する必要があります。

次の例では、HttpContext カスケード パラメーターを使用して、ページが静的にレンダリングされているかどうかを判断します。 null HttpContext は、コンポーネントが対話形式でレンダリングされていることを示します。これは、ページ全体の再読み込みをトリガーするアプリ コードのシグナルとして役立ちます。

静的 SSR コンポーネントの領域 (フォルダー)

このサブセクションで説明する方法は、個々の認証とグローバル対話機能を使用して Blazor Web App プロジェクト テンプレートによって使用されます。

アプリの領域 (フォルダー) には、静的 SSR を採用し、サーバーでのみ実行する必要があるコンポーネントが含まれています。 フォルダー内のコンポーネントは、同じルート パス プレフィックスを共有します。 たとえば、Blazor Web App プロジェクト テンプレートの IdentityRazor コンポーネントはComponents/Account/Pages フォルダー内にあり、ルート パス プレフィックス /Account を共有します。

このフォルダーには、フォルダー内のコンポーネントにカスタム アカウント レイアウトを適用する _Imports.razor ファイルも含まれています。

@using BlazorSample.Components.Account.Shared
@layout AccountLayout

Shared フォルダーには AccountLayout レイアウト コンポーネントが保持されています。 このコンポーネントは、HttpContext を使用して、コンポーネントが静的 SSR を採用しているかどうかを判断します。 Identity コンポーネントは Identity Cookie を設定しているため、静的 SSR を使用してサーバー上にレンダリングする必要があります。 HttpContext の値が null の場合、コンポーネントは対話形式でレンダリングされ、forceLoadtrue に設定して NavigationManager.Refresh を呼び出すことによってページ全体の再読み込みが実行されます。 これにより、静的 SSR を使用してページの完全な再レンダリングが強制されます。

Components/Account/Shared/AccountLayout.razor:

@inherits LayoutComponentBase
@layout BlazorSample.Components.Layout.MainLayout
@inject NavigationManager Navigation

@if (HttpContext is null)
{
    <p>Loading...</p>
}
else
{
    @Body
}

@code {
    [CascadingParameter]
    private HttpContext? HttpContext { get; set; }

    protected override void OnParametersSet()
    {
        if (HttpContext is null)
        {
            Navigation.Refresh(forceReload: true);
        }
    }
}

Note

Blazor Web App プロジェクト テンプレートには、Components/Account/Pages/Manage フォルダー内の Identity コンポーネント用の 2 つ目のレイアウト ファイル (Components/Account/Shared フォルダー内の ManageLayout.razor) があります。 Manage フォルダーには、フォルダー内の ManageLayout コンポーネントに適用する独自の _Imports.razor ファイルがあります。 独自のアプリで、入れ子になった _Imports.razor ファイルを使用すると、ページのグループにカスタム レイアウトを適用する際に便利です。

App コンポーネントでは、Account フォルダー内のコンポーネントに対するすべての要求で null レンダー モードが適用され、静的 SSR が強制されます。 その他のコンポーネント要求は、対話型 SSR レンダー モード (InteractiveServer) のグローバル アプリケーションを受け取ります。

重要

null レンダー モードを適用しても、必ずしも静的 SSR が強制されるわけではありません。 このセクションに示す方法を使用して、そのように動作しているだけです。

null レンダー モードは、レンダリング モードを指定しない場合と実質的に同じであり、その結果、コンポーネントは親のレンダー モードを継承します。 この場合、App コンポーネントは静的 SSR を使用してレンダリングされるため、null レンダー モードの結果、Routes コンポーネントは App コンポーネントから 静的 SSR を継承します。 親が対話型レンダー モードを使用する子コンポーネントに対して null レンダー モードが指定されている場合、子は同じ対話型レンダリング モードを継承します。

Components/App.razor:

<Routes @rendermode="RenderModeForPage" />

...

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

    private IComponentRenderMode? RenderModeForPage => 
        HttpContext.Request.Path.StartsWithSegments("/Account")
            ? null
            : {INTERACTIVE RENDER MODE};
}

前のコードでは、アプリケーションの rest でグローバル InteractiveServerInteractiveWebAssembly、または InteractiveAuto レンダリングを採用する必要があるかどうかに応じて、{INTERACTIVE RENDER MODE} プレースホルダーを適切な値に変更します。

Account フォルダーに静的 SSR を採用する必要があるコンポーネントは、_Imports.razor ファイルを介して適用されるレイアウトを設定する必要はありません。 このコンポーネントは静的 SSR でレンダリングする必要があるため、レンダリング モードを設定しません。 Account フォルダー内のコンポーネントで静的 SSR を適用するために、これ以上何も行う必要はありません。

アプリ全体に分散している静的 SSR コンポーネント

前のサブセクションでは、アプリが App コンポーネントでレンダー モードをグローバルに設定することで、コンポーネントのレンダー モードを制御していました。 また、App コンポーネントでは、レンダー モードを設定するために "コンポーネントごと" のレンダー モードを採用することもできます。これにより、コンポーネントをアプリの周囲に分散して静的 SSR の採用を強制できます。 このサブセクションでは、このアプローチについて説明します。

アプリには、アプリの周囲のコンポーネントに適用できるカスタム レイアウトがあります。 通常、アプリの共有コンポーネントは Components/Layout フォルダーに配置されます。 このコンポーネントは、HttpContext を使用して、コンポーネントが静的 SSR を採用しているかどうかを判断します。 HttpContext の値が null の場合、コンポーネントは対話形式でレンダリングされ、forceLoadtrue に設定して NavigationManager.Refresh を呼び出すことによってページ全体の再読み込みが実行されます。 これにより、コンポーネントについてのサーバーへの要求がトリガーされます。

Components/Layout/StaticSsrLayout.razor:

@inherits LayoutComponentBase
@layout MainLayout
@inject NavigationManager Navigation

@if (HttpContext is null)
{
    <p>Loading...</p>
}
else
{
    @Body
}

@code {
    [CascadingParameter]
    private HttpContext? HttpContext { get; set; }

    protected override void OnParametersSet()
    {
        if (HttpContext is null)
        {
            Navigation.Refresh(forceReload: true);
        }
    }
}

App コンポーネントでは、リフレクションを使用してレンダー モードを設定します。 個々のコンポーネント定義ファイルに割り当てられているレンダリング モードが、Routes コンポーネントに適用されます。

Components/App.razor:

<Routes @rendermode="RenderModeForPage" />

...

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

    private IComponentRenderMode? RenderModeForPage =>
        HttpContext.GetEndpoint()?.Metadata.GetMetadata<RenderModeAttribute>()?
            .Mode;
}

静的 SSR を採用する必要がある各コンポーネントは、カスタム レイアウトを設定し、レンダリング モードを指定しません。 レンダー モードを指定しないと、App コンポーネントの RenderModeAttribute.Mode 値が null となり、その結果、Routes コンポーネント インスタンスにレンダー モードが割り当てられず、静的 SSR が適用されます。

重要

null レンダー モードを適用しても、必ずしも静的 SSR が強制されるわけではありません。 このセクションに示す方法を使用して、そのように動作しているだけです。

null レンダー モードは、レンダリング モードを指定しない場合と実質的に同じであり、その結果、コンポーネントは親のレンダー モードを継承します。 この場合、App コンポーネントは静的 SSR を使用してレンダリングされるため、null レンダー モードの結果、Routes コンポーネントは App コンポーネントから 静的 SSR を継承します。 親が対話型レンダー モードを使用する子コンポーネントに対して null レンダー モードが指定されている場合、子は同じ対話型レンダリング モードを継承します。

静的 SSR を適用するために、対話型レンダリング モードを設定せずにカスタム レイアウトを適用する以外にコンポーネントに対して何も行う必要はありません。

@layout BlazorSample.Components.Layout.StaticSsrLayout

アプリの周囲の対話型コンポーネントは、カスタム静的 SSR レイアウトの適用を回避しApp コンポーネント内のリフレクション時に Routes コンポーネントに適用される適切な対話型レンダリング モードのみを設定します

@rendermode {INTERACTIVE RENDER MODE}

前のコードでは、コンポーネントで InteractiveServerInteractiveWebAssembly、または InteractiveAuto レンダリングを採用する必要があるかどうかに応じて、{INTERACTIVE RENDER MODE} プレースホルダーを適切な値に変更します。

プリレンダリング中にクライアント側サービスによる解決が失敗する

コンポーネントまたはアプリでプリレンダリングが無効になっていないとすると、.Client プロジェクト内のコンポーネントはサーバー上でプリレンダリングされます。 サーバーは登録されたクライアント側 Blazor サービスにアクセスできないため、これらのサービスをコンポーネントに挿入することはできず、プリレンダリング中にサービスが見つからないというエラーを受け取ります。

たとえば、グローバルな対話型 WebAssembly または対話型自動レンダリングを使用する、Blazor Web App の .Client プロジェクト内の次のような Home コンポーネントについて考えます。 このコンポーネントは、環境の名前を取得するために IWebAssemblyHostEnvironment を挿入しようとします。

@page "/"
@inject IWebAssemblyHostEnvironment Environment

<PageTitle>Home</PageTitle>

<h1>Home</h1>

<p>
    Environment: @Environment.Environment
</p>

コンパイル時エラーは発生しませんが、プリレンダリング中に実行時エラーが発生します。

型 'BlazorSample.Client.Pages.Home' のプロパティ 'Environment' の値を指定できません。 There is no registered service of type 'Microsoft.AspNetCore.Components.WebAssembly.Hosting.IWebAssemblyHostEnvironment'. ('Microsoft.AspNetCore.Components.WebAssembly.Hosting.IWebAssemblyHostEnvironment' 型の登録されたサービスはありません。)

このエラーは、コンポーネントはプリレンダリング中にサーバーでコンパイルおよび実行される必要がありますが、IWebAssemblyHostEnvironment はサーバー上の登録されたサービスでないために発生します。

プリレンダリング中にアプリで値が必要ない場合は、サービスの種類自体ではなく、IServiceProvider を挿入してサービスを取得することにより、この問題を解決できます。

@page "/"
@using Microsoft.AspNetCore.Components.WebAssembly.Hosting
@inject IServiceProvider Services

<PageTitle>Home</PageTitle>

<h1>Home</h1>

<p>
    <b>Environment:</b> @environmentName
</p>

@code {
    private string? environmentName;

    protected override void OnInitialized()
    {
        if (Services.GetService<IWebAssemblyHostEnvironment>() is { } env)
        {
            environmentName = env.Environment;
        }
    }
}

ただし、上の方法は、プリレンダリング中にロジックで値が必要な場合は役に立ちません。

また、コンポーネントのプリレンダリングを無効にした場合も問題を回避できますが、多くの場合はコンポーネントの仕様を満たしていない可能性があるときに取るべき非常手段です。

このシナリオに対処するために取ることができる 3 つの方法があります。 以下では、最も推奨されるものから順に示します。

  • 共有フレームワークのサービスで "推奨": 共有フレームワークのサービスがメイン プロジェクトのサーバー側に登録されていないだけの場合には、メイン プロジェクトにそのサービスを登録します。これにより、プリレンダリング中にサービスを利用できるようになります。 このシナリオの例については、「ASP.NET Core Blazor アプリから Web API を呼び出す」の HttpClient サービスのガイダンスを参照してください。

  • 共有フレームワークに含まれないサービスで "推奨": サーバー上のサービスに対するカスタム サービス実装を作成します。 通常は、.Client プロジェクトの対話型コンポーネントでそのサービスを使います。 この方法のデモについては、「ASP.NET Core Blazor の環境」をご覧ください。

  • サービスの抽象化を作成し、.Client とサーバーのプロジェクトでサービスの実装を作成します。 各プロジェクトでサービスを登録します。 カスタム サービスをコンポーネントに挿入します。

  • .Client プロジェクト パッケージの参照をサーバー側パッケージに追加し、サーバーでのプリレンダリング時にはサーバー側 API の使用にフォールバックできる場合があります。

追加アセンブリからコンポーネントを検出する

参照先のプロジェクトでルーティング可能な Razor コンポーネントを検出するには、追加のアセンブリを Blazor フレームワークに公開する必要があります。 詳細については、「ASP.NET Core の Blazor ルーティングとナビゲーション」を参照してください。

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

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

カスタムの短縮形レンダリング モード

@rendermode ディレクティブは、IComponentRenderMode 型の静的なインスタンスである 1 つのパラメーターを受け取ります。 @rendermode ディレクティブ属性は、静的かどうかに関係なく、任意のレンダリング モード インスタンスを受け取ることができます。 Blazor フレームワークには、便利な事前定義されたレンダリング モードをいくつか備えた RenderMode 静的クラスが用意されています、独自に作成することもできます。

通常、コンポーネントは次の @rendermode ディレクティブを使ってプリレンダリングを無効にします。

@rendermode @(new InteractiveServerRenderMode(prerender: false))

しかし、プリレンダリングを行わずに、アプリの _Imports ファイル (Components/_Imports.razor) を使って短縮形の対話型サーバー レンダリング モードを作成する次の例を考えてみます。

public static IComponentRenderMode InteractiveServerWithoutPrerendering { get; } = 
    new InteractiveServerRenderMode(prerender: false);

Components フォルダー全体のコンポーネントで、短縮形のレンダリング モードを使います。

@rendermode InteractiveServerWithoutPrerendering

または、1 つのコンポーネント インスタンスで、プライベート フィールドを使ってカスタム レンダリング モードを定義することもできます。

@rendermode interactiveServerWithoutPrerendering

...

@code {
    private static IComponentRenderMode interactiveServerWithoutPrerendering = 
        new InteractiveServerRenderMode(prerender: false);
}

現時点で、短縮形レンダリング モードのアプローチは、おそらく prerender フラグの詳細な指定を軽減するためにのみ役立ちます。 将来的に、対話型レンダリングで使用できるフラグが追加され、さまざまなフラグの組み合わせで短縮形レンダリング モードを作成できるようになれば、短縮形のアプローチの方が便利になる可能性があります。

最上位レベルのインポート ファイル (_Imports.razor) を使用したサービスの挿入

このセクションは Blazor Web App にのみ適用されます。

Components フォルダーにある最上位レベルのインポート ファイル (Components/_Imports.razor) によって、その参照がフォルダー階層内のすべてのコンポーネントに挿入されます。これには App コンポーネント (App.razor) が含まれます。 ページ コンポーネントのプリレンダリングが無効になっている場合でも、App コンポーネントは常に静的にレンダリングされます。 したがって、最上位レベルのインポート ファイルを介してサービスを挿入すると、ページ コンポーネントにおいてサービスの "2 つのインスタンス" が解決されます。

このシナリオに対処するには、Pages フォルダーに配置した新しいインポート ファイル (Components/Pages/_Imports.razor) でサービスを挿入します。 その場所から、サービスはページ コンポーネントにおいて 1 回だけ解決されます。

その他のリソース