ASP.NET Core Razor コンポーネントのプリレンダリングと統合を行う
注意
これは、この記事の最新バージョンではありません。 この記事の最新バージョンについては、「.NET 7 のバージョン」を参照してください。
この記事では、サーバー上の Razor コンポーネントのプリレンダリングを含む Blazor アプリの Razor コンポーネントの統合シナリオについて説明します。
重要
ASP.NET Core リリース間でのフレームワークの変更により、この記事のさまざまな手順セットが作成されました。 この記事のガイダンスを使用する前に、このページのドキュメント バージョン セレクターが、アプリに使用する ASP.NET Core のバージョンと一致していることを確認します。
ホストされる Blazor WebAssemblyソリューションの Razor Pages と MVC アプリに Razor コンポーネントを統合できます。 ページまたはビューがレンダリングされるときには、コンポーネントを同時に事前レンダリングすることができます。
プリレンダリングにより、検索エンジンがページ ランクの計算に使える最初の HTTP 応答の内容がレンダリングされることで、検索エンジンの最適化 (SEO) が向上します。
ソリューションの構成
プリレンダリングの構成
ホストされる Blazor WebAssembly アプリのプリレンダリングを設定するには:
ASP.NET Core アプリで Blazor WebAssembly をホストします。 スタンドアロンの Blazor WebAssembly アプリを ASP.NET Core ソリューションに追加することも、hosted たオプションを使用して Blazor WebAssembly プロジェクト テンプレートから作成されたホスト型の Blazor WebAssembly アプリを使用することもできます。
- Visual Studio: Blazor WebAssembly アプリの作成時に、[追加情報] ダイアログで [ASP.NET Core Hosted] (ASP.NET Core ホステッド) チェックボックスをオンにします。 この記事の例では、ソリューションに
BlazorHosted
という名前が付けられています。 - Visual Studio Code/.NET CLI コマンド シェル:
dotnet new blazorwasm -ho
(-ho|--hosted
オプションを使用)。-o|--output {LOCATION}
オプションを使用してソリューションのフォルダーを作成し、ソリューションのプロジェクト名前空間を設定します。 この記事の例では、ソリューションにBlazorHosted
という名前が付けられています (dotnet new blazorwasm -ho -o BlazorHosted
)。
この記事の例では、ホステッド ソリューションの名前 (アセンブリ名) は
BlazorHosted
です。 クライアント プロジェクトの名前空間はBlazorHosted.Client
で、サーバー プロジェクトの名前空間はBlazorHosted.Server
です。- Visual Studio: Blazor WebAssembly アプリの作成時に、[追加情報] ダイアログで [ASP.NET Core Hosted] (ASP.NET Core ホステッド) チェックボックスをオンにします。 この記事の例では、ソリューションに
Blazor WebAssemblyClient プロジェクトから
wwwroot/index.html
ファイルを削除します。Client プロジェクトで、
Program.cs
の次の行を削除します。- builder.RootComponents.Add<App>("#app"); - builder.RootComponents.Add<HeadOutlet>("head::after");
_Host.cshtml
ファイルを Server プロジェクトのPages
フォルダーに追加します。 これらのファイルは、Visual Studio または .NET CLI のコマンド シェルでdotnet new blazorserver -o BlazorServer
コマンドを使用して Blazor Server テンプレートから作成されたプロジェクトから取得できます (-o BlazorServer
オプションを指定すると、プロジェクトのフォルダーが作成されます)。 Server プロジェクトのPages
フォルダーにファイルを配置した後、ファイルに次の変更を加えます。_Host.cshtml
ファイルに次の変更を加えます。ファイルの先頭にある
Pages
名前空間を更新し、 Server アプリのページの名前空間と一致させます。 次の例に示す{APP NAMESPACE}
プレースホルダーは、_Host.cshtml
ファイルを提供したドナー アプリのページの名前空間を表します。削除:
- @namespace {APP NAMESPACE}.Pages
次の項目を追加します。
@namespace BlazorHosted.Server.Pages
ファイルの先頭に、 Client プロジェクトの
@using
ディレクティブを追加します。@using BlazorHosted.Client
スタイルシートのリンクを、WebAssembly プロジェクトのスタイルシートをポイントするように更新します。 次の例では、クライアント プロジェクトの名前空間は
BlazorHosted.Client
になります。{APP NAMESPACE}
プレースホルダーは、_Host.cshtml
ファイルを提供したドナー アプリの名前空間を表します。HeadOutlet
コンポーネントのコンポーネント タグ ヘルパー (<component>
タグ) を、コンポーネントをプリレンダリングするように更新します。削除:
- <link href="css/site.css" rel="stylesheet" /> - <link href="{APP NAMESPACE}.styles.css" rel="stylesheet" /> - <component type="typeof(HeadOutlet)" render-mode="ServerPrerendered" />
次の項目を追加します。
<link href="css/app.css" rel="stylesheet" /> <link href="BlazorHosted.Client.styles.css" rel="stylesheet" /> <component type="typeof(HeadOutlet)" render-mode="WebAssemblyPrerendered" />
Note
ブートストラップ スタイルシート (
css/bootstrap/bootstrap.min.css
) を要求する<link>
要素はそのままにしておきます。Blazor スクリプトのソースを、クライアント側の Blazor WebAssembly スクリプトを使用するように更新します。
削除:
- <script src="_framework/blazor.server.js"></script>
次の項目を追加します。
<script src="_framework/blazor.webassembly.js"></script>
コンポーネント タグ ヘルパーの
render-mode
を、ルートのApp
コンポーネントを WebAssemblyPrerendered を使用してプリレンダリングするように更新します。削除:
- <component type="typeof(App)" render-mode="ServerPrerendered" />
次の項目を追加します。
<component type="typeof(App)" render-mode="WebAssemblyPrerendered" />
重要
プリレンダリングは認証エンドポイントではサポートされていません (
/authentication/
パス セグメント)。 詳細については、「ASP.NET Core Blazor WebAssembly のその他のセキュリティ シナリオ」を参照してください。
Server プロジェクトの
Program.cs
ファイルで、フォールバック エンドポイントをindex.html
ファイルから_Host.cshtml
ページに変更します。削除:
- app.MapFallbackToFile("index.html");
次の項目を追加します。
app.MapFallbackToPage("/_Host");
Client プロジェクトと Server プロジェクトでプリレンダリング中に 1 つまたは複数の一般的サービスが使用される場合、両方のプロジェクトから呼び出せるメソッドにサービス登録を入れます。 詳細については、「ASP.NET Core Blazor の依存関係の挿入」を参照してください。
Server プロジェクトを実行します。 ホストされる Blazor WebAssembly アプリは、クライアントの Server プロジェクトによってプリレンダリングされ ます。
Razor コンポーネントをページおよびビューに埋め込むための構成
ClientBlazor WebAssembly アプリの Razor コンポーネントをサーバー アプリのページとビューに埋め込むための次のセクションと例では、追加の構成が必要です。
Server プロジェクトには 次のファイルとフォルダーが含まれている必要があります。
Razor Pages:
Pages/Shared/_Layout.cshtml
Pages/Shared/_Layout.cshtml.css
Pages/_ViewImports.cshtml
Pages/_ViewStart.cshtml
MVC:
Views/Shared/_Layout.cshtml
Views/Shared/_Layout.cshtml.css
Views/_ViewImports.cshtml
Views/_ViewStart.cshtml
上記のファイルは、次の方法で ASP.NET Core プロジェクト テンプレートからアプリを生成することによって取得できます。
- Visual Studio の新しいプロジェクト作成ツール。
- コマンド シェルを開き、
dotnet new webapp -o {PROJECT NAME}
(Razor Pages) またはdotnet new mvc -o {PROJECT NAME}
(MVC) を実行する。{PROJECT NAME}
プレースホルダーの値を持つ-o|--output
オプションは、アプリの名前を指定して、アプリのフォルダーを作成します。
インポートされた _ViewImports.cshtml
ファイル内の名前空間を、ファイルを受け取る Server プロジェクトで使用されているものと一致するように更新します。
Pages/_ViewImports.cshtml
(Razor Pages):
@using BlazorHosted.Server
@namespace BlazorHosted.Server.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
Views/_ViewImports.cshtml
(MVC):
@using BlazorHosted.Server
@using BlazorHosted.Server.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
インポートされたレイアウト ファイルを更新します。これは、Razor Pages の場合は Pages/Shared/_Layout.cshtml
、MVC の場合は Views/Shared/_Layout.cshtml
です。
最初に、ドナー プロジェクトからタイトルとスタイルシートを削除します。これは、次の例では RPDonor.styles.css
です。 {PROJECT NAME}
プレースホルダーは、ドナー プロジェクトのアプリ名を表します。
- <title>@ViewData["Title"] - {PROJECT NAME}</title>
- <link rel="stylesheet" href="~/RPDonor.styles.css" asp-append-version="true" />
レイアウト ファイルに Client プロジェクトのスタイルを含めます。 次の例では、 Client プロジェクトの名前空間は BlazorHosted.Client
になります。 <title>
要素は同時に更新できます。
レイアウト ファイルの <head>
の内容に次の行を配置します。
<title>@ViewData["Title"] - BlazorHosted</title>
<link href="css/app.css" rel="stylesheet" />
<link rel="stylesheet" href="BlazorHosted.Client.styles.css" asp-append-version="true" />
<component type="typeof(HeadOutlet)" render-mode="WebAssemblyPrerendered" />
インポートされたレイアウトには 2 つの Home
Index
ページと Privacy
のナビゲーション リンクが含まれます。 Home
リンクが、ホストされる Blazor WebAssembly アプリを指すようにするには、ハイパーリンクを次のように変更します。
- <a class="navbar-brand" asp-area="" asp-page="/Index">{PROJECT NAME}</a>
+ <a class="navbar-brand" href="/">BlazorHosted</a>
- <a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
+ <a class="nav-link text-dark" href="/">Home</a>
MVC レイアウト ファイルの場合:
- <a class="navbar-brand" asp-area="" asp-controller="Home"
- asp-action="Index">{PROJECT NAME}</a>
+ <a class="navbar-brand" href="/">BlazorHosted</a>
- <a class="nav-link text-dark" asp-area="" asp-controller="Home"
- asp-action="Index">Home</a>
+ <a class="nav-link text-dark" href="/">Home</a>
<footer>
要素のアプリ名を更新します。 次の例では、BlazorHosted
というアプリ名を使用しています。
- © {DATE} - {DONOR NAME} - <a asp-area="" asp-page="/Privacy">Privacy</a>
+ © {DATE} - BlazorHosted - <a asp-area="" asp-page="/Privacy">Privacy</a>
前の例では、{DATE}
プレースホルダーは Razor Pages または MVC プロジェクト テンプレートから生成されたアプリの著作権日を表します。
Privacy
リンクが privacy ページ (Razor Pages) につながるようにするには、privacy ページを Server プロジェクトに追加します。
Server プロジェクトの Pages/Privacy.cshtml
:
@page
@model PrivacyModel
@{
ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>
<p>Use this page to detail your site's privacy policy.</p>
MVC ベースの privacy ビューの場合は、Server プロジェクトで privacy ビューを作成します。
Server プロジェクトの View/Home/Privacy.cshtml
:
@{
ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>
<p>Use this page to detail your site's privacy policy.</p>
MVC アプリの Home
コントローラーで、ビューを返します。
Controllers/HomeController.cs
に次のコードを追加します。
public IActionResult Privacy()
{
return View();
}
ドナー アプリからファイルをインポートする場合は、ファイル内のすべての名前空間を更新して、 Server プロジェクトの名前空間 (たとえば、BlazorHosted.Server
) に一致させてください。
ドナー プロジェクトの wwwroot
フォルダーから Server プロジェクトに静的アセットをインポートします。
wwwroot/css
フォルダーと内容wwwroot/js
フォルダーと内容wwwroot/lib
フォルダーと内容
ドナー プロジェクトが ASP.NET Core プロジェクト テンプレートから作成され、ファイルが変更されていない場合は、ドナー プロジェクトの wwwroot
フォルダー全体を Server プロジェクトにコピー して、favicon アイコン ファイルを削除することができます。
警告
静的アセットを Client フォルダーと Server wwwroot
フォルダーの両方に配置するのは避けてください。 両方のフォルダーに同じファイルがある場合は、各静的アセットで同じ Web ルート パスが共有されるため、例外がスローされます。 そのため、静的アセットを wwwroot
フォルダーのいずれか (両方ではなく) でホストします。
上記の構成を採用した後で、Razor コンポーネントを Server プロジェクトのページまたはビューに埋め込みます。 この記事の以降のセクションのガイダンスを使用してください。
- コンポーネント タグ ヘルパーを使用してページまたはビューのコンポーネントをレンダリングする
- CSS セレクターを使用してページまたはビューのコンポーネントをレンダリングする
コンポーネント タグ ヘルパーを使用してページまたはビューのコンポーネントをレンダリングする
追加構成を含むソリューションを構成した後、コンポーネント タグ ヘルパーは、Blazor WebAssembly アプリのコンポーネントをページまたはビュー内にレンダリングするための 2 つのレンダー モードをサポートします。
次の Razor Pages の例では、Counter
コンポーネントがページにレンダリングされます。 コンポーネントを対話形式にするために、ページのレンダリング セクションに Blazor WebAssembly スクリプトが含まれます。 コンポーネント タグ ヘルパーによる Counter
コンポーネントの完全な名前空間 ({ASSEMBLY NAME}.Pages.Counter
) の使用を避けるために、クライアント プロジェクトの Pages
名前空間に @using
ディレクティブを追加します。 次の例では、 Client プロジェクトの名前空間は BlazorHosted.Client
になります。
Server プロジェクトの Pages/RazorPagesCounter1.cshtml
:
@page
@using BlazorHosted.Client.Pages
<component type="typeof(Counter)" render-mode="WebAssemblyPrerendered" />
@section Scripts {
<script src="_framework/blazor.webassembly.js"></script>
}
Server プロジェクトを実行します。 /razorpagescounter1
の Razor ページに移動します。 プリレンダリングされた Counter
コンポーネントはページに埋め込まれています。
RenderMode によって、コンポーネントに対して以下の構成が行われます。
- ページに事前レンダリングするかどうか。
- ページに静的 HTML としてレンダリングするかどうか。または、ユーザー エージェントから Blazor アプリをブートストラップするために必要な情報が含まれているかどうか。
パラメーターの渡し方や RenderMode の構成などのコンポーネント タグ ヘルパーの詳細については、「ASP.NET Core のコンポーネント タグ ヘルパー」を参照してください。
コンポーネントによって使用される静的リソースや、アプリでのレイアウト ページの整理方法によっては、追加の作業が必要になる場合があります。 通常、ページまたはビューの Scripts
レンダー セクションにスクリプトが追加され、スタイル シートはレイアウトの <head>
要素コンテンツに追加されます。
レンダリング フラグメントを使用して子コンテンツを設定する
コンポーネント タグ ヘルパーでは、子コンテンツの RenderFragment
デリゲート (param-ChildContent="..."
など) の受信をサポートしていません。 渡される子コンテンツを使用してレンダリングするコンポーネントを参照する Razor コンポーネント (.razor
) を作成し、ページまたはビューから Razor コンポーネントを呼び出すことをお勧めします。
最上位のプリレンダリングされたコンポーネントが発行時にトリミングされないようにする
コンポーネント タグ ヘルパーが、発行時にトリミングの対象となるライブラリからコンポーネントを直接参照している場合は、クライアント側のアプリ コードからの参照がないため、発行時にコンポーネントがトリミングされる可能性があります。 その結果、コンポーネントはプリレンダリングされず、出力に空白が残ります。 この問題が発生した場合は、クライアント側アプリの任意のクラスに DynamicDependency
属性を追加して、ライブラリ コンポーネントを保持するようにトリマーに指示します。 SomeLibraryComponentToBePreserved
というコンポーネントを保持するには、任意のコンポーネントに次を追加します。
@using System.Diagnostics.CodeAnalysis
@attribute [DynamicDependency(DynamicallyAccessedMemberTypes.All,
typeof(SomeLibraryComponentToBePreserved))]
通常、アプリでは (トリミングされていない) コンポーネントをプリレンダリングするため、上記の方法は通常、必要ありません。これにより、ライブラリからコンポーネントが参照されます (これにより、トリミングもされません)。 ライブラリをトリミングするときにライブラリ コンポーネントを直接プリレンダリングする場合にのみ、DynamicDependency
を明示的に使用します。
CSS セレクターを使用してページまたはビューのコンポーネントをレンダリングする
追加の構成を含めてソリューションを構成した後、Program.cs
ファイルでホストされる Blazor WebAssembly ソリューションの Client プロジェクトにルート コンポーネントを追加します。 次の例では、counter-component
と一致する id
を持つ要素を選択する CSS セレクターを使用して、ルート コンポーネントとして Counter
コンポーネントが宣言されています。 次の例では、 Client プロジェクトの名前空間は BlazorHosted.Client
になります。
Client プロジェクトの Program.cs
ファイルで、プロジェクトの Razor コンポーネントの名前空間をファイルの先頭に追加します。
using BlazorHosted.Client.Pages;
Program.cs
で builder
が確立されたら、Counter
コンポーネントをルート コンポーネントとして追加します。
builder.RootComponents.Add<Counter>("#counter-component");
次の Razor Pages の例では、Counter
コンポーネントがページにレンダリングされます。 コンポーネントを対話形式にするために、ページのレンダリング セクションに Blazor WebAssembly スクリプトが含まれます。
Server プロジェクトの Pages/RazorPagesCounter2.cshtml
:
@page
<div id="counter-component">Loading...</div>
@section Scripts {
<script src="_framework/blazor.webassembly.js"></script>
}
Server プロジェクトを実行します。 /razorpagescounter2
の Razor ページに移動します。 プリレンダリングされた Counter
コンポーネントはページに埋め込まれています。
コンポーネントによって使用される静的リソースや、アプリでのレイアウト ページの整理方法によっては、追加の作業が必要になる場合があります。 通常、ページまたはビューの Scripts
レンダー セクションにスクリプトが追加され、スタイル シートはレイアウトの <head>
要素コンテンツに追加されます。
Note
前の例では、Blazor WebAssembly アプリが CSS セレクターを使用して Razor Pages または MVC アプリに同時にプリレンダリングおよび統合された場合に JSException がスローされます。 Client プロジェクトのいずれかの Razor コンポーネントに移動するか、埋め込みコンポーネントを含む Server のページまたはビューに移動すると、1 つ以上の JSException がスローされます。
ルーティング可能な Razor コンポーネントを使用した Blazor WebAssembly アプリのプリレンダリングおよび統合は、CSS セレクターの使用と両立しないため、これは通常の動作です。
前のセクションの例を使用している状態で、サンプル アプリで CSS セレクターが動作することを確認するだけの場合は、 Client プロジェクトの Program.cs
ファイルの App
ルート コンポーネントの仕様をコメント アウトしてください。
- builder.RootComponents.Add<App>("#app");
+ //builder.RootComponents.Add<App>("#app");
CSS セレクターを使用する埋め込みの Razor コンポーネント (たとえば、前の例の /razorpagescounter2
) を含むページまたはビューに移動します。 ページまたはビューが埋め込みコンポーネントと共に読み込まれ、埋め込みコンポーネントは想定どおりに機能します。
Razor コンポーネントは、Razor Pages と MVC アプリに統合できます。 ページまたはビューがレンダリングされるときには、コンポーネントを同時に事前レンダリングすることができます。
プリレンダリングにより、検索エンジンがページ ランクの計算に使える最初の HTTP 応答の内容がレンダリングされることで、検索エンジンの最適化 (SEO) が向上します。
プロジェクトを構成した後、プロジェクトの要件に応じて、次のセクションのガイダンスを使用します。
- ユーザー要求から直接ルーティング可能なコンポーネント。 訪問者が
@page
ディレクティブを含むコンポーネントのブラウザーで HTTP 要求を行うことができる必要がある場合は、このガイダンスに従ってください。 - ユーザー要求から直接ルーティングできないコンポーネントについては、「ページまたはビューからコンポーネントをレンダリングする」セクションを参照してください。 アプリによってコンポーネント タグ ヘルパーを含む既存のページやビューにコンポーネントが埋め込まれる場合は、このガイダンスに従ってください。
構成
次のガイダンスを使用して、既存の Razor Pages または MVC アプリのページとビューに Razor コンポーネントを統合します。
次の内容の imports ファイルをプロジェクトのルート フォルダーに追加します。
{APP NAMESPACE}
プレースホルダーをプロジェクトの名前空間に変更します。_Imports.razor
:@using System.Net.Http @using Microsoft.AspNetCore.Authorization @using Microsoft.AspNetCore.Components.Authorization @using Microsoft.AspNetCore.Components.Forms @using Microsoft.AspNetCore.Components.Routing @using Microsoft.AspNetCore.Components.Web @using Microsoft.AspNetCore.Components.Web.Virtualization @using Microsoft.JSInterop @using {APP NAMESPACE}
プロジェクトのレイアウト ファイル (Razor Pages アプリの
Pages/Shared/_Layout.cshtml
、または MVC アプリのViews/Shared/_Layout.cshtml
):<head>
要素に次の<base>
タグと HeadOutlet コンポーネント タグ ヘルパーを追加します。<base href="~/" /> <component type="typeof(Microsoft.AspNetCore.Components.Web.HeadOutlet)" render-mode="ServerPrerendered" />
前の例の
href
値 (アプリ ベースのパス) は、アプリがルート URL パス (/
) に置かれていることを前提としています。 アプリがサブアプリケーションになっている場合は、「ASP.NET Core Blazor のホストと展開」記事の「アプリのベース パス」セクションのガイダンスに従ってください。HeadOutlet コンポーネントは、Razor コンポーネントによって設定されたページタイトル (PageTitle コンポーネント) とその他の head 要素 (HeadContent コンポーネント) の head (
<head>
) コンテンツをレンダリングするために使用されます。 詳しくは、「ASP.NET Core Blazor アプリで コンテンツを制御する」をご覧ください。blazor.server.js
スクリプトの<script>
タグを、Scripts
レンダリング セクション (@await RenderSectionAsync(...)
) の直前に追加します。<script src="_framework/blazor.server.js"></script>
フレームワークによって
blazor.server.js
スクリプトがアプリに追加されます。blazor.server.js
スクリプト ファイルをアプリに手動で追加する必要はありません。
Note
通常、レイアウトは
_ViewStart.cshtml
ファイルを介して読み込まれます。Blazor Server サービスを、サービスの登録先である
Program.cs
に登録します。builder.Services.AddServerSideBlazor();
Blazor ハブ エンドポイントを、ルートがマップされる
Program.cs
のエンドポイントに追加します。MapRazorPages
(Razor Pages) またはMapControllerRoute
(MVC) の呼び出しの後に、次の行を配置します。app.MapBlazorHub();
コンポーネントを任意のページまたはビューに統合します。 たとえば、プロジェクトの
Shared
フォルダーにCounter
コンポーネントを追加します。Pages/Shared/Counter.razor
(Razor Pages) またはViews/Shared/Counter.razor
(MVC):<h1>Counter</h1> <p>Current count: @currentCount</p> <button class="btn btn-primary" @onclick="IncrementCount">Click me</button> @code { private int currentCount = 0; private void IncrementCount() { currentCount++; } }
Razor Pages:
Razor Pages アプリのプロジェクトの
Index
ページで、Counter
コンポーネントの名前空間を追加し、そのコンポーネントをページに埋め込みます。Index
ページが読み込まれるとき、Counter
コンポーネントはページにプリレンダリングされます。 次の例では、{APP NAMESPACE}
プレースホルダーをプロジェクトの名前空間に置き換えます。Pages/Index.cshtml
:@page @using {APP NAMESPACE}.Pages.Shared @model IndexModel @{ ViewData["Title"] = "Home page"; } <component type="typeof(Counter)" render-mode="ServerPrerendered" />
MVC:
MVC アプリのプロジェクトの
Index
ビューで、Counter
コンポーネントの名前空間を追加し、そのコンポーネントをビューに埋め込みます。Index
ビューが読み込まれるとき、Counter
コンポーネントはページにプリレンダリングされます。 次の例では、{APP NAMESPACE}
プレースホルダーをプロジェクトの名前空間に置き換えます。Views/Home/Index.cshtml
:@using {APP NAMESPACE}.Views.Shared @{ ViewData["Title"] = "Home Page"; } <component type="typeof(Counter)" render-mode="ServerPrerendered" />
詳細については、「ページまたはビューからコンポーネントをレンダリングする」セクションを参照してください。
Razor Pages アプリでルーティング可能なコンポーネントを使用する
ここは、ユーザー要求から直接ルーティング可能なコンポーネントを追加することに関係のあるセクションです。
Razor Pages アプリでルーティング可能な Razor コンポーネントをサポートするには、次のようにします。
「構成」セクションのガイダンスに従います。
次の内容の
App
コンポーネントをプロジェクト ルートに追加します。App.razor
:@using Microsoft.AspNetCore.Components.Routing <Router AppAssembly="typeof(App).Assembly"> <Found Context="routeData"> <RouteView RouteData="routeData" /> </Found> <NotFound> <PageTitle>Not found</PageTitle> <p role="alert">Sorry, there's nothing at this address.</p> </NotFound> </Router>
次の内容の
_Host
ページをプロジェクトに追加します。{APP NAMESPACE}
プレースホルダーをアプリの名前空間に置き換えます。Pages/_Host.cshtml
:@page @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers <component type="typeof(App)" render-mode="ServerPrerendered" />
注意
前の例では、HeadOutlet コンポーネントと Blazor スクリプト (
_framework/blazor.server.js
) がアプリのレイアウトによってレンダリングされることを前提としています。 詳細については、「構成」セクションを参照してください。RenderMode によって、
App
コンポーネントに対して以下の構成が行われます。- ページに事前レンダリングするかどうか。
- ページに静的 HTML としてレンダリングするかどうか。または、ユーザー エージェントから Blazor アプリをブートストラップするために必要な情報が含まれているかどうか。
パラメーターの渡し方や RenderMode の構成などのコンポーネント タグ ヘルパーの詳細については、「ASP.NET Core のコンポーネント タグ ヘルパー」を参照してください。
Program.cs
エンドポイントで、_Host
ページの優先度の低いルートを最後のエンドポイントとして追加します。app.MapFallbackToPage("/_Host");
ルーティング可能なコンポーネントをプロジェクトに追加します。 次の例は、Blazor プロジェクト テンプレート内の
Counter
コンポーネントに基づくRoutableCounter
コンポーネントです。Pages/RoutableCounter.razor
:@page "/routable-counter" <PageTitle>Routable Counter</PageTitle> <h1>Routable Counter</h1> <p>Current count: @currentCount</p> <button class="btn btn-primary" @onclick="IncrementCount">Click me</button> @code { private int currentCount = 0; private void IncrementCount() { currentCount++; } }
プロジェクトを実行し、
/routable-counter
のルーティング可能なRoutableCounter
コンポーネントに移動します。
名前空間の詳細については、「コンポーネントの名前空間」セクションを参照してください。
MVC アプリでルーティング可能なコンポーネントを使用する
ここは、ユーザー要求から直接ルーティング可能なコンポーネントを追加することに関係のあるセクションです。
MVC アプリでルーティング可能な Razor コンポーネントをサポートするには、次のようにします。
「構成」セクションのガイダンスに従います。
次の内容の
App
コンポーネントをプロジェクト ルートに追加します。App.razor
:@using Microsoft.AspNetCore.Components.Routing <Router AppAssembly="typeof(App).Assembly"> <Found Context="routeData"> <RouteView RouteData="routeData" /> </Found> <NotFound> <PageTitle>Not found</PageTitle> <p role="alert">Sorry, there's nothing at this address.</p> </NotFound> </Router>
次の内容の
_Host
ビューをプロジェクトに追加します。{APP NAMESPACE}
プレースホルダーをアプリの名前空間に置き換えます。Views/Home/_Host.cshtml
:@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers <component type="typeof(App)" render-mode="ServerPrerendered" />
注意
前の例では、HeadOutlet コンポーネントと Blazor スクリプト (
_framework/blazor.server.js
) がアプリのレイアウトによってレンダリングされることを前提としています。 詳細については、「構成」セクションを参照してください。RenderMode によって、
App
コンポーネントに対して以下の構成が行われます。- ページに事前レンダリングするかどうか。
- ページに静的 HTML としてレンダリングするかどうか。または、ユーザー エージェントから Blazor アプリをブートストラップするために必要な情報が含まれているかどうか。
パラメーターの渡し方や RenderMode の構成などのコンポーネント タグ ヘルパーの詳細については、「ASP.NET Core のコンポーネント タグ ヘルパー」を参照してください。
Home コントローラーにアクションを追加します。
Controllers/HomeController.cs
:public IActionResult Blazor() { return View("_Host"); }
Program.cs
エンドポイントに、_Host
ビューを返すコントローラー アクションのために、優先度が低いルートを追加します。app.MapFallbackToController("Blazor", "Home");
MVC アプリに
Pages
フォルダーを作成し、ルーティング可能なコンポーネントを追加します。 次の例は、Blazor プロジェクト テンプレート内のCounter
コンポーネントに基づくRoutableCounter
コンポーネントです。Pages/RoutableCounter.razor
:@page "/routable-counter" <PageTitle>Routable Counter</PageTitle> <h1>Routable Counter</h1> <p>Current count: @currentCount</p> <button class="btn btn-primary" @onclick="IncrementCount">Click me</button> @code { private int currentCount = 0; private void IncrementCount() { currentCount++; } }
プロジェクトを実行し、
/routable-counter
のルーティング可能なRoutableCounter
コンポーネントに移動します。
名前空間の詳細については、「コンポーネントの名前空間」セクションを参照してください。
ページまたはビューからコンポーネントをレンダリングする
これは、コンポーネントをユーザー要求から直接ルーティングできないページまたはビューにコンポーネントを追加することに関係するセクションです。
ページまたはビューからコンポーネントをレンダリングするには、コンポーネント タグ ヘルパーを使用します。
ステートフル対話型コンポーネントをレンダリングする
Razor ページまたはビューには、ステートフル対話型コンポーネントを追加できます。
ページまたはビューがレンダリングされると、次の処理が行われます。
- ページまたはビューと共にコンポーネントがプリレンダリングされます。
- プリレンダリングに使用された初期のコンポーネント状態は失われます。
- SignalR 接続が確立されると、新しいコンポーネント状態が作成されます。
次の Razor ページには、Counter
コンポーネントがレンダリングされます。
<h1>Razor Page</h1>
<component type="typeof(Counter)" render-mode="ServerPrerendered"
param-InitialValue="InitialValue" />
@functions {
[BindProperty(SupportsGet=true)]
public int InitialValue { get; set; }
}
詳細については、「ASP.NET Core のコンポーネント タグ ヘルパー」を参照してください。
非対話型コンポーネントをレンダリングする
次の Razor ページには、フォームを使用して指定された初期値を使用して、Counter
コンポーネントが静的にレンダリングされます。 コンポーネントは静的にレンダリングされるため、コンポーネントは対話型ではありません。
<h1>Razor Page</h1>
<form>
<input type="number" asp-for="InitialValue" />
<button type="submit">Set initial value</button>
</form>
<component type="typeof(Counter)" render-mode="Static"
param-InitialValue="InitialValue" />
@functions {
[BindProperty(SupportsGet=true)]
public int InitialValue { get; set; }
}
詳細については、「ASP.NET Core のコンポーネント タグ ヘルパー」を参照してください。
コンポーネントの名前空間
カスタム フォルダーを使用してプロジェクトの Razor コンポーネントを保持する場合は、フォルダーを表す名前空間を、ページまたはビューのいずれかに追加するか、_ViewImports.cshtml
ファイルに追加します。 次に例を示します。
- コンポーネントはプロジェクトの
Components
フォルダーに格納されます。 {APP NAMESPACE}
プレースホルダーはロジェクトの名前空間です。Components
はフォルダーの名前を表します。
@using {APP NAMESPACE}.Components
_ViewImports.cshtml
ファイルは、Razor Pages アプリの Pages
フォルダーまたは MVC アプリの Views
フォルダーにあります。
詳細については、「ASP.NET Core Razor コンポーネント」を参照してください。
プリレンダリングされた状態を保持する
プリレンダリングされた状態を保持しないと、プリレンダリング中に使用された状態は失われ、アプリが完全に読み込まれたときに再作成する必要があります。 いずれかの状態が非同期でセットアップされている場合、プリレンダリングされた UI は一時的なプレースホルダーに置き換えられてから再度完全にレンダリングされるため、UI がちらつくことがあります。
プリレンダリング済みコンポーネントの状態を保持するには、コンポーネントの状態保持タグ ヘルパー (参照ソース) を使用します。 コンポーネントをプリレンダリングするアプリの _Host
ページの </body>
の終了タグの内側に、タグ ヘルパのタグ <persist-component-state />
を追加します。
Note
通常、.NET 参照ソースへのドキュメント リンクを使用すると、リポジトリの既定のブランチが読み込まれます。このブランチは、.NET の次回リリースに向けて行われている現在の開発を表します。 特定のリリースのタグを選択するには、[Switch branches or tags](ブランチまたはタグの切り替え) ドロップダウン リストを使います。 詳細については、「ASP.NET Core ソース コードのバージョン タグを選択する方法」 (dotnet/AspNetCore.Docs #26205) を参照してください。
ホストされた Blazor WebAssembly アプリのプリレンダリングされた WebAssembly (WebAssemblyPrerendered
) または Blazor Server アプリの ServerPrerendered
である、Blazor アプリの Pages/_Host.cshtml
内:
<body>
...
<persist-component-state />
</body>
PersistentComponentState サービスを使用してどの状態を永続化するか決定します。 アプリが一時停止される前に、PersistentComponentState.RegisterOnPersisting
によってコールバックが登録され、コンポーネントの状態が保持されます。 状態は、アプリケーションの再開時に取得されます。
次に例を示します。
{TYPE}
プレースホルダーは、(WeatherForecast[]
など) 永続化するデータの種類を表します。{TOKEN}
プレースホルダーは、(fetchdata
など) 状態識別子の文字列です。
@implements IDisposable
@inject PersistentComponentState ApplicationState
...
@code {
private {TYPE} data;
private PersistingComponentStateSubscription persistingSubscription;
protected override async Task OnInitializedAsync()
{
persistingSubscription =
ApplicationState.RegisterOnPersisting(PersistData);
if (!ApplicationState.TryTakeFromJson<{TYPE}>(
"{TOKEN}", out var restored))
{
data = await ...;
}
else
{
data = restored!;
}
}
private Task PersistData()
{
ApplicationState.PersistAsJson("{TOKEN}", data);
return Task.CompletedTask;
}
void IDisposable.Dispose()
{
persistingSubscription.Dispose();
}
}
次の例は、Blazor プロジェクト テンプレートに基づいた、ホストされている Blazor WebAssembly アプリ内の FetchData
コンポーネントの更新バージョンです。 WeatherForecastPreserveState
コンポーネントでは、プリレンダリング中に天気予報の状態を保持し、コンポーネントを初期化するために状態が取得されます。 永続コンポーネントの状態タグ ヘルパーでは、すべてのコンポーネントの呼び出しの後で、コンポーネントの状態を保持します。
Pages/WeatherForecastPreserveState.razor
:
@page "/weather-forecast-preserve-state"
@using BlazorSample.Shared
@implements IDisposable
@inject IWeatherForecastService WeatherForecastService
@inject PersistentComponentState ApplicationState
<PageTitle>Weather Forecast</PageTitle>
<h1>Weather forecast</h1>
<p>This component demonstrates fetching data from the server.</p>
@if (forecasts == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
}
@code {
private WeatherForecast[] forecasts = Array.Empty<WeatherForecast>();
private PersistingComponentStateSubscription persistingSubscription;
protected override async Task OnInitializedAsync()
{
persistingSubscription =
ApplicationState.RegisterOnPersisting(PersistForecasts);
if (!ApplicationState.TryTakeFromJson<WeatherForecast[]>(
"fetchdata", out var restored))
{
forecasts =
await WeatherForecastService.GetForecastAsync(DateOnly.FromDateTime(DateTime.Now));
}
else
{
forecasts = restored!;
}
}
private Task PersistForecasts()
{
ApplicationState.PersistAsJson("fetchdata", forecasts);
return Task.CompletedTask;
}
void IDisposable.Dispose()
{
persistingSubscription.Dispose();
}
}
プリレンダリング中に使用されたのと同じ状態でコンポーネントを初期化することにより、負荷の高い初期化ステップが 1 回だけ実行されます。 レンダリングされた UI もプリレンダリングされた UI に一致するので、ブラウザーでちらつきは発生しません。
永続化されたプリレンダリングされた状態はクライアントに転送され、そこでコンポーネントの状態を復元するために使用されます。 コア データ保護 ASP.NETBlazor Serverアプリでデータが安全に転送されるようにします。 ホストされている Blazor WebAssembly アプリでプリレンダリングを行う場合、データはブラウザーに公開され、機密情報を含む必要はありません。
Blazor WebAssembly のその他のリソース
- 状態管理: プリレンダリングを処理する
- アセンブリ遅延読み込みによるプリレンダリングのサポート
- プリレンダリングに関連する Razor コンポーネント ライフサイクルの話題
- コンポーネントの初期化 (
OnInitialized{Async}
) - コンポーネントのレンダリング後 (
OnAfterRender{Async}
) - プリレンダリング後のステートフル再接続: このセクションの内容では、Blazor Server およびステートフルな SignalR の "再接続" に焦点を当てていますが、ホストされた Blazor WebAssembly アプリ (WebAssemblyPrerendered) でのプリレンダリングのシナリオでは、開発者コードを 2 回実行しないようにするための同様の条件とアプローチが必要です。 プリレンダリング中に初期化コードの実行中に状態を保持するには、この記事の「プリレンダリングされた状態を保持する」セクションを参照してください。
- JavaScript 相互運用を使用したプリレンダリング
- コンポーネントの初期化 (
- プリレンダリングに関連する認証と認可の話題
- ホストと展開: Blazor WebAssembly
- エラーを処理する: プリレンダリング
- OnNavigateAsync は、プリレンダリング時に 2 回実行されます。
OnNavigateAsync
で非同期ナビゲーション イベントを処理する
プリレンダリングされた状態サイズと SignalR メッセージ サイズの制限
大規模なプリレンダリングされた状態サイズが SignalR 回線メッセージ サイズの制限を超える可能性があり、その結果、次のようになります。
- この SignalR 回線は、クライアントで次のエラーで初期化に失敗します: Circuit host not initialized.
- 回線が失敗状態になると、クライアント側に再接続 UI が表示されます。 復旧はできません。
この問題を解決するには、次の "いずれかの" 方法を使用します。
- プリレンダリングされた状態に入れるデータの量を減らします。
- SignalR メッセージ サイズの制限を増やします。 警告: 上限を引き上げると、サービス拒否 (DoS) 攻撃のリスクが高まる可能性があります。
Blazor Server のその他のリソース
- 状態管理: プリレンダリングを処理する
- プリレンダリングに関連する Razor コンポーネント ライフサイクルの話題
- 認証と認可: 一般的な側面
- エラーを処理する: プリレンダリング
- ホストと展開: Blazor Server
- 脅威の緩和: クロスサイト スクリプティング (XSS)
- OnNavigateAsync は、プリレンダリング時に 2 回実行されます。
OnNavigateAsync
で非同期ナビゲーション イベントを処理する
ホストされる Blazor WebAssemblyソリューションの Razor Pages と MVC アプリに Razor コンポーネントを統合できます。 ページまたはビューがレンダリングされるときには、コンポーネントを同時に事前レンダリングすることができます。
プリレンダリングにより、検索エンジンがページ ランクの計算に使える最初の HTTP 応答の内容がレンダリングされることで、検索エンジンの最適化 (SEO) が向上します。
ソリューションの構成
プリレンダリングの構成
ホストされる Blazor WebAssembly アプリのプリレンダリングを設定するには:
ASP.NET Core アプリで Blazor WebAssembly をホストします。 スタンドアロンの Blazor WebAssembly アプリを ASP.NET Core ソリューションに追加することも、hosted たオプションを使用して Blazor WebAssembly プロジェクト テンプレートから作成されたホスト型の Blazor WebAssembly アプリを使用することもできます。
- Visual Studio: Blazor WebAssembly アプリの作成時に、[追加情報] ダイアログで [ASP.NET Core Hosted] (ASP.NET Core ホステッド) チェックボックスをオンにします。 この記事の例では、ソリューションに
BlazorHosted
という名前が付けられています。 - Visual Studio Code/.NET CLI コマンド シェル:
dotnet new blazorwasm -ho
(-ho|--hosted
オプションを使用)。-o|--output {LOCATION}
オプションを使用してソリューションのフォルダーを作成し、ソリューションのプロジェクト名前空間を設定します。 この記事の例では、ソリューションにBlazorHosted
という名前が付けられています (dotnet new blazorwasm -ho -o BlazorHosted
)。
この記事の例では、クライアント プロジェクトの名前空間は
BlazorHosted.Client
で、サーバー プロジェクトの名前空間はBlazorHosted.Server
です。- Visual Studio: Blazor WebAssembly アプリの作成時に、[追加情報] ダイアログで [ASP.NET Core Hosted] (ASP.NET Core ホステッド) チェックボックスをオンにします。 この記事の例では、ソリューションに
Blazor WebAssemblyClient プロジェクトから
wwwroot/index.html
ファイルを削除します。Client プロジェクトで、
Program.cs
の次の行を削除します。- builder.RootComponents.Add<App>("#app"); - builder.RootComponents.Add<HeadOutlet>("head::after");
_Host.cshtml
ファイルと_Layout.cshtml
ファイルを Server プロジェクトのPages
フォルダーに追加します。 これらのファイルは、Visual Studio または .NET CLI のコマンド シェルでdotnet new blazorserver -o BlazorServer
コマンドを使用して Blazor Server テンプレートから作成されたプロジェクトから取得できます (-o BlazorServer
オプションを指定すると、プロジェクトのフォルダーが作成されます)。 Server プロジェクトのPages
フォルダーにファイルを配置した後、ファイルに次の変更を加えます。重要
ページのタイトル (PageTitle コンポーネント) や他の head 要素 (HeadContent コンポーネント) などの
<head>
コンテンツを制御するには、HeadOutlet コンポーネントのコンポーネント タグ ヘルパーでレイアウト ページ (_Layout.cshtml
) を使用する必要があります。 詳しくは、「ASP.NET Core Blazor アプリで コンテンツを制御する」をご覧ください。_Layout.cshtml
ファイルに次の変更を加えます。ファイルの先頭にある
Pages
名前空間を更新し、 Server アプリのページの名前空間と一致させます。 次の例に示す{APP NAMESPACE}
プレースホルダーは、_Layout.cshtml
ファイルを提供したドナー アプリのページの名前空間を表します。削除:
- @namespace {APP NAMESPACE}.Pages
次の項目を追加します。
@namespace BlazorHosted.Server.Pages
ファイルの先頭に、 Client プロジェクトの
@using
ディレクティブを追加します。@using BlazorHosted.Client
スタイルシートのリンクを、WebAssembly プロジェクトのスタイルシートをポイントするように更新します。 次の例では、クライアント プロジェクトの名前空間は
BlazorHosted.Client
になります。{APP NAMESPACE}
プレースホルダーは、_Layout.cshtml
ファイルを提供したドナー アプリの名前空間を表します。HeadOutlet
コンポーネントのコンポーネント タグ ヘルパー (<component>
タグ) を、コンポーネントをプリレンダリングするように更新します。削除:
- <link href="css/site.css" rel="stylesheet" /> - <link href="{APP NAMESPACE}.styles.css" rel="stylesheet" /> - <component type="typeof(HeadOutlet)" render-mode="ServerPrerendered" />
次の項目を追加します。
<link href="css/app.css" rel="stylesheet" /> <link href="BlazorHosted.Client.styles.css" rel="stylesheet" /> <component type="typeof(HeadOutlet)" render-mode="WebAssemblyPrerendered" />
Note
ブートストラップ スタイルシート (
css/bootstrap/bootstrap.min.css
) を要求する<link>
要素はそのままにしておきます。Blazor スクリプトのソースを、クライアント側の Blazor WebAssembly スクリプトを使用するように更新します。
削除:
- <script src="_framework/blazor.server.js"></script>
次の項目を追加します。
<script src="_framework/blazor.webassembly.js"></script>
_Host.cshtml
ファイルで次の操作を行います。Pages
名前空間を Client プロジェクトの名前空間に変更します。{APP NAMESPACE}
プレースホルダーは、_Host.cshtml
ファイルを提供したドナー アプリのページの名前空間を表します。削除:
- @namespace {APP NAMESPACE}.Pages
次の項目を追加します。
@namespace BlazorHosted.Client
コンポーネント タグ ヘルパーの
render-mode
を、ルートのApp
コンポーネントを WebAssemblyPrerendered を使用してプリレンダリングするように更新します。削除:
- <component type="typeof(App)" render-mode="ServerPrerendered" />
次の項目を追加します。
<component type="typeof(App)" render-mode="WebAssemblyPrerendered" />
重要
プリレンダリングは認証エンドポイントではサポートされていません (
/authentication/
パス セグメント)。 詳細については、「ASP.NET Core Blazor WebAssembly のその他のセキュリティ シナリオ」を参照してください。
Program.cs
内の Server プロジェクトのエンドポイント マッピングで、フォールバックをindex.html
ファイルから_Host.cshtml
ページに変更します。削除:
- app.MapFallbackToFile("index.html");
次の項目を追加します。
app.MapFallbackToPage("/_Host");
Client プロジェクトと Server プロジェクトでプリレンダリング中に 1 つまたは複数の一般的サービスが使用される場合、両方のプロジェクトから呼び出せるメソッドにサービス登録を入れます。 詳細については、「ASP.NET Core Blazor の依存関係の挿入」を参照してください。
Server プロジェクトを実行します。 ホストされる Blazor WebAssembly アプリは、クライアントの Server プロジェクトによってプリレンダリングされ ます。
Razor コンポーネントをページおよびビューに埋め込むための構成
ClientBlazor WebAssembly アプリの Razor コンポーネントをサーバー アプリのページとビューに埋め込むための次のセクションと例では、追加の構成が必要です。
Server プロジェクトには 次のファイルとフォルダーが含まれている必要があります。
Razor Pages:
Pages/Shared/_Layout.cshtml
Pages/Shared/_Layout.cshtml.css
Pages/_ViewImports.cshtml
Pages/_ViewStart.cshtml
MVC:
Views/Shared/_Layout.cshtml
Views/Shared/_Layout.cshtml.css
Views/_ViewImports.cshtml
Views/_ViewStart.cshtml
重要
ページのタイトル (PageTitle コンポーネント) や他の head 要素 (HeadContent コンポーネント) などの <head>
コンテンツを制御するには、HeadOutlet コンポーネントのコンポーネント タグ ヘルパーでレイアウト ページ (_Layout.cshtml
) を使用する必要があります。 詳しくは、「ASP.NET Core Blazor アプリで コンテンツを制御する」をご覧ください。
上記のファイルは、次の方法で ASP.NET Core プロジェクト テンプレートからアプリを生成することによって取得できます。
- Visual Studio の新しいプロジェクト作成ツール。
- コマンド シェルを開き、
dotnet new webapp -o {PROJECT NAME}
(Razor Pages) またはdotnet new mvc -o {PROJECT NAME}
(MVC) を実行する。{PROJECT NAME}
プレースホルダーの値を持つ-o|--output
オプションは、アプリの名前を指定して、アプリのフォルダーを作成します。
インポートされた _ViewImports.cshtml
ファイル内の名前空間を、ファイルを受け取る Server プロジェクトで使用されているものと一致するように更新します。
Pages/_ViewImports.cshtml
(Razor Pages):
@using BlazorHosted.Server
@namespace BlazorHosted.Server.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
Views/_ViewImports.cshtml
(MVC):
@using BlazorHosted.Server
@using BlazorHosted.Server.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
インポートされたレイアウト ファイルを更新します。これは、Razor Pages の場合は Pages/Shared/_Layout.cshtml
、MVC の場合は Views/Shared/_Layout.cshtml
です。
最初に、ドナー プロジェクトからタイトルとスタイルシートを削除します。これは、次の例では RPDonor.styles.css
です。 {PROJECT NAME}
プレースホルダーは、ドナー プロジェクトのアプリ名を表します。
- <title>@ViewData["Title"] - {PROJECT NAME}</title>
- <link rel="stylesheet" href="~/RPDonor.styles.css" asp-append-version="true" />
レイアウト ファイルに Client プロジェクトのスタイルを含めます。 次の例では、 Client プロジェクトの名前空間は BlazorHosted.Client
になります。 <title>
要素は同時に更新できます。
レイアウト ファイルの <head>
の内容に次の行を配置します。
<title>@ViewData["Title"] - BlazorHosted</title>
<link href="css/app.css" rel="stylesheet" />
<link rel="stylesheet" href="BlazorHosted.Client.styles.css" asp-append-version="true" />
<component type="typeof(HeadOutlet)" render-mode="WebAssemblyPrerendered" />
インポートされたレイアウトには 2 つの Home
Index
ページと Privacy
のナビゲーション リンクが含まれます。 Home
リンクが、ホストされる Blazor WebAssembly アプリを指すようにするには、ハイパーリンクを次のように変更します。
- <a class="navbar-brand" asp-area="" asp-page="/Index">{PROJECT NAME}</a>
+ <a class="navbar-brand" href="/">BlazorHosted</a>
- <a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
+ <a class="nav-link text-dark" href="/">Home</a>
MVC レイアウト ファイルの場合:
- <a class="navbar-brand" asp-area="" asp-controller="Home"
- asp-action="Index">{PROJECT NAME}</a>
+ <a class="navbar-brand" href="/">BlazorHosted</a>
- <a class="nav-link text-dark" asp-area="" asp-controller="Home"
- asp-action="Index">Home</a>
+ <a class="nav-link text-dark" href="/">Home</a>
<footer>
要素のアプリ名を更新します。 次の例では、BlazorHosted
というアプリ名を使用しています。
- © {DATE} - {DONOR NAME} - <a asp-area="" asp-page="/Privacy">Privacy</a>
+ © {DATE} - BlazorHosted - <a asp-area="" asp-page="/Privacy">Privacy</a>
前の例では、{DATE}
プレースホルダーは Razor Pages または MVC プロジェクト テンプレートから生成されたアプリの著作権日を表します。
Privacy
リンクが privacy ページ (Razor Pages) につながるようにするには、privacy ページを Server プロジェクトに追加します。
Server プロジェクトの Pages/Privacy.cshtml
:
@page
@model PrivacyModel
@{
ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>
<p>Use this page to detail your site's privacy policy.</p>
MVC ベースの privacy ビューの場合は、Server プロジェクトで privacy ビューを作成します。
Server プロジェクトの View/Home/Privacy.cshtml
:
@{
ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>
<p>Use this page to detail your site's privacy policy.</p>
MVC アプリの Home
コントローラーで、ビューを返します。
Controllers/HomeController.cs
に次のコードを追加します。
public IActionResult Privacy()
{
return View();
}
ドナー アプリからファイルをインポートする場合は、ファイル内のすべての名前空間を更新して、 Server プロジェクトの名前空間 (たとえば、BlazorHosted.Server
) に一致させてください。
ドナー プロジェクトの wwwroot
フォルダーから Server プロジェクトに静的アセットをインポートします。
wwwroot/css
フォルダーと内容wwwroot/js
フォルダーと内容wwwroot/lib
フォルダーと内容
ドナー プロジェクトが ASP.NET Core プロジェクト テンプレートから作成され、ファイルが変更されていない場合は、ドナー プロジェクトの wwwroot
フォルダー全体を Server プロジェクトにコピー して、favicon アイコン ファイルを削除することができます。
警告
静的アセットを Client フォルダーと Server wwwroot
フォルダーの両方に配置するのは避けてください。 両方のフォルダーに同じファイルがある場合は、各フォルダー内の静的アセットが同じ Web ルート パスを共有しているため、例外がスローされます。 そのため、静的アセットを両方ではなく、いずれかの wwwroot
フォルダーにホストします。
上記の構成を採用した後で、Razor コンポーネントを Server プロジェクトのページまたはビューに埋め込みます。 この記事の以降のセクションのガイダンスを使用してください。
- コンポーネント タグ ヘルパーを使用してページまたはビューのコンポーネントをレンダリングする
- CSS セレクターを使用してページまたはビューのコンポーネントをレンダリングする
コンポーネント タグ ヘルパーを使用してページまたはビューのコンポーネントをレンダリングする
追加構成を含むソリューションを構成した後、コンポーネント タグ ヘルパーは、Blazor WebAssembly アプリのコンポーネントをページまたはビュー内にレンダリングするための 2 つのレンダー モードをサポートします。
次の Razor Pages の例では、Counter
コンポーネントがページにレンダリングされます。 コンポーネントを対話形式にするために、ページのレンダリング セクションに Blazor WebAssembly スクリプトが含まれます。 コンポーネント タグ ヘルパーによる Counter
コンポーネントの完全な名前空間 ({ASSEMBLY NAME}.Pages.Counter
) の使用を避けるために、クライアント プロジェクトの Pages
名前空間に @using
ディレクティブを追加します。 次の例では、 Client プロジェクトの名前空間は BlazorHosted.Client
になります。
Server プロジェクトの Pages/RazorPagesCounter1.cshtml
:
@page
@using BlazorHosted.Client.Pages
<component type="typeof(Counter)" render-mode="WebAssemblyPrerendered" />
@section Scripts {
<script src="_framework/blazor.webassembly.js"></script>
}
Server プロジェクトを実行します。 /razorpagescounter1
の Razor ページに移動します。 プリレンダリングされた Counter
コンポーネントはページに埋め込まれています。
RenderMode によって、コンポーネントに対して以下の構成が行われます。
- ページに事前レンダリングするかどうか。
- ページに静的 HTML としてレンダリングするかどうか。または、ユーザー エージェントから Blazor アプリをブートストラップするために必要な情報が含まれているかどうか。
パラメーターの渡し方や RenderMode の構成などのコンポーネント タグ ヘルパーの詳細については、「ASP.NET Core のコンポーネント タグ ヘルパー」を参照してください。
コンポーネントによって使用される静的リソースや、アプリでのレイアウト ページの整理方法によっては、追加の作業が必要になる場合があります。 通常、ページまたはビューの Scripts
レンダー セクションにスクリプトが追加され、スタイル シートはレイアウトの <head>
要素コンテンツに追加されます。
レンダリング フラグメントを使用して子コンテンツを設定する
コンポーネント タグ ヘルパーでは、子コンテンツの RenderFragment
デリゲート (param-ChildContent="..."
など) の受信をサポートしていません。 渡される子コンテンツを使用してレンダリングするコンポーネントを参照する Razor コンポーネント (.razor
) を作成し、ページまたはビューから Razor コンポーネントを呼び出すことをお勧めします。
最上位のプリレンダリングされたコンポーネントが発行時にトリミングされないようにする
コンポーネント タグ ヘルパーが、発行時にトリミングの対象となるライブラリからコンポーネントを直接参照している場合は、クライアント側のアプリ コードからの参照がないため、発行時にコンポーネントがトリミングされる可能性があります。 その結果、コンポーネントはプリレンダリングされず、出力に空白が残ります。 この問題が発生した場合は、クライアント側アプリの任意のクラスに DynamicDependency
属性を追加して、ライブラリ コンポーネントを保持するようにトリマーに指示します。 SomeLibraryComponentToBePreserved
というコンポーネントを保持するには、任意のコンポーネントに次を追加します。
@using System.Diagnostics.CodeAnalysis
@attribute [DynamicDependency(DynamicallyAccessedMemberTypes.All,
typeof(SomeLibraryComponentToBePreserved))]
通常、アプリでは (トリミングされていない) コンポーネントをプリレンダリングするため、上記の方法は通常、必要ありません。これにより、ライブラリからコンポーネントが参照されます (これにより、トリミングもされません)。 ライブラリをトリミングするときにライブラリ コンポーネントを直接プリレンダリングする場合にのみ、DynamicDependency
を明示的に使用します。
CSS セレクターを使用してページまたはビューのコンポーネントをレンダリングする
追加の構成を含めてソリューションを構成した後、Program.cs
ファイルでホストされる Blazor WebAssembly ソリューションの Client プロジェクトにルート コンポーネントを追加します。 次の例では、counter-component
と一致する id
を持つ要素を選択する CSS セレクターを使用して、ルート コンポーネントとして Counter
コンポーネントが宣言されています。 次の例では、 Client プロジェクトの名前空間は BlazorHosted.Client
になります。
Client プロジェクトの Program.cs
ファイルで、プロジェクトの Razor コンポーネントの名前空間をファイルの先頭に追加します。
using BlazorHosted.Client.Pages;
Program.cs
で builder
が確立されたら、Counter
コンポーネントをルート コンポーネントとして追加します。
builder.RootComponents.Add<Counter>("#counter-component");
次の Razor Pages の例では、Counter
コンポーネントがページにレンダリングされます。 コンポーネントを対話形式にするために、ページのレンダリング セクションに Blazor WebAssembly スクリプトが含まれます。
Server プロジェクトの Pages/RazorPagesCounter2.cshtml
:
@page
<div id="counter-component">Loading...</div>
@section Scripts {
<script src="_framework/blazor.webassembly.js"></script>
}
Server プロジェクトを実行します。 /razorpagescounter2
の Razor ページに移動します。 プリレンダリングされた Counter
コンポーネントはページに埋め込まれています。
コンポーネントによって使用される静的リソースや、アプリでのレイアウト ページの整理方法によっては、追加の作業が必要になる場合があります。 通常、ページまたはビューの Scripts
レンダー セクションにスクリプトが追加され、スタイル シートはレイアウトの <head>
要素コンテンツに追加されます。
Note
前の例では、Blazor WebAssembly アプリが CSS セレクターを使用して Razor Pages または MVC アプリに同時にプリレンダリングおよび統合された場合に JSException がスローされます。 Client プロジェクトのいずれかの Razor コンポーネントに移動するか、埋め込みコンポーネントを含む Server のページまたはビューに移動すると、1 つ以上の JSException がスローされます。
ルーティング可能な Razor コンポーネントを使用した Blazor WebAssembly アプリのプリレンダリングおよび統合は、CSS セレクターの使用と両立しないため、これは通常の動作です。
前のセクションの例を使用している状態で、サンプル アプリで CSS セレクターが動作することを確認するだけの場合は、 Client プロジェクトの Program.cs
ファイルの App
ルート コンポーネントの仕様をコメント アウトしてください。
- builder.RootComponents.Add<App>("#app");
+ //builder.RootComponents.Add<App>("#app");
CSS セレクターを使用する埋め込みの Razor コンポーネント (たとえば、前の例の /razorpagescounter2
) を含むページまたはビューに移動します。 ページまたはビューが埋め込みコンポーネントと共に読み込まれ、埋め込みコンポーネントは想定どおりに機能します。
Razor コンポーネントは、Razor Pages と MVC アプリに統合できます。 ページまたはビューがレンダリングされるときには、コンポーネントを同時に事前レンダリングすることができます。
プリレンダリングにより、検索エンジンがページ ランクの計算に使える最初の HTTP 応答の内容がレンダリングされることで、検索エンジンの最適化 (SEO) が向上します。
プロジェクトを構成した後、プロジェクトの要件に応じて、次のセクションのガイダンスを使用します。
- ルーティング可能なコンポーネント:ユーザー要求から直接ルーティング可能なコンポーネント。 訪問者が
@page
ディレクティブを含むコンポーネントのブラウザーで HTTP 要求を行うことができる必要がある場合は、このガイダンスに従ってください。 - ページまたはビューからコンポーネントをレンダリングする:ユーザー要求から直接ルーティングできないコンポーネント。 アプリによってコンポーネント タグ ヘルパーを含む既存のページやビューにコンポーネントが埋め込まれる場合は、このガイダンスに従ってください。
構成
次のガイダンスを使用して、既存の Razor Pages または MVC アプリのページとビューに Razor コンポーネントを統合します。
重要
ページのタイトル (PageTitle コンポーネント) や他の head 要素 (HeadContent コンポーネント) などの <head>
コンテンツを制御するには、HeadOutlet コンポーネントのコンポーネント タグ ヘルパーでレイアウト ページ (_Layout.cshtml
) を使用する必要があります。 詳しくは、「ASP.NET Core Blazor アプリで コンテンツを制御する」をご覧ください。
プロジェクトのレイアウト ファイルで、次のようにします。
Pages/Shared/_Layout.cshtml
(Razor Pages) またはViews/Shared/_Layout.cshtml
(MVC) の<head>
要素に次の<base>
タグと HeadOutlet コンポーネント タグ ヘルパーを追加します。<base href="~/" /> <component type="typeof(HeadOutlet)" render-mode="ServerPrerendered" />
前の例の
href
値 (アプリ ベースのパス) は、アプリがルート URL パス (/
) に置かれていることを前提としています。 アプリがサブアプリケーションになっている場合は、「ASP.NET Core Blazor のホストと展開」記事の「アプリのベース パス」セクションのガイダンスに従ってください。HeadOutlet コンポーネントは、Razor コンポーネントによって設定されたページタイトル (PageTitle コンポーネント) とその他の head 要素 (HeadContent コンポーネント) の head (
<head>
) コンテンツをレンダリングするために使用されます。 詳しくは、「ASP.NET Core Blazor アプリで コンテンツを制御する」をご覧ください。blazor.server.js
スクリプトの<script>
タグを、アプリのレイアウトのScripts
レンダリング セクション (@await RenderSectionAsync(...)
) の直前に追加します。Pages/Shared/_Layout.cshtml
(Razor Pages) またはViews/Shared/_Layout.cshtml
(MVC):<script src="_framework/blazor.server.js"></script>
フレームワークによって
blazor.server.js
スクリプトがアプリに追加されます。blazor.server.js
スクリプト ファイルをアプリに手動で追加する必要はありません。
次の内容の imports ファイルをプロジェクトのルート フォルダーに追加します。
{APP NAMESPACE}
プレースホルダーをプロジェクトの名前空間に変更します。_Imports.razor
:@using System.Net.Http @using Microsoft.AspNetCore.Authorization @using Microsoft.AspNetCore.Components.Authorization @using Microsoft.AspNetCore.Components.Forms @using Microsoft.AspNetCore.Components.Routing @using Microsoft.AspNetCore.Components.Web @using Microsoft.AspNetCore.Components.Web.Virtualization @using Microsoft.JSInterop @using {APP NAMESPACE}
Blazor Server サービスを、サービスの登録先である
Program.cs
に登録します。builder.Services.AddServerSideBlazor();
Blazor ハブ エンドポイントを、ルートがマップされる
Program.cs
のエンドポイントに追加します。MapRazorPages
(Razor Pages) またはMapControllerRoute
(MVC) の呼び出しの後に、次の行を配置します。app.MapBlazorHub();
コンポーネントを任意のページまたはビューに統合します。 たとえば、プロジェクトの
Shared
フォルダーにCounter
コンポーネントを追加します。Pages/Shared/Counter.razor
(Razor Pages) またはViews/Shared/Counter.razor
(MVC):<h1>Counter</h1> <p>Current count: @currentCount</p> <button class="btn btn-primary" @onclick="IncrementCount">Click me</button> @code { private int currentCount = 0; private void IncrementCount() { currentCount++; } }
Razor Pages:
Razor Pages アプリのプロジェクトの
Index
ページで、Counter
コンポーネントの名前空間を追加し、そのコンポーネントをページに埋め込みます。Index
ページが読み込まれるとき、Counter
コンポーネントはページにプリレンダリングされます。 次の例では、{APP NAMESPACE}
プレースホルダーをプロジェクトの名前空間に置き換えます。Pages/Index.cshtml
:@page @using {APP NAMESPACE}.Pages.Shared @model IndexModel @{ ViewData["Title"] = "Home page"; } <component type="typeof(Counter)" render-mode="ServerPrerendered" />
MVC:
MVC アプリのプロジェクトの
Index
ビューで、Counter
コンポーネントの名前空間を追加し、そのコンポーネントをビューに埋め込みます。Index
ビューが読み込まれるとき、Counter
コンポーネントはページにプリレンダリングされます。 次の例では、{APP NAMESPACE}
プレースホルダーをプロジェクトの名前空間に置き換えます。Views/Home/Index.cshtml
:@using {APP NAMESPACE}.Views.Shared @{ ViewData["Title"] = "Home Page"; } <component type="typeof(Counter)" render-mode="ServerPrerendered" />
詳細については、「ページまたはビューからコンポーネントをレンダリングする」セクションを参照してください。
Razor Pages アプリでルーティング可能なコンポーネントを使用する
ここは、ユーザー要求から直接ルーティング可能なコンポーネントを追加することに関係のあるセクションです。
Razor Pages アプリでルーティング可能な Razor コンポーネントをサポートするには、次のようにします。
「構成」セクションのガイダンスに従います。
次の内容の
App
コンポーネントをプロジェクト ルートに追加します。App.razor
:@using Microsoft.AspNetCore.Components.Routing <Router AppAssembly="typeof(App).Assembly"> <Found Context="routeData"> <RouteView RouteData="routeData" /> </Found> <NotFound> <PageTitle>Not found</PageTitle> <p role="alert">Sorry, there's nothing at this address.</p> </NotFound> </Router>
次の内容の
_Host
ページをプロジェクトに追加します。Pages/_Host.cshtml
:@page "/blazor" @namespace {APP NAMESPACE}.Pages.Shared @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers @{ Layout = "_Layout"; } <component type="typeof(App)" render-mode="ServerPrerendered" />
このシナリオのコンポーネントでは、そのレイアウトで共有される
_Layout.cshtml
ファイルが使用されます。重要
ページのタイトル (PageTitle コンポーネント) や他の head 要素 (HeadContent コンポーネント) などの
<head>
コンテンツを制御するには、HeadOutlet コンポーネントのコンポーネント タグ ヘルパーでレイアウト ページ (_Layout.cshtml
) を使用する必要があります。 詳しくは、「ASP.NET Core Blazor アプリで コンテンツを制御する」をご覧ください。RenderMode によって、
App
コンポーネントに対して以下の構成が行われます。- ページに事前レンダリングするかどうか。
- ページに静的 HTML としてレンダリングするかどうか。または、ユーザー エージェントから Blazor アプリをブートストラップするために必要な情報が含まれているかどうか。
パラメーターの渡し方や RenderMode の構成などのコンポーネント タグ ヘルパーの詳細については、「ASP.NET Core のコンポーネント タグ ヘルパー」を参照してください。
Program.cs
エンドポイントで、_Host
ページの優先度の低いルートを最後のエンドポイントとして追加します。app.MapFallbackToPage("/_Host");
ルーティング可能なコンポーネントをプロジェクトに追加します。 次の例は、Blazor プロジェクト テンプレート内の
Counter
コンポーネントに基づくRoutableCounter
コンポーネントです。Pages/RoutableCounter.razor
:@page "/routable-counter" <PageTitle>Routable Counter</PageTitle> <h1>Routable Counter</h1> <p>Current count: @currentCount</p> <button class="btn btn-primary" @onclick="IncrementCount">Click me</button> @code { private int currentCount = 0; private void IncrementCount() { currentCount++; } }
プロジェクトを実行し、
/routable-counter
のルーティング可能なRoutableCounter
コンポーネントに移動します。
名前空間の詳細については、「コンポーネントの名前空間」セクションを参照してください。
MVC アプリでルーティング可能なコンポーネントを使用する
ここは、ユーザー要求から直接ルーティング可能なコンポーネントを追加することに関係のあるセクションです。
MVC アプリでルーティング可能な Razor コンポーネントをサポートするには、次のようにします。
「構成」セクションのガイダンスに従います。
次の内容の
App
コンポーネントをプロジェクト ルートに追加します。App.razor
:@using Microsoft.AspNetCore.Components.Routing <Router AppAssembly="typeof(App).Assembly"> <Found Context="routeData"> <RouteView RouteData="routeData" /> </Found> <NotFound> <PageTitle>Not found</PageTitle> <p role="alert">Sorry, there's nothing at this address.</p> </NotFound> </Router>
次の内容の
_Host
ビューをプロジェクトに追加します。Views/Home/_Host.cshtml
:@namespace {APP NAMESPACE}.Views.Shared @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers @{ Layout = "_Layout"; } <component type="typeof(App)" render-mode="ServerPrerendered" />
コンポーネントでは、そのレイアウトで共有される
_Layout.cshtml
ファイルが使用されます。重要
ページのタイトル (PageTitle コンポーネント) や他の head 要素 (HeadContent コンポーネント) などの
<head>
コンテンツを制御するには、HeadOutlet コンポーネントのコンポーネント タグ ヘルパーでレイアウト ページ (_Layout.cshtml
) を使用する必要があります。 詳しくは、「ASP.NET Core Blazor アプリで コンテンツを制御する」をご覧ください。RenderMode によって、
App
コンポーネントに対して以下の構成が行われます。- ページに事前レンダリングするかどうか。
- ページに静的 HTML としてレンダリングするかどうか。または、ユーザー エージェントから Blazor アプリをブートストラップするために必要な情報が含まれているかどうか。
パラメーターの渡し方や RenderMode の構成などのコンポーネント タグ ヘルパーの詳細については、「ASP.NET Core のコンポーネント タグ ヘルパー」を参照してください。
Home コントローラーにアクションを追加します。
Controllers/HomeController.cs
:public IActionResult Blazor() { return View("_Host"); }
Program.cs
エンドポイントに、_Host
ビューを返すコントローラー アクションのために、優先度が低いルートを追加します。app.MapFallbackToController("Blazor", "Home");
MVC アプリに
Pages
フォルダーを作成し、ルーティング可能なコンポーネントを追加します。 次の例は、Blazor プロジェクト テンプレート内のCounter
コンポーネントに基づくRoutableCounter
コンポーネントです。Pages/RoutableCounter.razor
:@page "/routable-counter" <PageTitle>Routable Counter</PageTitle> <h1>Routable Counter</h1> <p>Current count: @currentCount</p> <button class="btn btn-primary" @onclick="IncrementCount">Click me</button> @code { private int currentCount = 0; private void IncrementCount() { currentCount++; } }
プロジェクトを実行し、
/routable-counter
のルーティング可能なRoutableCounter
コンポーネントに移動します。
名前空間の詳細については、「コンポーネントの名前空間」セクションを参照してください。
ページまたはビューからコンポーネントをレンダリングする
これは、コンポーネントをユーザー要求から直接ルーティングできないページまたはビューにコンポーネントを追加することに関係するセクションです。
ページまたはビューからコンポーネントをレンダリングするには、コンポーネント タグ ヘルパーを使用します。
ステートフル対話型コンポーネントをレンダリングする
Razor ページまたはビューには、ステートフル対話型コンポーネントを追加できます。
ページまたはビューがレンダリングされると、次の処理が行われます。
- ページまたはビューと共にコンポーネントがプリレンダリングされます。
- プリレンダリングに使用された初期のコンポーネント状態は失われます。
- SignalR 接続が確立されると、新しいコンポーネント状態が作成されます。
次の Razor ページには、Counter
コンポーネントがレンダリングされます。
<h1>Razor Page</h1>
<component type="typeof(Counter)" render-mode="ServerPrerendered"
param-InitialValue="InitialValue" />
@functions {
[BindProperty(SupportsGet=true)]
public int InitialValue { get; set; }
}
詳細については、「ASP.NET Core のコンポーネント タグ ヘルパー」を参照してください。
重要
ページのタイトル (PageTitle コンポーネント) や他の head 要素 (HeadContent コンポーネント) などの <head>
コンテンツを制御するには、HeadOutlet コンポーネントのコンポーネント タグ ヘルパーでレイアウト ページ (_Layout.cshtml
) を使用する必要があります。 詳しくは、「ASP.NET Core Blazor アプリで コンテンツを制御する」をご覧ください。
非対話型コンポーネントをレンダリングする
次の Razor ページには、フォームを使用して指定された初期値を使用して、Counter
コンポーネントが静的にレンダリングされます。 コンポーネントは静的にレンダリングされるため、コンポーネントは対話型ではありません。
<h1>Razor Page</h1>
<form>
<input type="number" asp-for="InitialValue" />
<button type="submit">Set initial value</button>
</form>
<component type="typeof(Counter)" render-mode="Static"
param-InitialValue="InitialValue" />
@functions {
[BindProperty(SupportsGet=true)]
public int InitialValue { get; set; }
}
詳細については、「ASP.NET Core のコンポーネント タグ ヘルパー」を参照してください。
重要
ページのタイトル (PageTitle コンポーネント) や他の head 要素 (HeadContent コンポーネント) などの <head>
コンテンツを制御するには、HeadOutlet コンポーネントのコンポーネント タグ ヘルパーでレイアウト ページ (_Layout.cshtml
) を使用する必要があります。 詳しくは、「ASP.NET Core Blazor アプリで コンテンツを制御する」をご覧ください。
コンポーネントの名前空間
カスタム フォルダーを使用してプロジェクトの Razor コンポーネントを保持する場合は、フォルダーを表す名前空間を、ページまたはビューのいずれかに追加するか、_ViewImports.cshtml
ファイルに追加します。 次に例を示します。
- コンポーネントはプロジェクトの
Components
フォルダーに格納されます。 {APP NAMESPACE}
プレースホルダーはロジェクトの名前空間です。Components
はフォルダーの名前を表します。
@using {APP NAMESPACE}.Components
_ViewImports.cshtml
ファイルは、Razor Pages アプリの Pages
フォルダーまたは MVC アプリの Views
フォルダーにあります。
詳細については、「ASP.NET Core Razor コンポーネント」を参照してください。
プリレンダリングされた状態を保持する
プリレンダリングされた状態を保持しないと、プリレンダリング中に使用された状態は失われ、アプリが完全に読み込まれたときに再作成する必要があります。 いずれかの状態が非同期でセットアップされている場合、プリレンダリングされた UI は一時的なプレースホルダーに置き換えられてから再度完全にレンダリングされるため、UI がちらつくことがあります。
これらの問題を解決するために、Blazor では、永続コンポーネントの状態タグ ヘルパーを使用して、プリレンダリングされたページ内での状態の永続化をサポートしています。 終了 </body>
タグの内側にタグ ヘルパーのタグ <persist-component-state />
を追加します。
Pages/_Layout.cshtml
:
<body>
...
<persist-component-state />
</body>
PersistentComponentState サービスを使用してどの状態を永続化するか決定します。 アプリが一時停止される前に、PersistentComponentState.RegisterOnPersisting
によってコールバックが登録され、コンポーネントの状態が保持されます。 状態は、アプリケーションの再開時に取得されます。
次の例は、Blazor プロジェクト テンプレートに基づいた、ホストされている Blazor WebAssembly アプリ内の FetchData
コンポーネントの更新バージョンです。 WeatherForecastPreserveState
コンポーネントでは、プリレンダリング中に天気予報の状態を保持し、コンポーネントを初期化するために状態が取得されます。 永続コンポーネントの状態タグ ヘルパーでは、すべてのコンポーネントの呼び出しの後で、コンポーネントの状態を保持します。
Pages/WeatherForecastPreserveState.razor
:
@page "/weather-forecast-preserve-state"
@implements IDisposable
@using BlazorSample.Shared
@inject IWeatherForecastService WeatherForecastService
@inject PersistentComponentState ApplicationState
<PageTitle>Weather Forecast</PageTitle>
<h1>Weather forecast</h1>
<p>This component demonstrates fetching data from the server.</p>
@if (forecasts == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
}
@code {
private WeatherForecast[] forecasts = Array.Empty<WeatherForecast>();
private PersistingComponentStateSubscription persistingSubscription;
protected override async Task OnInitializedAsync()
{
persistingSubscription =
ApplicationState.RegisterOnPersisting(PersistForecasts);
if (!ApplicationState.TryTakeFromJson<WeatherForecast[]>(
"fetchdata", out var restored))
{
forecasts =
await WeatherForecastService.GetForecastAsync(DateTime.Now);
}
else
{
forecasts = restored!;
}
}
private Task PersistForecasts()
{
ApplicationState.PersistAsJson("fetchdata", forecasts);
return Task.CompletedTask;
}
void IDisposable.Dispose()
{
persistingSubscription.Dispose();
}
}
プリレンダリング中に使用されたのと同じ状態でコンポーネントを初期化することにより、負荷の高い初期化ステップが 1 回だけ実行されます。 レンダリングされた UI もプリレンダリングされた UI に一致するので、ブラウザーでちらつきは発生しません。
永続化されたプリレンダリングされた状態はクライアントに転送され、そこでコンポーネントの状態を復元するために使用されます。 コア データ保護 ASP.NETBlazor Serverアプリでデータが安全に転送されるようにします。 ホストされている Blazor WebAssembly アプリでプリレンダリングを行う場合、データはブラウザーに公開され、機密情報を含む必要はありません。
Blazor WebAssembly のその他のリソース
- 状態管理: プリレンダリングを処理する
- アセンブリ遅延読み込みによるプリレンダリングのサポート
- プリレンダリングに関連する Razor コンポーネント ライフサイクルの話題
- コンポーネントの初期化 (
OnInitialized{Async}
) - コンポーネントのレンダリング後 (
OnAfterRender{Async}
) - プリレンダリング後のステートフル再接続: このセクションの内容では、Blazor Server およびステートフルな SignalR の "再接続" に焦点を当てていますが、ホストされた Blazor WebAssembly アプリ (WebAssemblyPrerendered) でのプリレンダリングのシナリオでは、開発者コードを 2 回実行しないようにするための同様の条件とアプローチが必要です。 プリレンダリング中に初期化コードの実行中に状態を保持するには、この記事の「プリレンダリングされた状態を保持する」セクションを参照してください。
- JavaScript 相互運用を使用したプリレンダリング
- コンポーネントの初期化 (
- プリレンダリングに関連する認証と認可の話題
- ホストと展開: Blazor WebAssembly
プリレンダリングされた状態サイズと SignalR メッセージ サイズの制限
大規模なプリレンダリングされた状態サイズが SignalR 回線メッセージ サイズの制限を超える可能性があり、その結果、次のようになります。
- この SignalR 回線は、クライアントで次のエラーで初期化に失敗します: Circuit host not initialized.
- 回線が失敗状態になると、クライアント側に再接続 UI が表示されます。 復旧はできません。
この問題を解決するには、次の "いずれかの" 方法を使用します。
- プリレンダリングされた状態に入れるデータの量を減らします。
- SignalR メッセージ サイズの制限を増やします。 警告: 上限を引き上げると、サービス拒否 (DoS) 攻撃のリスクが高まる可能性があります。
Blazor Server のその他のリソース
ホストされる Blazor WebAssemblyソリューションの Razor Pages と MVC アプリに Razor コンポーネントを統合できます。 ページまたはビューがレンダリングされるときには、コンポーネントを同時に事前レンダリングすることができます。
プリレンダリングにより、検索エンジンがページ ランクの計算に使える最初の HTTP 応答の内容がレンダリングされることで、検索エンジンの最適化 (SEO) が向上します。
ソリューションの構成
プリレンダリングの構成
ホストされる Blazor WebAssembly アプリのプリレンダリングを設定するには:
ASP.NET Core アプリで Blazor WebAssembly をホストします。 スタンドアロンの Blazor WebAssembly アプリを ASP.NET Core ソリューションに追加することも、hosted たオプションを使用して Blazor WebAssembly プロジェクト テンプレートから作成されたホスト型の Blazor WebAssembly アプリを使用することもできます。
- Visual Studio: Blazor WebAssembly アプリの作成時に、[追加情報] ダイアログで [ASP.NET Core Hosted] (ASP.NET Core ホステッド) チェックボックスをオンにします。 この記事の例では、ソリューションに
BlazorHosted
という名前が付けられています。 - Visual Studio Code/.NET CLI コマンド シェル:
dotnet new blazorwasm -ho
(-ho|--hosted
オプションを使用)。-o|--output {LOCATION}
オプションを使用してソリューションのフォルダーを作成し、ソリューションのプロジェクト名前空間を設定します。 この記事の例では、ソリューションにBlazorHosted
という名前が付けられています (dotnet new blazorwasm -ho -o BlazorHosted
)。
この記事の例では、クライアント プロジェクトの名前空間は
BlazorHosted.Client
で、サーバー プロジェクトの名前空間はBlazorHosted.Server
です。- Visual Studio: Blazor WebAssembly アプリの作成時に、[追加情報] ダイアログで [ASP.NET Core Hosted] (ASP.NET Core ホステッド) チェックボックスをオンにします。 この記事の例では、ソリューションに
Blazor WebAssemblyClient プロジェクトから
wwwroot/index.html
ファイルを削除します。Client プロジェクトで、
Program.cs
の次の行を削除します。- builder.RootComponents.Add<App>("#app");
Pages/_Host.cshtml
ファイルを Server プロジェクトのPages
フォルダーに追加します。_Host.cshtml
ファイルは、コマンド シェルでdotnet new blazorserver -o BlazorServer
コマンドを使用して Blazor Server テンプレートから作成されたプロジェクトから取得できます (-o BlazorServer
オプションを指定すると、プロジェクトのフォルダーが作成されます)。 ホストされる Blazor WebAssembly ソリューションの Server プロジェクトにPages/_Host.cshtml
ファイルを配置した後、ファイルに次の変更を加えます。Client プロジェクト用の
@using
ディレクティブを指定します (例:@using BlazorHosted.Client
)。スタイルシートのリンクを、WebAssembly プロジェクトのスタイルシートをポイントするように更新します。 次の例では、クライアント プロジェクトの名前空間は
BlazorHosted.Client
になります。- <link href="css/site.css" rel="stylesheet" /> - <link href="_content/BlazorServer/_framework/scoped.styles.css" rel="stylesheet" /> + <link href="css/app.css" rel="stylesheet" /> + <link href="BlazorHosted.Client.styles.css" rel="stylesheet" />
Note
ブートストラップ スタイルシート (
css/bootstrap/bootstrap.min.css
) を要求する<link>
要素はそのままにしておきます。コンポーネント タグ ヘルパーの
render-mode
を、ルートのApp
コンポーネントを WebAssemblyPrerendered を使用してプリレンダリングするように更新します。- <component type="typeof(App)" render-mode="ServerPrerendered" /> + <component type="typeof(App)" render-mode="WebAssemblyPrerendered" />
Blazor スクリプトのソースを、クライアント側の Blazor WebAssembly スクリプトを使用するように更新します。
- <script src="_framework/blazor.server.js"></script> + <script src="_framework/blazor.webassembly.js"></script>
Server プロジェクトの
Startup.Configure
で、フォールバックをindex.html
ファイルから_Host.cshtml
ページに変更します。Startup.cs
:- endpoints.MapFallbackToFile("index.html"); + endpoints.MapFallbackToPage("/_Host");
Client プロジェクトと Server プロジェクトでプリレンダリング中に 1 つまたは複数の一般的サービスが使用される場合、両方のプロジェクトから呼び出せるメソッドにサービス登録を入れます。 詳細については、「ASP.NET Core Blazor の依存関係の挿入」を参照してください。
Server プロジェクトを実行します。 ホストされる Blazor WebAssembly アプリは、クライアントの Server プロジェクトによってプリレンダリングされ ます。
Razor コンポーネントをページおよびビューに埋め込むための構成
クライアント Blazor WebAssembly アプリの Razor コンポーネントをサーバー アプリのページとビューに埋め込むためのこの記事の次のセクションと例では、追加の構成が必要です。
Server プロジェクトの既定のRazor Pages または MVC レイアウト ファイルを使用します。 Server プロジェクトには 次のファイルとフォルダーが含まれている必要があります。
Razor Pages:
Pages/Shared/_Layout.cshtml
Pages/_ViewImports.cshtml
Pages/_ViewStart.cshtml
MVC:
Views/Shared/_Layout.cshtml
Views/_ViewImports.cshtml
Views/_ViewStart.cshtml
Razor Pages または MVC プロジェクト テンプレートから作成されたアプリから、上記のファイルを取得します。 詳しくは、「チュートリアル: ASP.NET Core の Razor Pages の概要」または「ASP.NET Core MVC の概要」をご覧ください。
インポートされた _ViewImports.cshtml
ファイル内の名前空間を、ファイルを受け取る Server プロジェクトで使用されているものと一致するように更新します。
インポートされたレイアウト ファイル (_Layout.cshtml
) を、 Client プロジェクトのスタイルを含むように更新します。 次の例では、 Client プロジェクトの名前空間は BlazorHosted.Client
になります。 <title>
要素は同時に更新できます。
Pages/Shared/_Layout.cshtml
(Razor Pages) または Views/Shared/_Layout.cshtml
(MVC):
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
- <title>@ViewData["Title"] - DonorProject</title>
+ <title>@ViewData["Title"] - BlazorHosted</title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="~/css/site.css" />
+ <link href="css/app.css" rel="stylesheet" />
+ <link href="BlazorHosted.Client.styles.css" rel="stylesheet" />
</head>
インポートされたレイアウトには Home
および Privacy
のナビゲーション リンクが含まれます。 Home
リンクが、ホストされる Blazor WebAssembly アプリをポイントするようにするには、ハイパーリンクを次のように変更します。
- <a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
+ <a class="nav-link text-dark" href="/">Home</a>
MVC レイアウト ファイルの場合:
- <a class="nav-link text-dark" asp-area="" asp-controller="Home"
- asp-action="Index">Home</a>
+ <a class="nav-link text-dark" href="/">Home</a>
Privacy
リンクが privacy ページにつながるようにするには、privacy ページを Server プロジェクトに追加します。
Server プロジェクトの Pages/Privacy.cshtml
:
@page
@model BlazorHosted.Server.Pages.PrivacyModel
@{
}
<h1>Privacy Policy</h1>
MVC ベースの privacy ビューが必要な場合は、Server プロジェクトで privacy ビューを作成します。
View/Home/Privacy.cshtml
:
@{
ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>
Home
コントローラーで、ビューを返します。
Controllers/HomeController.cs
:
public IActionResult Privacy()
{
return View();
}
ドナー プロジェクトの wwwroot
フォルダーから Server プロジェクトに静的アセットをインポートします。
wwwroot/css
フォルダーと内容wwwroot/js
フォルダーと内容wwwroot/lib
フォルダーと内容
ドナー プロジェクトが ASP.NET Core プロジェクト テンプレートから作成され、ファイルが変更されていない場合は、ドナー プロジェクトの wwwroot
フォルダー全体を Server プロジェクトにコピー して、favicon アイコン ファイルを削除することができます。
警告
静的アセットを Client フォルダーと Server wwwroot
フォルダーの両方に配置するのは避けてください。 両方のフォルダーに同じファイルがある場合は、各フォルダー内の静的アセットが同じ Web ルート パスを共有しているため、例外がスローされます。 そのため、静的アセットを両方ではなく、いずれかの wwwroot
フォルダーにホストします。
コンポーネント タグ ヘルパーを使用してページまたはビューのコンポーネントをレンダリングする
追加構成を含むソリューションを構成した後、コンポーネント タグ ヘルパーは、Blazor WebAssembly アプリのコンポーネントをページまたはビュー内にレンダリングするための 2 つのレンダー モードをサポートします。
次の Razor Pages の例では、Counter
コンポーネントがページにレンダリングされます。 コンポーネントを対話形式にするために、ページのレンダリング セクションに Blazor WebAssembly スクリプトが含まれます。 コンポーネント タグ ヘルパーによる Counter
コンポーネントの完全な名前空間 ({ASSEMBLY NAME}.Pages.Counter
) の使用を避けるために、クライアント プロジェクトの Pages
名前空間に @using
ディレクティブを追加します。 次の例では、 Client プロジェクトの名前空間は BlazorHosted.Client
になります。
Server プロジェクトの Pages/RazorPagesCounter1.cshtml
:
@page
@using BlazorHosted.Client.Pages
<component type="typeof(Counter)" render-mode="WebAssemblyPrerendered" />
@section Scripts {
<script src="_framework/blazor.webassembly.js"></script>
}
Server プロジェクトを実行します。 /razorpagescounter1
の Razor ページに移動します。 プリレンダリングされた Counter
コンポーネントはページに埋め込まれています。
RenderMode によって、コンポーネントに対して以下の構成が行われます。
- ページに事前レンダリングするかどうか。
- ページに静的 HTML としてレンダリングするかどうか。または、ユーザー エージェントから Blazor アプリをブートストラップするために必要な情報が含まれているかどうか。
パラメーターの渡し方や RenderMode の構成などのコンポーネント タグ ヘルパーの詳細については、「ASP.NET Core のコンポーネント タグ ヘルパー」を参照してください。
コンポーネントによって使用される静的リソースや、アプリでのレイアウト ページの整理方法によっては、追加の作業が必要になる場合があります。 通常、ページまたはビューの Scripts
レンダー セクションにスクリプトが追加され、スタイル シートはレイアウトの <head>
要素コンテンツに追加されます。
CSS セレクターを使用してページまたはビューのコンポーネントをレンダリングする
追加の構成を含めてソリューションを構成した後、Program.cs
でホストされる Blazor WebAssembly ソリューションの Client プロジェクトにルート コンポーネントを追加します。 次の例では、counter-component
と一致する id
を持つ要素を選択する CSS セレクターを使用して、ルート コンポーネントとして Counter
コンポーネントが宣言されています。 次の例では、 Client プロジェクトの名前空間は BlazorHosted.Client
になります。
Client プロジェクトの Program.cs
で、プロジェクトの Razor コンポーネントの名前空間をファイルの先頭に追加します。
using BlazorHosted.Client.Pages;
Program.cs
で builder
が確立されたら、Counter
コンポーネントをルート コンポーネントとして追加します。
builder.RootComponents.Add<Counter>("#counter-component");
次の Razor Pages の例では、Counter
コンポーネントがページにレンダリングされます。 コンポーネントを対話形式にするために、ページのレンダリング セクションに Blazor WebAssembly スクリプトが含まれます。
Server プロジェクトの Pages/RazorPagesCounter2.cshtml
:
@page
<div id="counter-component">Loading...</div>
@section Scripts {
<script src="_framework/blazor.webassembly.js"></script>
}
Server プロジェクトを実行します。 /razorpagescounter2
の Razor ページに移動します。 プリレンダリングされた Counter
コンポーネントはページに埋め込まれています。
コンポーネントによって使用される静的リソースや、アプリでのレイアウト ページの整理方法によっては、追加の作業が必要になる場合があります。 通常、ページまたはビューの Scripts
レンダー セクションにスクリプトが追加され、スタイル シートはレイアウトの <head>
要素コンテンツに追加されます。
Note
前の例では、Blazor WebAssembly アプリが CSS セレクターを使用して Razor Pages または MVC アプリに同時にプリレンダリングおよび統合された場合に JSException がスローされます。 Client プロジェクトの Razor コンポーネントのいずれかに移動すると、次の例外がスローされます。
Microsoft.JSInterop.JSException: Could not find any element matching selector '#counter-component'.(Microsoft.JSInterop.JSException: セレクター '#counter-component' に一致する要素が見つかりませんでした。)
ルーティング可能な Razor コンポーネントを使用した Blazor WebAssembly アプリのプリレンダリングおよび統合は、CSS セレクターの使用と両立しないため、これは通常の動作です。
Razor コンポーネントは、Razor Pages と MVC アプリに統合できます。 ページまたはビューがレンダリングされるときには、コンポーネントを同時に事前レンダリングすることができます。
プリレンダリングにより、検索エンジンがページ ランクの計算に使える最初の HTTP 応答の内容がレンダリングされることで、検索エンジンの最適化 (SEO) が向上します。
プロジェクトを構成した後、プロジェクトの要件に応じて、次のセクションのガイダンスを使用します。
- ルーティング可能なコンポーネント:ユーザー要求から直接ルーティング可能なコンポーネント。 訪問者が
@page
ディレクティブを含むコンポーネントのブラウザーで HTTP 要求を行うことができる必要がある場合は、このガイダンスに従ってください。 - ページまたはビューからコンポーネントをレンダリングする:ユーザー要求から直接ルーティングできないコンポーネント。 アプリによってコンポーネント タグ ヘルパーを含む既存のページやビューにコンポーネントが埋め込まれる場合は、このガイダンスに従ってください。
構成
既存の Razor Pages や MVC アプリでは、Razor コンポーネントをページとビューに統合できます。
プロジェクトのレイアウト ファイルで、次のようにします。
Pages/Shared/_Layout.cshtml
(Razor Pages) またはViews/Shared/_Layout.cshtml
(MVC) の<head>
要素に次の<base>
タグを追加します。<base href="~/" />
前の例の
href
値 (アプリ ベースのパス) は、アプリがルート URL パス (/
) に置かれていることを前提としています。 アプリがサブアプリケーションになっている場合は、「ASP.NET Core Blazor のホストと展開」記事の「アプリのベース パス」セクションのガイダンスに従ってください。blazor.server.js
スクリプトの<script>
タグをScripts
レンダリング セクションの直前に追加します。Pages/Shared/_Layout.cshtml
(Razor Pages) またはViews/Shared/_Layout.cshtml
(MVC):... <script src="_framework/blazor.server.js"></script> @await RenderSectionAsync("Scripts", required: false) </body>
フレームワークによって
blazor.server.js
スクリプトがアプリに追加されます。blazor.server.js
スクリプト ファイルをアプリに手動で追加する必要はありません。
次の内容の imports ファイルをプロジェクトのルート フォルダーに追加します。
{APP NAMESPACE}
プレースホルダーをプロジェクトの名前空間に変更します。_Imports.razor
:@using System.Net.Http @using Microsoft.AspNetCore.Authorization @using Microsoft.AspNetCore.Components.Authorization @using Microsoft.AspNetCore.Components.Forms @using Microsoft.AspNetCore.Components.Routing @using Microsoft.AspNetCore.Components.Web @using Microsoft.JSInterop @using {APP NAMESPACE}
Blazor Server サービスを
Startup.ConfigureServices
に登録します。Startup.cs
:services.AddServerSideBlazor();
Blazor ハブ エンドポイントを
Startup.Configure
のエンドポイント (app.UseEndpoints
) に追加します。Startup.cs
:endpoints.MapBlazorHub();
コンポーネントを任意のページまたはビューに統合します。 たとえば、プロジェクトの
Shared
フォルダーにCounter
コンポーネントを追加します。Pages/Shared/Counter.razor
(Razor Pages) またはViews/Shared/Counter.razor
(MVC):<h1>Counter</h1> <p>Current count: @currentCount</p> <button class="btn btn-primary" @onclick="IncrementCount">Click me</button> @code { private int currentCount = 0; private void IncrementCount() { currentCount++; } }
Razor Pages:
Razor Pages アプリのプロジェクトの
Index
ページで、Counter
コンポーネントの名前空間を追加し、そのコンポーネントをページに埋め込みます。Index
ページが読み込まれるとき、Counter
コンポーネントはページにプリレンダリングされます。 次の例では、{APP NAMESPACE}
プレースホルダーをプロジェクトの名前空間に置き換えます。Pages/Index.cshtml
:@page @using {APP NAMESPACE}.Pages.Shared @model IndexModel @{ ViewData["Title"] = "Home page"; } <div> <component type="typeof(Counter)" render-mode="ServerPrerendered" /> </div>
前の例では、
{APP NAMESPACE}
プレースホルダーをアプリの名前空間に置き換えます。MVC:
MVC アプリのプロジェクトの
Index
ビューで、Counter
コンポーネントの名前空間を追加し、そのコンポーネントをビューに埋め込みます。Index
ビューが読み込まれるとき、Counter
コンポーネントはページにプリレンダリングされます。 次の例では、{APP NAMESPACE}
プレースホルダーをプロジェクトの名前空間に置き換えます。Views/Home/Index.cshtml
:@using {APP NAMESPACE}.Views.Shared @{ ViewData["Title"] = "Home Page"; } <div> <component type="typeof(Counter)" render-mode="ServerPrerendered" /> </div>
詳細については、「ページまたはビューからコンポーネントをレンダリングする」セクションを参照してください。
Razor Pages アプリでルーティング可能なコンポーネントを使用する
ここは、ユーザー要求から直接ルーティング可能なコンポーネントを追加することに関係のあるセクションです。
Razor Pages アプリでルーティング可能な Razor コンポーネントをサポートするには、次のようにします。
「構成」セクションのガイダンスに従います。
次の内容の
App
コンポーネントをプロジェクト ルートに追加します。App.razor
:@using Microsoft.AspNetCore.Components.Routing <Router AppAssembly="typeof(Program).Assembly"> <Found Context="routeData"> <RouteView RouteData="routeData" /> </Found> <NotFound> <h1>Page not found</h1> <p>Sorry, but there's nothing here!</p> </NotFound> </Router>
注意
ASP.NET Core 5.0.1 のリリースと、その他の 5.x リリースでは、
Router
コンポーネントに@true
に設定されたPreferExactMatches
パラメーターが含まれています。 詳細については、「ASP.NET Core 3.1 から 5.0 への移行」を参照してください。次の内容の
_Host
ページをプロジェクトに追加します。Pages/_Host.cshtml
:@page "/blazor" @{ Layout = "_Layout"; } <app> <component type="typeof(App)" render-mode="ServerPrerendered" /> </app>
コンポーネントでは、そのレイアウトで共有される
_Layout.cshtml
ファイルが使用されます。RenderMode によって、
App
コンポーネントに対して以下の構成が行われます。- ページに事前レンダリングするかどうか。
- ページに静的 HTML としてレンダリングするかどうか。または、ユーザー エージェントから Blazor アプリをブートストラップするために必要な情報が含まれているかどうか。
パラメーターの渡し方や RenderMode の構成などのコンポーネント タグ ヘルパーの詳細については、「ASP.NET Core のコンポーネント タグ ヘルパー」を参照してください。
Startup.cs
のStartup.Configure
エンドポイントで、_Host
ページの優先度の低いルートを最後のエンドポイントとして追加します。endpoints.MapFallbackToPage("/_Host");
次の例は、一般的なアプリのエンドポイント構成に追加された行を示しています。
app.UseEndpoints(endpoints => { endpoints.MapRazorPages(); endpoints.MapBlazorHub(); endpoints.MapFallbackToPage("/_Host"); });
ルーティング可能なコンポーネントをプロジェクトに追加します。
Pages/RoutableCounter.razor
:@page "/routable-counter" <h1>Routable Counter</h1> <p>Current count: @currentCount</p> <button class="btn btn-primary" @onclick="IncrementCount">Click me</button> @code { private int currentCount = 0; private void IncrementCount() { currentCount++; } }
プロジェクトを実行し、
/routable-counter
のルーティング可能なRoutableCounter
コンポーネントに移動します。
名前空間の詳細については、「コンポーネントの名前空間」セクションを参照してください。
MVC アプリでルーティング可能なコンポーネントを使用する
ここは、ユーザー要求から直接ルーティング可能なコンポーネントを追加することに関係のあるセクションです。
MVC アプリでルーティング可能な Razor コンポーネントをサポートするには、次のようにします。
「構成」セクションのガイダンスに従います。
次の内容の
App
コンポーネントをプロジェクト ルートに追加します。App.razor
:@using Microsoft.AspNetCore.Components.Routing <Router AppAssembly="typeof(Program).Assembly"> <Found Context="routeData"> <RouteView RouteData="routeData" /> </Found> <NotFound> <h1>Page not found</h1> <p>Sorry, but there's nothing here!</p> </NotFound> </Router>
注意
ASP.NET Core 5.0.1 のリリースと、その他の 5.x リリースでは、
Router
コンポーネントに@true
に設定されたPreferExactMatches
パラメーターが含まれています。 詳細については、「ASP.NET Core 3.1 から 5.0 への移行」を参照してください。次の内容の
_Host
ビューをプロジェクトに追加します。Views/Home/_Host.cshtml
:@{ Layout = "_Layout"; } <app> <component type="typeof(App)" render-mode="ServerPrerendered" /> </app>
コンポーネントでは、そのレイアウトで共有される
_Layout.cshtml
ファイルが使用されます。RenderMode によって、
App
コンポーネントに対して以下の構成が行われます。- ページに事前レンダリングするかどうか。
- ページに静的 HTML としてレンダリングするかどうか。または、ユーザー エージェントから Blazor アプリをブートストラップするために必要な情報が含まれているかどうか。
パラメーターの渡し方や RenderMode の構成などのコンポーネント タグ ヘルパーの詳細については、「ASP.NET Core のコンポーネント タグ ヘルパー」を参照してください。
Home コントローラーにアクションを追加します。
Controllers/HomeController.cs
:public IActionResult Blazor() { return View("_Host"); }
Startup.cs
のStartup.Configure
エンドポイントに、_Host
ビューを返すコントローラー アクションのために、優先度が低いルートを追加します。endpoints.MapFallbackToController("Blazor", "Home");
次の例は、一般的なアプリのエンドポイント構成に追加された行を示しています。
app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); endpoints.MapBlazorHub(); endpoints.MapFallbackToController("Blazor", "Home"); });
ルーティング可能なコンポーネントをプロジェクトに追加します。
Pages/RoutableCounter.razor
:@page "/routable-counter" <h1>Routable Counter</h1> <p>Current count: @currentCount</p> <button class="btn btn-primary" @onclick="IncrementCount">Click me</button> @code { private int currentCount = 0; private void IncrementCount() { currentCount++; } }
プロジェクトを実行し、
/routable-counter
のルーティング可能なRoutableCounter
コンポーネントに移動します。
名前空間の詳細については、「コンポーネントの名前空間」セクションを参照してください。
ページまたはビューからコンポーネントをレンダリングする
これは、コンポーネントをユーザー要求から直接ルーティングできないページまたはビューにコンポーネントを追加することに関係するセクションです。
ページまたはビューからコンポーネントをレンダリングするには、コンポーネント タグ ヘルパーを使用します。
ステートフル対話型コンポーネントをレンダリングする
Razor ページまたはビューには、ステートフル対話型コンポーネントを追加できます。
ページまたはビューがレンダリングされると、次の処理が行われます。
- ページまたはビューと共にコンポーネントがプリレンダリングされます。
- プリレンダリングに使用された初期のコンポーネント状態は失われます。
- SignalR 接続が確立されると、新しいコンポーネント状態が作成されます。
次の Razor ページには、Counter
コンポーネントがレンダリングされます。
<h1>My Razor Page</h1>
<component type="typeof(Counter)" render-mode="ServerPrerendered"
param-InitialValue="InitialValue" />
@functions {
[BindProperty(SupportsGet=true)]
public int InitialValue { get; set; }
}
詳細については、「ASP.NET Core のコンポーネント タグ ヘルパー」を参照してください。
非対話型コンポーネントをレンダリングする
次の Razor ページには、フォームを使用して指定された初期値を使用して、Counter
コンポーネントが静的にレンダリングされます。 コンポーネントは静的にレンダリングされるため、コンポーネントは対話型ではありません。
<h1>My Razor Page</h1>
<form>
<input type="number" asp-for="InitialValue" />
<button type="submit">Set initial value</button>
</form>
<component type="typeof(Counter)" render-mode="Static"
param-InitialValue="InitialValue" />
@functions {
[BindProperty(SupportsGet=true)]
public int InitialValue { get; set; }
}
詳細については、「ASP.NET Core のコンポーネント タグ ヘルパー」を参照してください。
コンポーネントの名前空間
カスタム フォルダーを使用してプロジェクトの Razor コンポーネントを保持する場合は、フォルダーを表す名前空間を、ページまたはビューのいずれかに追加するか、_ViewImports.cshtml
ファイルに追加します。 次に例を示します。
- コンポーネントはプロジェクトの
Components
フォルダーに格納されます。 {APP NAMESPACE}
プレースホルダーはロジェクトの名前空間です。Components
はフォルダーの名前を表します。
@using {APP NAMESPACE}.Components
_ViewImports.cshtml
ファイルは、Razor Pages アプリの Pages
フォルダーまたは MVC アプリの Views
フォルダーにあります。
詳細については、「ASP.NET Core Razor コンポーネント」を参照してください。
Blazor WebAssembly のその他のリソース
- 状態管理: プリレンダリングを処理する
- アセンブリ遅延読み込みによるプリレンダリングのサポート
- プリレンダリングに関連する Razor コンポーネント ライフサイクルの話題
- コンポーネントの初期化 (
OnInitialized{Async}
) - コンポーネントのレンダリング後 (
OnAfterRender{Async}
) - プリレンダリング後のステートフル再接続: このセクションの内容では、Blazor Server およびステートフルな SignalR の "再接続" に焦点を当てていますが、ホストされた Blazor WebAssembly アプリ (WebAssemblyPrerendered) でのプリレンダリングのシナリオでは、開発者コードを 2 回実行しないようにするための同様の条件とアプローチが必要です。 プリレンダリング中に初期化コードの実行中に状態を保持するには、この記事の「プリレンダリングされた状態を保持する」セクションを参照してください。
- JavaScript 相互運用を使用したプリレンダリング
- コンポーネントの初期化 (
- プリレンダリングに関連する認証と認可の話題
- ホストと展開: Blazor WebAssembly
プリレンダリングされた状態サイズと SignalR メッセージ サイズの制限
大規模なプリレンダリングされた状態サイズが SignalR 回線メッセージ サイズの制限を超える可能性があり、その結果、次のようになります。
- この SignalR 回線は、クライアントで次のエラーで初期化に失敗します: Circuit host not initialized.
- 回線が失敗状態になると、クライアント側に再接続 UI が表示されます。 復旧はできません。
この問題を解決するには、次の "いずれかの" 方法を使用します。
- プリレンダリングされた状態に入れるデータの量を減らします。
- SignalR メッセージ サイズの制限を増やします。 警告: 上限を引き上げると、サービス拒否 (DoS) 攻撃のリスクが高まる可能性があります。
Blazor Server のその他のリソース
ホストされる Blazor WebAssemblyソリューションの Razor Pages と MVC アプリへの Razor コンポーネントの統合は、.NET 5 以降の ASP.NET Core でサポートされています。 この記事の .NET 5 以降のバージョンを選択してください。
Razor コンポーネントは、Razor Pages と MVC アプリに統合できます。 ページまたはビューがレンダリングされるときには、コンポーネントを同時に事前レンダリングすることができます。
プリレンダリングにより、検索エンジンがページ ランクの計算に使える最初の HTTP 応答の内容がレンダリングされることで、検索エンジンの最適化 (SEO) が向上します。
プロジェクトを構成した後、プロジェクトの要件に応じて、次のセクションのガイダンスを使用します。
- ルーティング可能なコンポーネント:ユーザー要求から直接ルーティング可能なコンポーネント。 訪問者が
@page
ディレクティブを含むコンポーネントのブラウザーで HTTP 要求を行うことができる必要がある場合は、このガイダンスに従ってください。 - ページまたはビューからコンポーネントをレンダリングする:ユーザー要求から直接ルーティングできないコンポーネント。 アプリによってコンポーネント タグ ヘルパーを含む既存のページやビューにコンポーネントが埋め込まれる場合は、このガイダンスに従ってください。
構成
既存の Razor Pages や MVC アプリでは、Razor コンポーネントをページとビューに統合できます。
プロジェクトのレイアウト ファイルで、次のようにします。
Pages/Shared/_Layout.cshtml
(Razor Pages) またはViews/Shared/_Layout.cshtml
(MVC) の<head>
要素に次の<base>
タグを追加します。+ <base href="~/" />
前の例の
href
値 (アプリ ベースのパス) は、アプリがルート URL パス (/
) に置かれていることを前提としています。 アプリがサブアプリケーションになっている場合は、「ASP.NET Core Blazor のホストと展開」記事の「アプリのベース パス」セクションのガイダンスに従ってください。blazor.server.js
スクリプトの<script>
タグをScripts
レンダリング セクションの直前に追加します。Pages/Shared/_Layout.cshtml
(Razor Pages) またはViews/Shared/_Layout.cshtml
(MVC):... <script src="_framework/blazor.server.js"></script> @await RenderSectionAsync("Scripts", required: false) </body>
フレームワークによって
blazor.server.js
スクリプトがアプリに追加されます。blazor.server.js
スクリプト ファイルをアプリに手動で追加する必要はありません。
次の内容の imports ファイルをプロジェクトのルート フォルダーに追加します。
{APP NAMESPACE}
プレースホルダーをプロジェクトの名前空間に変更します。_Imports.razor
:@using System.Net.Http @using Microsoft.AspNetCore.Authorization @using Microsoft.AspNetCore.Components.Authorization @using Microsoft.AspNetCore.Components.Forms @using Microsoft.AspNetCore.Components.Routing @using Microsoft.AspNetCore.Components.Web @using Microsoft.JSInterop @using {APP NAMESPACE}
Blazor Server サービスを
Startup.ConfigureServices
に登録します。Startup.cs
:services.AddServerSideBlazor();
Blazor ハブ エンドポイントを
Startup.Configure
のエンドポイント (app.UseEndpoints
) に追加します。Startup.cs
:endpoints.MapBlazorHub();
コンポーネントを任意のページまたはビューに統合します。 たとえば、プロジェクトの
Shared
フォルダーにCounter
コンポーネントを追加します。Pages/Shared/Counter.razor
(Razor Pages) またはViews/Shared/Counter.razor
(MVC):<h1>Counter</h1> <p>Current count: @currentCount</p> <button class="btn btn-primary" @onclick="IncrementCount">Click me</button> @code { private int currentCount = 0; private void IncrementCount() { currentCount++; } }
Razor Pages:
Razor Pages アプリのプロジェクトの
Index
ページで、Counter
コンポーネントの名前空間を追加し、そのコンポーネントをページに埋め込みます。Index
ページが読み込まれるとき、Counter
コンポーネントはページにプリレンダリングされます。 次の例では、{APP NAMESPACE}
プレースホルダーをプロジェクトの名前空間に置き換えます。Pages/Index.cshtml
:@page @using {APP NAMESPACE}.Pages.Shared @model IndexModel @{ ViewData["Title"] = "Home page"; } <div> <component type="typeof(Counter)" render-mode="ServerPrerendered" /> </div>
前の例では、
{APP NAMESPACE}
プレースホルダーをアプリの名前空間に置き換えます。MVC:
MVC アプリのプロジェクトの
Index
ビューで、Counter
コンポーネントの名前空間を追加し、そのコンポーネントをビューに埋め込みます。Index
ビューが読み込まれるとき、Counter
コンポーネントはページにプリレンダリングされます。 次の例では、{APP NAMESPACE}
プレースホルダーをプロジェクトの名前空間に置き換えます。Views/Home/Index.cshtml
:@using {APP NAMESPACE}.Views.Shared @{ ViewData["Title"] = "Home Page"; } <div> <component type="typeof(Counter)" render-mode="ServerPrerendered" /> </div>
詳細については、「ページまたはビューからコンポーネントをレンダリングする」セクションを参照してください。
Razor Pages アプリでルーティング可能なコンポーネントを使用する
ここは、ユーザー要求から直接ルーティング可能なコンポーネントを追加することに関係のあるセクションです。
Razor Pages アプリでルーティング可能な Razor コンポーネントをサポートするには、次のようにします。
「構成」セクションのガイダンスに従います。
次の内容の
App
コンポーネントをプロジェクト ルートに追加します。App.razor
:@using Microsoft.AspNetCore.Components.Routing <Router AppAssembly="typeof(Program).Assembly"> <Found Context="routeData"> <RouteView RouteData="routeData" /> </Found> <NotFound> <h1>Page not found</h1> <p>Sorry, but there's nothing here!</p> </NotFound> </Router>
次の内容の
_Host
ページをプロジェクトに追加します。Pages/_Host.cshtml
:@page "/blazor" @{ Layout = "_Layout"; } <app> <component type="typeof(App)" render-mode="ServerPrerendered" /> </app>
コンポーネントでは、そのレイアウトで共有される
_Layout.cshtml
ファイルが使用されます。RenderMode によって、
App
コンポーネントに対して以下の構成が行われます。- ページに事前レンダリングするかどうか。
- ページに静的 HTML としてレンダリングするかどうか。または、ユーザー エージェントから Blazor アプリをブートストラップするために必要な情報が含まれているかどうか。
パラメーターの渡し方や RenderMode の構成などのコンポーネント タグ ヘルパーの詳細については、「ASP.NET Core のコンポーネント タグ ヘルパー」を参照してください。
Startup.cs
のStartup.Configure
エンドポイントで、_Host
ページの優先度の低いルートを最後のエンドポイントとして追加します。endpoints.MapFallbackToPage("/_Host");
次の例は、一般的なアプリのエンドポイント構成に追加された行を示しています。
app.UseEndpoints(endpoints => { endpoints.MapRazorPages(); endpoints.MapBlazorHub(); endpoints.MapFallbackToPage("/_Host"); });
ルーティング可能なコンポーネントをプロジェクトに追加します。
Pages/RoutableCounter.razor
:@page "/routable-counter" <h1>Routable Counter</h1> <p>Current count: @currentCount</p> <button class="btn btn-primary" @onclick="IncrementCount">Click me</button> @code { private int currentCount = 0; private void IncrementCount() { currentCount++; } }
プロジェクトを実行し、
/routable-counter
のルーティング可能なRoutableCounter
コンポーネントに移動します。
名前空間の詳細については、「コンポーネントの名前空間」セクションを参照してください。
MVC アプリでルーティング可能なコンポーネントを使用する
ここは、ユーザー要求から直接ルーティング可能なコンポーネントを追加することに関係のあるセクションです。
MVC アプリでルーティング可能な Razor コンポーネントをサポートするには、次のようにします。
「構成」セクションのガイダンスに従います。
次の内容の
App
コンポーネントをプロジェクト ルートに追加します。App.razor
:@using Microsoft.AspNetCore.Components.Routing <Router AppAssembly="typeof(Program).Assembly"> <Found Context="routeData"> <RouteView RouteData="routeData" /> </Found> <NotFound> <h1>Page not found</h1> <p>Sorry, but there's nothing here!</p> </NotFound> </Router>
次の内容の
_Host
ビューをプロジェクトに追加します。Views/Home/_Host.cshtml
:@{ Layout = "_Layout"; } <app> <component type="typeof(App)" render-mode="ServerPrerendered" /> </app>
コンポーネントでは、そのレイアウトで共有される
_Layout.cshtml
ファイルが使用されます。RenderMode によって、
App
コンポーネントに対して以下の構成が行われます。- ページに事前レンダリングするかどうか。
- ページに静的 HTML としてレンダリングするかどうか。または、ユーザー エージェントから Blazor アプリをブートストラップするために必要な情報が含まれているかどうか。
パラメーターの渡し方や RenderMode の構成などのコンポーネント タグ ヘルパーの詳細については、「ASP.NET Core のコンポーネント タグ ヘルパー」を参照してください。
Home コントローラーにアクションを追加します。
Controllers/HomeController.cs
:public IActionResult Blazor() { return View("_Host"); }
Startup.cs
のStartup.Configure
エンドポイントに、_Host
ビューを返すコントローラー アクションのために、優先度が低いルートを追加します。endpoints.MapFallbackToController("Blazor", "Home");
次の例は、一般的なアプリのエンドポイント構成に追加された行を示しています。
app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); endpoints.MapBlazorHub(); endpoints.MapFallbackToController("Blazor", "Home"); });
ルーティング可能なコンポーネントをプロジェクトに追加します。
Pages/RoutableCounter.razor
:@page "/routable-counter" <h1>Routable Counter</h1> <p>Current count: @currentCount</p> <button class="btn btn-primary" @onclick="IncrementCount">Click me</button> @code { private int currentCount = 0; private void IncrementCount() { currentCount++; } }
プロジェクトを実行し、
/routable-counter
のルーティング可能なRoutableCounter
コンポーネントに移動します。
名前空間の詳細については、「コンポーネントの名前空間」セクションを参照してください。
ページまたはビューからコンポーネントをレンダリングする
これは、コンポーネントをユーザー要求から直接ルーティングできないページまたはビューにコンポーネントを追加することに関係するセクションです。
ページまたはビューからコンポーネントをレンダリングするには、コンポーネント タグ ヘルパーを使用します。
ステートフル対話型コンポーネントをレンダリングする
Razor ページまたはビューには、ステートフル対話型コンポーネントを追加できます。
ページまたはビューがレンダリングされると、次の処理が行われます。
- ページまたはビューと共にコンポーネントがプリレンダリングされます。
- プリレンダリングに使用された初期のコンポーネント状態は失われます。
- SignalR 接続が確立されると、新しいコンポーネント状態が作成されます。
次の Razor ページには、Counter
コンポーネントがレンダリングされます。
<h1>My Razor Page</h1>
<component type="typeof(Counter)" render-mode="ServerPrerendered"
param-InitialValue="InitialValue" />
@functions {
[BindProperty(SupportsGet=true)]
public int InitialValue { get; set; }
}
詳細については、「ASP.NET Core のコンポーネント タグ ヘルパー」を参照してください。
非対話型コンポーネントをレンダリングする
次の Razor ページには、フォームを使用して指定された初期値を使用して、Counter
コンポーネントが静的にレンダリングされます。 コンポーネントは静的にレンダリングされるため、コンポーネントは対話型ではありません。
<h1>My Razor Page</h1>
<form>
<input type="number" asp-for="InitialValue" />
<button type="submit">Set initial value</button>
</form>
<component type="typeof(Counter)" render-mode="Static"
param-InitialValue="InitialValue" />
@functions {
[BindProperty(SupportsGet=true)]
public int InitialValue { get; set; }
}
詳細については、「ASP.NET Core のコンポーネント タグ ヘルパー」を参照してください。
コンポーネントの名前空間
カスタム フォルダーを使用してプロジェクトの Razor コンポーネントを保持する場合は、フォルダーを表す名前空間を、ページまたはビューのいずれかに追加するか、_ViewImports.cshtml
ファイルに追加します。 次に例を示します。
- コンポーネントはプロジェクトの
Components
フォルダーに格納されます。 {APP NAMESPACE}
プレースホルダーはロジェクトの名前空間です。Components
はフォルダーの名前を表します。
@using {APP NAMESPACE}.Components
_ViewImports.cshtml
ファイルは、Razor Pages アプリの Pages
フォルダーまたは MVC アプリの Views
フォルダーにあります。
詳細については、「ASP.NET Core Razor コンポーネント」を参照してください。
プリレンダリングされた状態サイズと SignalR メッセージ サイズの制限
大規模なプリレンダリングされた状態サイズが SignalR 回線メッセージ サイズの制限を超える可能性があり、その結果、次のようになります。
- この SignalR 回線は、クライアントで次のエラーで初期化に失敗します: Circuit host not initialized.
- 回線が失敗状態になると、クライアント側に再接続 UI が表示されます。 復旧はできません。
この問題を解決するには、次の "いずれかの" 方法を使用します。
- プリレンダリングされた状態に入れるデータの量を減らします。
- SignalR メッセージ サイズの制限を増やします。 警告: 上限を引き上げると、サービス拒否 (DoS) 攻撃のリスクが高まる可能性があります。
Blazor Server のその他のリソース
ASP.NET Core