注
これは、この記事の最新バージョンではありません。 現在のリリースについては、 この記事の .NET 10 バージョンを参照してください。
この記事では、コンパイル時または実行時の Razor での Blazor Web App コンポーネントのレンダリングの制御について説明します。
このガイダンスは、スタンドアロン Blazor WebAssembly アプリには適用されません。 Blazor WebAssembly アプリは、クライアント側の WebAssembly ベースのランタイムを介してクライアント上でレンダリングのみを行い、レンダリング モードの概念はありません。 レンダリング モードが Blazor WebAssembly アプリのコンポーネントに適用されている場合、レンダリング モードの指定はコンポーネントのレンダリングに影響しません。
レンダー モード
Blazor Web App のすべてのコンポーネントは、レンダー モードを採用して、使用するホスティング モデル、レンダリング場所、対話型かどうかを判断します。 Interactivity を使用すると、ユーザーはレンダリングされたコンポーネントを操作できます。 これには、Document Object Model (DOM) イベントに対するアプリの応答と、Blazorのイベント ハンドラーとバインドを介して C# メンバーに関連付けられた状態の変更が含まれます。
次の表は、Razor で Blazor Web App コンポーネントをレンダリングするために使用できるレンダー モードを示しています。 コンポーネントにレンダリング モードを適用するには、コンポーネント インスタンスまたはコンポーネント定義で @rendermode ディレクティブを使います。 この記事の後半では、レンダー モードのシナリオごとに例を示します。
| 名前 | 説明 | レンダリング場所 | インタラクティブ |
|---|---|---|---|
| 静的サーバー | 静的サーバー側レンダリング (静的 SSR) | [サーバー] | いいえ |
| 対話型サーバー | Blazor Server を使用した対話型サーバー側レンダリング (対話型 SSR)。 | [サーバー] | はい |
| 対話型 WebAssembly | Blazor WebAssembly を使用したクライアント側レンダリング (CSR)†。 | クライアント | はい |
| 対話型自動車 | 対話型SSRは、最初にBlazor Serverを使用し、Blazor バンドルがダウンロードされた後の後続のアクセスではCSRを使用します。 | サーバー、その後クライアント | はい |
†クライアント側レンダリング (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 プロジェクト テンプレートから作成されたアプリに対して自動的に適用されます。 個々のコンポーネントは、アプリの ファイルでコンポーネント サービスとエンドポイントを構成した後、「」セクションに従ってレンダー モードを宣言する必要があります。
Razor コンポーネントのサービスは、AddRazorComponents を呼び出すことによって追加されます。
コンポーネント ビルダー拡張機能:
- AddInteractiveServerComponents によって、対話型サーバー コンポーネントのレンダリングをサポートするサービスが追加されます。
- AddInteractiveWebAssemblyComponents によって、対話型 WebAssembly コンポーネントのレンダリングをサポートするサービスが追加されます。
MapRazorComponents は使用可能なコンポーネントを検出し、アプリのルート コンポーネント (読み込む最初のコンポーネント) を特定します。これは既定では App コンポーネント (App.razor) です。
エンドポイント規則ビルダー拡張機能:
- AddInteractiveServerRenderMode では、アプリの対話型サーバー側レンダリング (対話型 SSR) を構成します。
- AddInteractiveWebAssemblyRenderMode では、アプリの対話型 WebAssembly レンダリング モードを構成します。
注
次の例での API の配置に関する説明については、Program プロジェクト テンプレートから生成されたアプリの Blazor Web App ファイルを調べてください。
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" />
注
Blazor テンプレートには、短い using 構文向けのアプリの RenderMode ファイル (_Imports) の Components/_Imports.razor の静的 @rendermode ディレクティブが含まれています。
@using static Microsoft.AspNetCore.Components.Web.RenderMode
上のディレクティブがない場合、コンポーネントは RenderMode 構文で静的な @rendermode クラスを指定する必要があります。
<Dialog @rendermode="RenderMode.InteractiveServer" />
また、カスタムの構成で直接インスタンス化されたカスタム レンダリング モード インスタンスを参照することもできます。 詳しくは、この記事で後述する「カスタムの短縮形レンダリング モード」セクションをご覧ください。
コンポーネント定義にレンダー モードを適用する
コンポーネントのレンダー モードを定義の一部として指定するには、@rendermodeRazor ディレクティブ とそれに対応するレンダー モード属性を使用します。
@page "..."
@rendermode InteractiveServer
コンポーネント定義にレンダー モードを適用することは、特定のページにレンダー モードを適用するときによく使用されます。 ルーティング可能なページは、そのページをレンダリングした Router コンポーネントと同じレンダリング モードを使用します。
技術的には、@rendermode は Razor "ディレクティブ" であり、 "ディレクティブ属性" でもあります。Razor セマンティクスは似ていますが、違いがあります。
@rendermode ディレクティブはコンポーネント定義に対するものなので、参照されるレンダリング モード インスタンスは静的である必要があります。
@rendermode ディレクティブ属性は、任意のレンダリング モード インスタンスを受け取ることができます。
注
コンポーネント作成者は、コンポーネントの実装を特定のレンダー モードに結合しないようにする必要があります。 代わりに、コンポーネント作成者は通常、任意のレンダー モードまたはホスティング モデルをサポートするようにコンポーネントを設計する必要があります。 コンポーネントの実装では、実行される環境 (サーバーまたはクライアント) に関する想定を避け、静的にレンダリングされる際には、スムーズに機能低下をさせるようにする必要があります。 コンポーネントが直接インスタンス化されていない場合 (ルーティング可能なページ コンポーネントなど)、またはすべてのコンポーネント インスタンスのレンダー モードを指定する場合は、コンポーネント定義でレンダー モードを指定することが必要になる場合があります。
アプリ全体にレンダリング モードを適用する
アプリ全体のレンダリング モードを設定するには、アプリのコンポーネント階層の、ルート コンポーネントではない最上位の対話型コンポーネントで、レンダリング モードを指定します。
注
ルート コンポーネントを対話型にすること (App コンポーネントなど) はサポートされていません。 そのため、アプリ全体のレンダリング モードを App コンポーネントで直接設定することはできません。
Blazor Web App プロジェクト テンプレートに基づくアプリの場合、アプリ全体に割り当てられるレンダリング モードは、通常、Routes コンポーネント (App) で Components/App.razor コンポーネントが使われる場所で指定されます。
<Routes @rendermode="InteractiveServer" />
Router コンポーネントは、ルーティングするページに自身のレンダー モードを伝達します。
また、通常は、HeadOutlet コンポーネントで同じインタラクティブ レンダー モードを設定する必要があります。これは、プロジェクト テンプレートから生成された App の Blazor Web App コンポーネントにも含まれます。
<HeadOutlet @rendermode="InteractiveServer" />
対話型クライアント側 (WebAssembly または自動) レンダリング モードを採用し、Routes コンポーネントを介してアプリ全体でレンダリング モードを有効にするアプリの場合:
- サーバー アプリの
Components/Layoutフォルダーにあるレイアウト ファイルとナビゲーション ファイルを、.ClientプロジェクトのLayoutフォルダーに配置または移動します。Layoutプロジェクトに.Clientフォルダーが存在しない場合は作成します。 - サーバー アプリの
Components/Pagesフォルダーにあるコンポーネントを、.ClientプロジェクトのPagesフォルダーに配置または移動します。Pagesプロジェクトに.Clientフォルダーが存在しない場合は作成します。 - サーバー アプリの
RoutesフォルダーにあるComponentsコンポーネントを、.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 を採用する方法を示します。
Blazor に関する Blazor Web Appのドキュメント例
Blazor Web App を使用する場合、Blazor ドキュメントのほとんどのサンプル コンポーネントを機能させ、記事で説明されている概念を実証するには、インタラクティビティが必要です。 記事で提供されているサンプル コンポーネントをテストする場合は、アプリがグローバル インタラクティビティを採用しているか、コンポーネントが対話型レンダリング モードを採用していることを確認してください。
プリレンダリング
対話型レンダリング モード (Interactive Server、Interactive WebAssembly、Interactive Auto) では、既定でプリレンダリングがサポートされています。既定では、初期読み込みエクスペリエンスを向上させるために、ページ コンテンツがサーバーから静的にレンダリングされます。 詳細については、「 Prerender ASP.NET Core Razor コンポーネント」を参照してください。
実行時にレンダリングの場所、対話機能、および割り当てられたレンダリング モードを検出する
ComponentBase.RendererInfo と ComponentBase.AssignedRenderMode プロパティを使用すると、アプリはコンポーネントの場所、対話機能、および割り当てられたレンダリング モードに関する詳細を検出できます。
-
RendererInfo.Name は、コンポーネントが実行されている場所を返します。
-
Static: サーバー (SSR) 上にあり、対話はできません。 -
Server: サーバー (SSR) 上にあり、プリレンダリング後に対話できます。 -
WebAssembly: クライアント (CSR) 上にあり、プリレンダリング後に対話できます。 -
WebView: ネイティブ デバイス上にあり、プリレンダリング後に対話できます。
-
-
RendererInfo.IsInteractive は、レンダリング時にコンポーネントが対話機能をサポートしているかどうかを示します。 値は、対話的にレンダリングする場合は
true、プリレンダリングまたは静的 SSR (falseが RendererInfo.Name) の場合はStaticになります。 -
AssignedRenderMode は、コンポーネントの割り当てられたレンダリング モードを公開します。
- Interactive Server の場合
InteractiveServerRenderMode。 - 対話型自動の場合
InteractiveAutoRenderMode。 -
InteractiveWebAssemblyRenderModeインタラクティブ WebAssembly の場合。 - レンダリング モードが割り当てられていない場合に
nullします。
- Interactive Server の場合
コンポーネントは、これらのプロパティを使用して、場所や対話機能の状態に応じてコンテンツをレンダリングします。 次の例は、一般的なユース ケースを示しています。
コンポーネントが対話型になるまでコンテンツを表示します。
@if (!RendererInfo.IsInteractive)
{
<p>Connecting to the assistant...</p>
}
else
{
...
}
コンポーネントが対話型になるまでボタンを無効にします。
<button @onclick="Send" disabled="@(!RendererInfo.IsInteractive)">
Send
</button>
事前レンダリング中にフォームを無効にし、コンポーネントが対話型の場合にフォームを有効にします。
<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 を使用するブラウザーでは機能しないため、コンポーネントは、ユーザーのtitleFilter値に設定された<input>クエリ文字列を含むフォーム (GET 要求) を送信します。Movieコンポーネント (/movie) は、クエリ文字列を読み取り、titleFilterの値を処理して、フィルター処理された結果でコンポーネントをレンダリングできます。 - それ以外の場合、レンダリング モードは、
InteractiveServer、InteractiveWebAssembly、またはInteractiveAutoのいずれかです。 コンポーネントは、イベント ハンドラー デリゲート (FilterMovies) と<input>要素 (titleFilter) にバインドされた値を使用して、バックグラウンド SignalR 接続経由でムービーを対話的にフィルター処理できます。
静的サーバー側レンダリング (静的 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 コア ミドルウェア パイプライン要求処理によって処理されます。
Blazor コンポーネントはサーバー側の要求処理中にレンダリングされないため、承認専用のRazor機能は動作しません。
Blazor静的 SSR 中に使用できないRoutes コンポーネントのルーター機能には、<NotAuthorized>...</NotAuthorized> の表示が含まれます。
Blazor Web App通常、 承認ミドルウェアの動作をカスタマイズして、サーバー上の未承認の要求を処理します。
静的 SSR である間、Razor コンポーネント ページ要求は、サーバー側の ASP.NET Core ミドルウェア パイプライン要求の処理によって、ルーティングと承認のために処理されます。
Blazor コンポーネントはサーバー側の要求の処理中にレンダリングされないため、ルーティングと承認のための専用の Razor 機能は動作しません。 静的 SSR である間に使用できない Blazor コンポーネントの Routes ルーター機能には、次のような表示が含まれます。
承認されていないコンテンツ (
<NotAuthorized>...</NotAuthorized>) (NotAuthorized): 通常、Blazor Web Appは承認ミドルウェアの動作をカスタマイズして、サーバー上の未承認の要求を処理します。見つからないコンテンツ (
<NotFound>...</NotFound>) (NotFound): Blazor Web Appは通常、ブラウザーの組み込みの 404 UI を表示するか、コア ミドルウェア (UseStatusCodePagesWithRedirects/ API ドキュメントなど) を介してカスタム 404 ページ (またはその他の応答) を返すことによって、サーバー上の不適切な URL 要求 ASP.NET 処理します。
アプリがルートレベルの対話機能を示す場合、サーバー側の 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 に移動します。
対話型サーバー コンポーネントでは、ブラウザーとのリアルタイム接続 (回線) を使用して、Web UI イベントを処理します。 ルートインタラクティブサーバーコンポーネントがレンダリングされると、回路とその関連する状態が作成されます。 ページ上に対話型サーバー コンポーネントが残っていない場合、回線は閉じられ、サーバー リソースは解放されます。
クライアント側レンダリング (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コンポーネントは、 Blazorの SignalR 回線が確立された後に対話型です。 - クライアント側レンダリング (CSR) を使用する 2 つ目の
SharedMessageコンポーネントは、 アプリ バンドルがダウンロードされ、.NET ランタイムがクライアントでアクティブになった "後" に対話型になります。Blazor
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' であるためです。これは任意のコードであり、シリアル化できません。
ページ単位/コンポーネントごとのレンダリングを採用するアプリで、アプリのLayoutComponentBase コンポーネントなど、MainLayoutから継承するレイアウトで対話型レンダリングを採用しようとすると、同じことが起こります。 詳しくは、「ASP.NET Core の Blazor レイアウト」を参照してください。
上記の制限を回避するには、パラメーターを持たない別のコンポーネントで子コンポーネントをラップします。 これは、Blazor Web App コンポーネントをラップするために Routes コンポーネント (Components/Routes.razor) を使用する Router プロジェクト テンプレートで利用されるアプローチです。
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) を採用し、サーバー上でのみ実行するようにコンポーネントを要求する場合がありますが、アプリの残りの部分では対話型レンダリング モードが使用されます。
このアプローチが役に立つのは、インタラクティブ サーバーまたは WebAssembly レンダリングを使用して機能しない特定のページがアプリにある場合のみです。 たとえば、HTTP Cookie の読み取り/書き込みに依存し、インタラクティブ レンダリングの代わりに要求/応答サイクルでのみ動作できるページには、このアプローチを採用します。 対話型レンダリングを使用するページでは、エンド ユーザーにとって効率的で応答性が低く、静的 SSR を使用するように強制しないでください。
Razor
[ExcludeFromInteractiveRouting] ディレクティブで割り当てられた@attribute属性を持つ任意のRazor コンポーネント ページをマークします。
@attribute [ExcludeFromInteractiveRouting]
この属性を適用すると、インタラクティブ ルーティングでページへのナビゲーションが終了します。 インバウンド ナビゲーションでは、インタラクティブ ルーティングを使用してページを解決するのではなく、ページ全体の再読み込みが強制的に実行されます。 ページ全体の再読み込みでは、最上位のルート コンポーネント (通常は App コンポーネント (App.razor)) がサーバーから再レンダリングするよう強制されるため、アプリは別の最上位レベルのレンダリング モードに切り替えることができます。
RazorComponentsEndpointHttpContextExtensions.AcceptsInteractiveRouting拡張メソッドを使用すると、コンポーネントは、[ExcludeFromInteractiveRouting]属性が現在のページに適用されているかどうかを検出できます。
App コンポーネントでは、次の例のパターンが使用されます。
-
[ExcludeFromInteractiveRouting]属性で注釈が付いていないページ既定では、グローバル対話機能を持つInteractiveServerレンダリング モードになります。InteractiveServerをInteractiveWebAssemblyまたは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;
}
RazorComponentsEndpointHttpContextExtensions.AcceptsInteractiveRouting 拡張メソッドを使用する代わりに、HttpContext.GetEndpoint()?.Metadata を使用してエンドポイント メタデータを手動で読み取る方法があります。
レンダー モードを細かく制御するには 2 つの方法があります。それぞれについて、次のサブセクションで説明します。
静的 SSR コンポーネントの領域 (フォルダー): 静的 SSR を採用し、同じルート パス プレフィックスを共有する必要があるコンポーネントを含むアプリの領域 (フォルダー) があります。 アプリは、フォルダーへのパスに基づいて
Routesコンポーネント内のAppコンポーネントにレンダー モードを設定することで、レンダー モードをグローバルに制御します。アプリ全体に分散した静的 SSR コンポーネント: 静的 SSR を採用し、サーバー上でのみ実行する必要があるコンポーネントが、アプリの周囲のさまざまな場所に分散しています。 静的 SSR 専用のコンポーネントは 1 つのフォルダーに含まれておらず、共通のルート パス プレフィックスを共有していません。 アプリは、コンポーネント インスタンスの
@rendermodeディレクティブを使用してレンダー モードを設定することで、コンポーネントごとにレンダー モードを制御します。Appコンポーネントでリフレクションを使用して、Routesコンポーネントのレンダー モードを設定します。
どちらの場合も、静的 SSR を採用する必要があるコンポーネントは、ページ全体の再読み込みも強制する必要があります。
次の例では、HttpContext カスケード パラメーターを使用して、ページが静的にレンダリングされているかどうかを判断します。
null
HttpContext は、コンポーネントが対話形式でレンダリングされていることを示します。これは、ページ全体の再読み込みをトリガーするアプリ コードのシグナルとして役立ちます。
静的 SSR コンポーネントのエリア (フォルダー)
このセクションのアプローチの例については、BlazorWebAppAreaOfStaticSsrComponents サンプル アプリのを参照してください。 このセクションで説明する手法は.NET 8 Blazor Web Appに最も適していますが、このサンプルは Blazor 機能を使用して .NET 9 に実装されており、この方法の動作を簡単に示します。
このサブセクションで説明する方法は、グローバルな対話機能を持つ Blazor Web App プロジェクト テンプレートによって使用されます。
アプリの領域 (フォルダー) には、静的 SSR を採用し、サーバーでのみ実行する必要があるコンポーネントが含まれています。 フォルダー内のコンポーネントは、同じルート パス プレフィックスを共有します。 たとえば、Identity プロジェクト テンプレートの RazorBlazor Web App コンポーネントはComponents/Account/Pages フォルダー内にあり、ルート パス プレフィックス /account を共有します。
アプリには、_Imports.razor フォルダー内の静的 SSR コンポーネントに自動的に適用される Components ファイルも含まれており、カスタム レイアウトが適用されます。
Components/Account/_Imports.razor:
@using BlazorSample.Components.Account.Shared
@layout AccountLayout
Shared フォルダーには AccountLayout レイアウト コンポーネントが保持されています。 このコンポーネントは、HttpContext を使用して、コンポーネントが静的 SSR を採用しているかどうかを判断します。 たとえば、Identity コンポーネントは、Identity Cookie を設定するため、静的 SSR を使用してサーバー上にレンダリングする必要があります。
HttpContext の値が null の場合、コンポーネントは対話形式でレンダリングされ、NavigationManager.Refresh を forceLoad に設定して true を呼び出すことによってページ全体の再読み込みが実行されます。 これにより、静的 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);
}
}
}
注
認証シナリオ用の Blazor Web App プロジェクト テンプレートには、ManageLayout.razor フォルダー内の Components/Account/Shared コンポーネント用の 2 つ目のレイアウト ファイル (Identity フォルダーにComponents/Account/Pages/Manage) があります。
Manage フォルダーには、フォルダー内の _Imports.razor コンポーネントに適用する独自の ManageLayout ファイルがあります。 独自のアプリで、入れ子になった _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};
}
前のコードでは、アプリケーションの残りの部分でグローバル {INTERACTIVE RENDER MODE}、InteractiveServerまたは InteractiveWebAssembly レンダリングを採用する必要があるかどうかに応じて、InteractiveAuto プレースホルダーを適切な値に変更します。
Account フォルダーに静的 SSR を採用する必要があるコンポーネントは、_Imports.razor ファイルを介して適用されるレイアウトを設定する必要はありません。 このコンポーネントは静的 SSR でレンダリングする必要があるため、レンダリング モードを設定しません。
Account フォルダー内のコンポーネントで静的 SSR を適用するために、これ以上何も行う必要はありません。
アプリ全体に分散している静的 SSR コンポーネント
このセクションのアプローチの例については、BlazorWebAppSpreadOutStaticSsrComponents サンプル アプリのを参照してください。 このセクションで説明する手法は.NET 8 Blazor Web Appに最も適していますが、このサンプルは Blazor 機能を使用して .NET 9 に実装されており、この方法の動作を簡単に示します。
前のサブセクションでは、アプリが App コンポーネントでレンダー モードをグローバルに設定することで、コンポーネントのレンダー モードを制御していました。 また、App コンポーネントでは、レンダー モードを設定するために "コンポーネントごと" のレンダー モードを採用することもできます。これにより、コンポーネントをアプリの周囲に分散して静的 SSR の採用を強制できます。 このサブセクションでは、このアプローチについて説明します。
アプリには、アプリの周囲のコンポーネントに適用できるカスタム レイアウトがあります。 通常、アプリの共有コンポーネントは Components/Layout フォルダーに配置されます。 このコンポーネントは、HttpContext を使用して、コンポーネントが静的 SSR を採用しているかどうかを判断します。
HttpContext の値が null の場合、コンポーネントは対話形式でレンダリングされ、NavigationManager.Refresh を forceLoad に設定して true を呼び出すことによってページ全体の再読み込みが実行されます。 これにより、コンポーネントについてのサーバーへの要求がトリガーされます。
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 を採用する必要がある各コンポーネントは、カスタム レイアウトを設定し、レンダリング モードを指定しません。 レンダー モードを指定しないと、null コンポーネントの RenderModeAttribute.Mode 値が App となり、その結果、Routes コンポーネント インスタンスにレンダー モードが割り当てられず、静的 SSR が適用されます。
重要
null レンダー モードを適用しても、必ずしも静的 SSR が強制されるわけではありません。 このセクションに示す方法を使用して、そのように動作しているだけです。
null レンダー モードは、レンダリング モードを指定しない場合と実質的に同じであり、その結果、コンポーネントは親のレンダー モードを継承します。 この場合、App コンポーネントは静的 SSR を使用してレンダリングされるため、null レンダー モードの結果、Routes コンポーネントは App コンポーネントから 静的 SSR を継承します。 親が対話型レンダー モードを使用する子コンポーネントに対して null レンダー モードが指定されている場合、子は同じ対話型レンダリング モードを継承します。
静的 SSR を適用するために、対話型レンダリング モードを設定せずにカスタム レイアウトを適用する以外にコンポーネントに対して何も行う必要はありません。
@layout BlazorSample.Components.Layout.StaticSsrLayout
アプリの周囲の対話型コンポーネントは、カスタム静的SSRレイアウトの適用を回避し、適切なインタラクティブレンダーモードのみを設定します。これはコンポーネント内でのリフレクション時にコンポーネントに適用されます。
@rendermode {INTERACTIVE RENDER MODE}
前のコードでは、コンポーネントで {INTERACTIVE RENDER MODE}、InteractiveServer、または InteractiveWebAssembly レンダリングを採用する必要があるかどうかに応じて、InteractiveAuto プレースホルダーを適切な値に変更します。
カスタムの短縮形レンダリング モード
@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 フラグの詳細な指定を軽減するためにのみ役立ちます。 将来的に、対話型レンダリングで使用できるフラグが追加され、さまざまなフラグの組み合わせで短縮形レンダリング モードを作成できるようになれば、短縮形のアプローチの方が便利になる可能性があります。
その他のリソース
- WebSocket 圧縮
- ASP.NET Core Blazor JavaScript と静的サーバー側レンダリング (静的 SSR)
- カスケード値/パラメーターとレンダリング モードの境界: この記事の前の「通知」セクションでは、 ルート レベルのカスケード値 と ルート レベルのカスケード値 も参照してください。
- ASP.NET Core の Razor クラス ライブラリ (RCL) と静的サーバー側レンダリング (静的 SSR)
- Blazor Web App を使用して、のデータを保護する
- ASP.NET Core Blazor JavaScript と静的サーバー側レンダリング (静的 SSR)
- カスケード値/パラメーターとレンダリング モードの境界: この記事の前の「通知」セクションでは、 ルート レベルのカスケード値 と ルート レベルのカスケード値 も参照してください。
- ASP.NET Core の Razor クラス ライブラリ (RCL) と静的サーバー側レンダリング (静的 SSR)
- Blazor Web App を使用して、のデータを保護する
ASP.NET Core