次の方法で共有


ASP.NET Core Razor コンポーネントのプリレンダリング

注記

これは、この記事の最新バージョンではありません。 現在のリリースについては、 この記事の .NET 10 バージョンを参照してください。

この記事では、RazorおよびBlazor Web App アプリでサーバーによってレンダリングされるコンポーネントのBlazor Server コンポーネントのプリレンダリング シナリオについて説明します。

プリレンダリング は、可能な限り迅速に HTML をブラウザーに配信するために、サーバーからページ コンテンツを静的にレンダリングするプロセスです。 プリレンダリングされたコンテンツがユーザーにすばやく表示されると、アクティブなイベント ハンドラーを含む対話型コンテンツがレンダリングされ、以前にレンダリングされたすべてのコンテンツが置き換わります。 プリレンダリングでは、検索エンジンによってページ ランクの計算に使用される初期 HTTP 応答のコンテンツをレンダリングすることで、検索エンジンの最適化 (SEO) を向上させることもできます。

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

対話型ルーティングを使用した内部ナビゲーションでは、ページが既に対話型であるため、プリレンダリングは使用されません。 詳細については、「 静的ルーティングと対話型ルーティング 」および 「対話型ルーティングとプリレンダリング」を参照してください。

OnAfterRender{Async} コンポーネントライフサイクルイベント は、プリレンダリング時には呼び出されず、コンポーネントが対話形式でレンダリングされた後にのみ呼び出されます。

プリレンダリングを無効にする

プリレンダリングでは、アプリの Razor コンポーネントを 2 回レンダリングする必要があるため、プリレンダリングが複雑になる可能性があります。プリレンダリング用に 1 回、対話機能を設定するために 1 回です。 コンポーネントが WebAssembly で実行されるように設定されている場合は、サーバーとクライアントの両方から実行できるようにコンポーネントを設計する必要もあります。

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

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

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

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

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

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

上記の手法を使用してプリレンダリングを無効にすると、最上位のレンダリング モードでのみ有効になります。 親コンポーネントでレンダリング モードが指定されている場合、その子のプリレンダリング設定は無視されます。

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

プリレンダリングされた状態を保持しないと、プリレンダリング中に使用された状態は失われ、アプリが完全に読み込まれたときに再作成する必要があります。 状態が非同期的に作成される場合、コンポーネントの再レンダリングによってプリレンダリングされたUIが置き換えられる際に、UIが一時的にちらつくことがあります。 プリレンダリング中に状態を保持する方法のガイダンスについては、「ASP.NET Core Blazor プリレンダリングされた状態の永続化」を参照してください。

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

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

たとえば、 Home プロジェクト内の .Client で、 Blazor Web Appグローバルな対話型 WebAssembly または対話型自動レンダリングを使用した次のコンポーネントについて検討します。 このコンポーネントは、環境の名前を取得するために 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 はサーバー上の登録されたサービスでないために発生します。

このシナリオに対処するには、次のいずれかの方法を検討してください。

クライアントに加えてサーバーにサービスを登録する

サービスがサーバーの実行をサポートしている場合は、プリレンダリング中に使用できるように、クライアントに加えてサーバーにサービスを登録します。 このシナリオの例については、HttpClientしに関する記事の「Blazor Web App外部 Web API」セクションの サービスのガイダンスを参照してください。

プリレンダリング中にアプリが使用できるサービスを挿入する

場合によっては、プリレンダリング中にサーバー上のサービスとクライアント上の別のサービスを使用できます。

たとえば、次のコードは、IHostEnvironmentMicrosoft.Extensions.Hosting.Abstractionsからを挿入することで、コードがサーバー上で実行されているかクライアント上で実行されているかに関係なく、アプリの環境を取得します。

private string? environmentName;

public Home(IHostEnvironment? serverEnvironment = null, 
    IWebAssemblyHostEnvironment? wasmEnvironment = null)
{
    environmentName = serverEnvironment?.EnvironmentName;
    environmentName ??= wasmEnvironment?.Environment;
}

ただし、この方法では、必要のない依存関係がクライアント プロジェクトに追加されます。

サービスを省略可能にする

プリレンダリング中に必要ない場合は、次のいずれかの方法を使用してサービスをオプションにします。

次の例では、 IWebAssemblyHostEnvironmentのコンストラクター挿入を使用します。

private string? environmentName;

public Home(IWebAssemblyHostEnvironment? env = null)
{
    environmentName = env?.Environment;
}

または、サービスが利用可能な場合にオプションで取得するために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;
        }
    }
}

サービスの抽象化を作成する

サーバーで別のサービス実装が必要な場合は、サービスの抽象化を作成し、サーバーおよびクライアント プロジェクトでサービスの実装を作成します。 各プロジェクトでサービスを登録します。 必要に応じ、カスタム サービスの抽象化をコンポーネントに挿入します。 その後、コンポーネントはカスタム サービスの抽象化のみに依存します。

IWebAssemblyHostEnvironmentの場合、新しいインターフェイスを作成する代わりに、既存のインターフェイスを再利用できます。

ServerHostEnvironment.cs:

using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.AspNetCore.Components;

public class ServerHostEnvironment(IWebHostEnvironment env, NavigationManager nav) : 
    IWebAssemblyHostEnvironment
{
    public string Environment => env.EnvironmentName;
    public string BaseAddress => nav.BaseUri;
}

サーバー プロジェクトの Program ファイルで、サービスを登録します。

builder.Services.TryAddScoped<IWebAssemblyHostEnvironment, ServerHostEnvironment>();

この時点で、 IWebAssemblyHostEnvironment サービスは 、サーバーからプリレンダリングされた対話型の WebAssembly または Auto コンポーネントに挿入できます。

コンポーネントのプリレンダリングを無効にする

コンポーネントまたはアプリ全体のプリレンダリングを無効にします。 詳細については、「 プリレンダリングを無効にする 」セクションを参照してください。