ASP.NET Core の Blazor ルーティングとナビゲーション

注意

これは、この記事の最新バージョンではありません。 最新のバージョンに切り替えるには、目次の上部にある ASP.NET Core バージョン セレクターを使用します。

バージョン セレクター

セレクターが狭いブラウザー ウィンドウに表示されない場合は、ウィンドウの幅を広げるか、垂直省略記号 ([⋮]) >[目次] の順に選択します。

目次セレクター

この記事では、要求ルーティングを管理する方法と、NavLink コンポーネントを使用して Blazor アプリでナビゲーション リンクを作成する方法について説明します。

重要

この記事全体のコード例では、Navigation で呼び出されるメソッドを示します。これはクラスとコンポーネントに挿入される NavigationManager です。

ルート テンプレート

Router コンポーネントを使用すると、Blazor アプリで Razor コンポーネントにルーティングできます。 Router コンポーネントは Blazor アプリの App コンポーネントで使用されます。

App.razor:

<Router AppAssembly="@typeof(Program).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
    </Found>
    <NotFound>
        <p>Sorry, there's nothing at this address.</p>
    </NotFound>
</Router>
<Router AppAssembly="@typeof(Program).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
    </Found>
    <NotFound>
        <p>Sorry, there's nothing at this address.</p>
    </NotFound>
</Router>
<Router AppAssembly="@typeof(Program).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
    </Found>
    <NotFound>
        <p>Sorry, there's nothing at this address.</p>
    </NotFound>
</Router>
<Router AppAssembly="@typeof(Program).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
    </Found>
    <NotFound>
        <p>Sorry, there's nothing at this address.</p>
    </NotFound>
</Router>

@page ディレクティブ を含む Razor コンポーネント (.razor) がコンパイルされると、生成されたコンポーネント クラスに、コンポーネントのルート テンプレートを指定する RouteAttribute が指定されます。

アプリが起動すると、Router の AppAssembly として指定されたアセンブリがスキャンされ、RouteAttribute を持つアプリのコンポーネントのルート情報が収集されます。

実行時に、RouteView コンポーネントは、

  • Router から、ルート パラメーターと共に RouteData を受け取ります。
  • さらに入れ子になったレイアウトを含め、指定されたコンポーネントをそのレイアウトでレンダリングします。

必要に応じて、@layout ディレクティブ を使用してレイアウトを指定しないコンポーネントに対して、レイアウト クラスで DefaultLayout パラメーターを指定します。 フレームワークの Blazor プロジェクト テンプレートによって、MainLayout コンポーネント (Shared/MainLayout.razor) が、アプリの既定のレイアウトとして指定されます。 レイアウトについて詳しくは、「ASP.NET Core Blazor のレイアウト」をご覧ください。

コンポーネントにより、複数の @page ディレクティブ を使用する複数のルート テンプレートがサポートされます。 次のコンポーネントの例では、/blazor-route/different-blazor-route に対する要求を読み込みます。

Pages/BlazorRoute.razor:

@page "/blazor-route"
@page "/different-blazor-route"

<h1>Blazor routing</h1>
@page "/blazor-route"
@page "/different-blazor-route"

<h1>Blazor routing</h1>
@page "/blazor-route"
@page "/different-blazor-route"

<h1>Blazor routing</h1>
@page "/blazor-route"
@page "/different-blazor-route"

<h1>Blazor routing</h1>

重要

URL が正しく解決されるように、アプリには <base> タグを含め (<head> コンテンツの場所)、href 属性でアプリのベース パスを指定する必要があります。 詳細については、「ASP.NET Core Blazor のホストと展開」を参照してください。

Router は、クエリ文字列値では使用できません。 クエリ文字列の使用方法については、「クエリ文字列」セクションをご覧ください。

ルート テンプレートを @page ディレクティブを使用して文字列リテラルとして指定する代わりに、定数ベースのルート テンプレートを @attribute ディレクティブと共に指定できます。

次の例では、コンポーネント内の @page ディレクティブが @attribute ディレクティブと Constants.CounterRoute の定数ベースのルート テンプレートに置き換えられます。これは、アプリ内の別の場所で "/counter" に設定されています。

- @page "/counter"
+ @attribute [Route(Constants.CounterRoute)]

ナビゲーション時に要素にフォーカスを合わせる

FocusOnNavigate コンポーネントを使用して、あるページから別のページに移動した後、CSS セレクターに基づいて要素に UI フォーカスを設定します。 Blazor プロジェクト テンプレートから生成されたアプリの App コンポーネントで、FocusOnNavigate コンポーネントの使用を確認できます。

App.razorの場合:

<FocusOnNavigate RouteData="@routeData" Selector="h1" />

Router コンポーネントが新しいページに移動すると、FocusOnNavigate コンポーネントによってページの最上位ヘッダー (<h1>) にフォーカスが設定されます。 これは、スクリーン リーダーを使用する際にページ ナビゲーションが読み上げられるようにするための一般的な方法です。

コンテンツが見つからないときにカスタム コンテンツを提供する

Router コンポーネントを使用すると、要求されたルートでコンテンツが見つからない場合に、アプリでカスタム コンテンツを指定できます。

App コンポーネントで、Router コンポーネントの NotFound テンプレートにカスタム コンテンツを設定します。

App.razor:

<Router AppAssembly="@typeof(Program).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
    </Found>
    <NotFound>
        <h1>Sorry</h1>
        <p>Sorry, there's nothing at this address.</p>
    </NotFound>
</Router>
<Router AppAssembly="@typeof(Program).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
    </Found>
    <NotFound>
        <h1>Sorry</h1>
        <p>Sorry, there's nothing at this address.</p>
    </NotFound>
</Router>
<Router AppAssembly="@typeof(Program).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
    </Found>
    <NotFound>
        <h1>Sorry</h1>
        <p>Sorry, there's nothing at this address.</p>
    </NotFound>
</Router>

注意

ASP.NET Core 5.0.1 のリリースと、その他の 5.x リリースでは、Router コンポーネントに @trueに設定された PreferExactMatches パラメーターが含まれています。 詳細については、「ASP.NET Core 3.1 から 5.0 への移行」を参照してください。

<Router AppAssembly="@typeof(Program).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
    </Found>
    <NotFound>
        <h1>Sorry</h1>
        <p>Sorry, there's nothing at this address.</p>
    </NotFound>
</Router>

他の対話型コンポーネントなど、<NotFound> タグのコンテンツとして任意の項目がサポートされます。 NotFound コンテンツに既定のレイアウトを適用するには、「ASP.NET Core Blazor のレイアウト」をご覧ください。

複数のアセンブリからコンポーネントにルーティングする

AdditionalAssemblies パラメーターを使用して、Router コンポーネントで、ルーティング可能なコンポーネントを検索するときに考慮する追加のアセンブリを指定します。 AppAssembly に指定されたアセンブリに加え、追加のアセンブリがスキャンされます。 次の例では、Component1 は、参照されているコンポーネント クラス ライブラリに定義されているルーティング可能なコンポーネントです。 次の AdditionalAssemblies の例は、Component1 のルーティング サポートの結果を示しています。

App.razor:

<Router
    AppAssembly="@typeof(App).Assembly"
    AdditionalAssemblies="new[] { typeof(Component1).Assembly }">
    @* ... Router component elements ... *@
</Router>

注意

ASP.NET Core 5.0.1 のリリースと、その他の 5.x リリースでは、Router コンポーネントに @trueに設定された PreferExactMatches パラメーターが含まれています。 詳細については、「ASP.NET Core 3.1 から 5.0 への移行」を参照してください。

ルート パラメーター

ルーターでルート パラメーターを使用すれば、同じ名前の対応するコンポーネント パラメーターを設定できます。 ルート パラメーター名では大文字と小文字は区別されません。 次の例では、text パラメーターを使用して、ルート セグメントの値をコンポーネントの Text プロパティに割り当てます。 /route-parameter-1/amazing に対して要求が行われると、<h1> タグのコンテンツは Blazor is amazing! としてレンダリングされます。

Pages/RouteParameter1.razor:

@page "/route-parameter-1/{text}"

<h1>Blazor is @Text!</h1>

@code {
    [Parameter]
    public string? Text { get; set; }
}
@page "/route-parameter-1/{text}"

<h1>Blazor is @Text!</h1>

@code {
    [Parameter]
    public string? Text { get; set; }
}
@page "/route-parameter-1/{text}"

<h1>Blazor is @Text!</h1>

@code {
    [Parameter]
    public string Text { get; set; }
}
@page "/route-parameter-1/{text}"

<h1>Blazor is @Text!</h1>

@code {
    [Parameter]
    public string Text { get; set; }
}

省略可能なパラメーターがサポートされています。 次の例では、省略可能なパラメーター text を使用して、ルート セグメントの値をコンポーネントの Text プロパティに割り当てます。 セグメントが存在しない場合、Text の値は fantastic に設定されます。

省略可能なパラメーターはサポートされていません。 以下の例では、2 つの @page ディレクティブが適用されています。 1 つ目のディレクティブでは、パラメーターを指定せずにコンポーネントへの移動を許可します。 2 つ目のディレクティブでは、{text} ルート パラメーターの値をコンポーネントの Text プロパティに割り当てます。

Pages/RouteParameter2.razor:

@page "/route-parameter-2/{text?}"

<h1>Blazor is @Text!</h1>

@code {
    [Parameter]
    public string? Text { get; set; }

    protected override void OnInitialized()
    {
        Text = Text ?? "fantastic";
    }
}
@page "/route-parameter-2/{text?}"

<h1>Blazor is @Text!</h1>

@code {
    [Parameter]
    public string? Text { get; set; }

    protected override void OnInitialized()
    {
        Text = Text ?? "fantastic";
    }
}
@page "/route-parameter-2/{text?}"

<h1>Blazor is @Text!</h1>

@code {
    [Parameter]
    public string Text { get; set; }

    protected override void OnInitialized()
    {
        Text = Text ?? "fantastic";
    }
}
@page "/route-parameter-2"
@page "/route-parameter-2/{text}"

<h1>Blazor is @Text!</h1>

@code {
    [Parameter]
    public string Text { get; set; }

    protected override void OnInitialized()
    {
        Text = Text ?? "fantastic";
    }
}

オプションのパラメーター値が異なる同じコンポーネントへのアプリの移動を許可するには、OnInitialized{Async} ではなく、OnParametersSet を使用します。 前の例に基づいて、ユーザーが /route-parameter-2 から /route-parameter-2/amazing に、または /route-parameter-2/amazing から /route-parameter-2 に移動できる必要がある場合は、OnParametersSet を使用してください。

protected override void OnParametersSet()
{
    Text = Text ?? "fantastic";
}

Note

ルート パラメーターは、クエリ文字列値では使用できません。 クエリ文字列の使用方法については、「クエリ文字列」セクションをご覧ください。

ルート制約

ルート制約は、コンポーネントへのルート セグメントに型の一致を適用します。

次の例で、User コンポーネントへのルートは、次の場合にのみ一致します。

  • 要求 URL に Id ルート セグメントが存在する。
  • Id セグメントが整数 (int) 型である。

Pages/User.razor:

@page "/user/{Id:int}"

<h1>User Id: @Id</h1>

@code {
    [Parameter]
    public int Id { get; set; }
}
@page "/user/{Id:int}"

<h1>User Id: @Id</h1>

@code {
    [Parameter]
    public int Id { get; set; }
}
@page "/user/{Id:int}"

<h1>User Id: @Id</h1>

@code {
    [Parameter]
    public int Id { get; set; }
}
@page "/user/{Id:int}"

<h1>User Id: @Id</h1>

@code {
    [Parameter]
    public int Id { get; set; }
}

注意

ルート制約は、クエリ文字列値では使用できません。 クエリ文字列の使用方法については、「クエリ文字列」セクションをご覧ください。

次の表に示すルート制約を使用できます。 インバリアント カルチャと一致するルート制約については、表の下の警告で詳細をご確認ください。

制約 一致の例 インバリアント
カルチャ
一致
bool {active:bool} true, FALSE いいえ
datetime {dob:datetime} 2016-12-31, 2016-12-31 7:32pm はい
decimal {price:decimal} 49.99, -1,000.01 はい
double {weight:double} 1.234, -1,001.01e8 はい
float {weight:float} 1.234, -1,001.01e8 はい
guid {id:guid} CD2C1638-1638-72D5-1638-DEADBEEF1638, {CD2C1638-1638-72D5-1638-DEADBEEF1638} いいえ
int {id:int} 123456789, -123456789 はい
long {ticks:long} 123456789, -123456789 はい

警告

URL の妥当性を検証し、CLR 型 (intDateTime など) に変換されるルート制約では、常にインバリアント カルチャが使用されます。 これらの制約では、URL がローカライズ不可であることが前提となります。

ルート制約は、省略可能なパラメーターでも使用できます。 次の例で、Id は必須ですが、Option は、省略可能なブール型のルート パラメーターです。

Pages/User.razor:

@page "/user/{Id:int}/{Option:bool?}"

<p>
    Id: @Id
</p>

<p>
    Option: @Option
</p>

@code {
    [Parameter]
    public int Id { get; set; }

    [Parameter]
    public bool Option { get; set; }
}

ドットを含む URL によるルーティング

ホストされている Blazor WebAssembly および Blazor Server アプリの場合は、サーバー側の既定のルート テンプレートで、ファイルが要求されているドット (.) が要求 URL の最後のセグメントに含まれていると想定されます。 たとえば、相対 URL /example/some.thing は、ルーターによって some.thing という名前のファイルに対する要求として解釈されます。 追加の構成がないと、some.thing@page ディレクティブ を含むコンポーネントにルーティングすることを意図しており、some.thing がルート パラメーター値である場合に、アプリによって "404 - 見つかりません" という応答が返されます。 ドットが含まれる 1 つまたは複数のパラメーターを指定してルートを使用するには、アプリでカスタム テンプレートを使ってルートを構成する必要があります。

URL の最後のセグメントからルート パラメーターを受け取ることができる次の Example コンポーネントについて考えてみます。

Pages/Example.razor:

@page "/example/{param?}"

<p>
    Param: @Param
</p>

@code {
    [Parameter]
    public string? Param { get; set; }
}
@page "/example/{param?}"

<p>
    Param: @Param
</p>

@code {
    [Parameter]
    public string? Param { get; set; }
}
@page "/example/{param?}"

<p>
    Param: @Param
</p>

@code {
    [Parameter]
    public string Param { get; set; }
}
@page "/example"
@page "/example/{param}"

<p>
    Param: @Param
</p>

@code {
    [Parameter]
    public string Param { get; set; }
}

ホストされている Blazor WebAssembly ソリューションServer アプリで、param ルート パラメーターのドットを使って要求をルーティングできるようにするには、Program.cs で省略可能なパラメーターを指定してフォールバック ファイル ルート テンプレートを追加します。

app.MapFallbackToFile("/example/{param?}", "index.html");

param ルート パラメーターのドットを使って要求をルーティングするように Blazor Server アプリを構成するには、Program.cs で省略可能なパラメーターを指定してフォールバック ページ ルート テンプレートを追加します。

app.MapFallbackToPage("/example/{param?}", "/_Host");

ホストされている Blazor WebAssembly ソリューションServer アプリで、param ルート パラメーターのドットを使って要求をルーティングできるようにするには、Startup.Configure で省略可能なパラメーターを指定してフォールバック ファイル ルート テンプレートを追加します。

Startup.cs:

endpoints.MapFallbackToFile("/example/{param?}", "index.html");

param ルート パラメーターのドットを使って要求をルーティングするように Blazor Server アプリを構成するには、Startup.Configure で省略可能なパラメーターを指定してフォールバック ページ ルート テンプレートを追加します。

Startup.cs:

endpoints.MapFallbackToPage("/example/{param?}", "/_Host");

詳細については、「ASP.NET Core のルーティング」を参照してください。

キャッチオールのルート パラメーター

複数のフォルダー境界にまたがるパスをキャプチャするキャッチオール ルート パラメーターが、コンポーネントでサポートされます。

キャッチオールのルート パラメーターは次のとおりです。

  • ルート セグメント名と一致する名前が付けられている。 名前付けで大文字と小文字は区別されない。
  • string 型。 フレームワークによって自動キャストは提供されません。
  • URL の末尾。

Pages/CatchAll.razor:

@page "/catch-all/{*pageRoute}"

@code {
    [Parameter]
    public string? PageRoute { get; set; }
}
@page "/catch-all/{*pageRoute}"

@code {
    [Parameter]
    public string? PageRoute { get; set; }
}
@page "/catch-all/{*pageRoute}"

@code {
    [Parameter]
    public string PageRoute { get; set; }
}

ルート テンプレートが /catch-all/{*pageRoute} の URL /catch-all/this/is/a/test の場合、PageRoute の値は this/is/a/test に設定されます。

キャプチャされたパスのスラッシュとセグメントはデコードされます。 /catch-all/{*pageRoute} のルート テンプレートでは、URL /catch-all/this/is/a%2Ftest%2A から this/is/a/test* が生成されます。

URI およびナビゲーション状態ヘルパー

C# コード内の URI とナビゲーションを管理するには、NavigationManager を使用します。 NavigationManager には、次の表に示すイベントとメソッドがあります。

メンバー 説明
Uri 現在の絶対 URI を取得します。
BaseUri 絶対 URI を生成するために、相対 URI パスの前に付加できるベース URI (末尾のスラッシュを含む) を取得します。 通常、BaseUri はドキュメントの <base> 要素の href 属性に対応します (<head> コンテンツの場所)。
NavigateTo 指定された URI に移動します。 forceLoadtrue の場合:
  • クライアント側のルーティングはバイパスされます。
  • URI が通常クライアント側ルーターによって処理されるかどうかにかかわらず、ブラウザーでは、強制的にサーバーから新しいページが読み込まれます。
replacetrue の場合、履歴スタックに新しい URI をプッシュする代わりに、ブラウザー履歴の現在の URI が置き換えられます。
LocationChanged ナビゲーションの場所が変更されたときに発生するイベントです。 詳細については、「場所の変更」セクションを参照してください。
ToAbsoluteUri 相対 URI を絶対 URI に変換します。
ToBaseRelativePath ベース URI (たとえば、BaseUri によって以前に返された URI) が与えられると、絶対 URI を、ベース URI プレフィックスに相対的な URI に変換します。
RegisterLocationChangingHandler 受信ナビゲーション イベントを処理するハンドラーを登録します。 NavigateTo を呼び出すと、常にハンドラーが呼び出されます。
GetUriWithQueryParameter 1 つのパラメーターを追加、更新、または削除して NavigationManager.Uri を更新することで構築された URI を返します。 詳細については、「クエリ文字列」セクションを参照してください。
メンバー 説明
Uri 現在の絶対 URI を取得します。
BaseUri 絶対 URI を生成するために、相対 URI パスの前に付加できるベース URI (末尾のスラッシュを含む) を取得します。 通常、BaseUri はドキュメントの <base> 要素の href 属性に対応します (<head> コンテンツの場所)。
NavigateTo 指定された URI に移動します。 forceLoadtrue の場合:
  • クライアント側のルーティングはバイパスされます。
  • URI が通常クライアント側ルーターによって処理されるかどうかにかかわらず、ブラウザーでは、強制的にサーバーから新しいページが読み込まれます。
replacetrue の場合、履歴スタックに新しい URI をプッシュする代わりに、ブラウザー履歴の現在の URI が置き換えられます。
LocationChanged ナビゲーションの場所が変更されたときに発生するイベントです。 詳細については、「場所の変更」セクションを参照してください。
ToAbsoluteUri 相対 URI を絶対 URI に変換します。
ToBaseRelativePath ベース URI (たとえば、BaseUri によって以前に返された URI) が与えられると、絶対 URI を、ベース URI プレフィックスに相対的な URI に変換します。
GetUriWithQueryParameter 1 つのパラメーターを追加、更新、または削除して NavigationManager.Uri を更新することで構築された URI を返します。 詳細については、「クエリ文字列」セクションを参照してください。
メンバー 説明
Uri 現在の絶対 URI を取得します。
BaseUri 絶対 URI を生成するために、相対 URI パスの前に付加できるベース URI (末尾のスラッシュを含む) を取得します。 通常、BaseUriwwwroot/index.html (Blazor WebAssembly) または Pages/_Host.cshtml (Blazor Server) 内のドキュメントの <base> 要素の href 属性に対応します。
NavigateTo 指定された URI に移動します。 forceLoadtrue の場合:
  • クライアント側のルーティングはバイパスされます。
  • URI が通常クライアント側ルーターによって処理されるかどうかにかかわらず、ブラウザーでは、強制的にサーバーから新しいページが読み込まれます。
LocationChanged ナビゲーションの場所が変更されたときに発生するイベントです。
ToAbsoluteUri 相対 URI を絶対 URI に変換します。
ToBaseRelativePath ベース URI (たとえば、BaseUri によって以前に返された URI) が与えられると、絶対 URI を、ベース URI プレフィックスに相対的な URI に変換します。

場所の変更

LocationChanged イベントの場合、LocationChangedEventArgs でナビゲーション イベントに関する次の情報が提供されます。

次のコンポーネント:

  • NavigateTo を使用してボタンが選択されたときに、アプリの Counter コンポーネント (Pages/Counter.razor) に移動します。
  • NavigationManager.LocationChanged をサブスクライブすることで、場所の変更イベントを処理します。
    • HandleLocationChanged メソッドは、Dispose がフレームワークによって呼び出されると、アンフックになります。 このメソッドをアンフックすることで、コンポーネントのガベージ コレクションが許可されます。

    • ロガーの実装では、ボタンが選択されたときに次の情報をログに記録します。

      BlazorSample.Pages.Navigate: Information: URL of new location: https://localhost:{PORT}/counter

Pages/Navigate.razor:

@page "/navigate"
@using Microsoft.Extensions.Logging 
@implements IDisposable
@inject ILogger<Navigate> Logger
@inject NavigationManager Navigation

<h1>Navigate in component code example</h1>

<button class="btn btn-primary" @onclick="NavigateToCounterComponent">
    Navigate to the Counter component
</button>

@code {
    private void NavigateToCounterComponent()
    {
        Navigation.NavigateTo("counter");
    }

    protected override void OnInitialized()
    {
        Navigation.LocationChanged += HandleLocationChanged;
    }

    private void HandleLocationChanged(object? sender, LocationChangedEventArgs e)
    {
        Logger.LogInformation("URL of new location: {Location}", e.Location);
    }

    public void Dispose()
    {
        Navigation.LocationChanged -= HandleLocationChanged;
    }
}
@page "/navigate"
@using Microsoft.Extensions.Logging 
@implements IDisposable
@inject ILogger<Navigate> Logger
@inject NavigationManager Navigation

<h1>Navigate in component code example</h1>

<button class="btn btn-primary" @onclick="NavigateToCounterComponent">
    Navigate to the Counter component
</button>

@code {
    private void NavigateToCounterComponent()
    {
        Navigation.NavigateTo("counter");
    }

    protected override void OnInitialized()
    {
        Navigation.LocationChanged += HandleLocationChanged;
    }

    private void HandleLocationChanged(object? sender, LocationChangedEventArgs e)
    {
        Logger.LogInformation("URL of new location: {Location}", e.Location);
    }

    public void Dispose()
    {
        Navigation.LocationChanged -= HandleLocationChanged;
    }
}
@page "/navigate"
@using Microsoft.Extensions.Logging 
@implements IDisposable
@inject ILogger<Navigate> Logger
@inject NavigationManager Navigation

<h1>Navigate in component code example</h1>

<button class="btn btn-primary" @onclick="NavigateToCounterComponent">
    Navigate to the Counter component
</button>

@code {
    private void NavigateToCounterComponent()
    {
        Navigation.NavigateTo("counter");
    }

    protected override void OnInitialized()
    {
        Navigation.LocationChanged += HandleLocationChanged;
    }

    private void HandleLocationChanged(object sender, LocationChangedEventArgs e)
    {
        Logger.LogInformation("URL of new location: {Location}", e.Location);
    }

    public void Dispose()
    {
        Navigation.LocationChanged -= HandleLocationChanged;
    }
}
@page "/navigate"
@using Microsoft.Extensions.Logging 
@implements IDisposable
@inject ILogger<Navigate> Logger
@inject NavigationManager Navigation

<h1>Navigate in component code example</h1>

<button class="btn btn-primary" @onclick="NavigateToCounterComponent">
    Navigate to the Counter component
</button>

@code {
    private void NavigateToCounterComponent()
    {
        Navigation.NavigateTo("counter");
    }

    protected override void OnInitialized()
    {
        Navigation.LocationChanged += HandleLocationChanged;
    }

    private void HandleLocationChanged(object sender, LocationChangedEventArgs e)
    {
        Logger.LogInformation("URL of new location: {Location}", e.Location);
    }

    public void Dispose()
    {
        Navigation.LocationChanged -= HandleLocationChanged;
    }
}

コンポーネントの破棄について詳しくは、「ASP.NET Core Razor コンポーネントのライフサイクル」をご覧ください。

NavigationManager では、ブラウザーの History API を使用して、アプリによって行われた各場所の変更に関連付けられているナビゲーション履歴の状態を維持します。 履歴状態の維持は、外部 ID プロバイダーを使用してユーザーを認証する場合など、外部リダイレクト シナリオで特に役立ちます。 詳細については、「ナビゲーション オプション」セクションを参照してください。

NavigationOptionsNavigateTo に渡して、次の動作を制御します。

  • ForceLoad: クライアント側のルーティングをバイパスし、URI がクライアント側ルーターによって処理されるかどうかにかかわらず、ブラウザーにサーバーから新しいページを読み込むよう強制します。 既定値は false です。
  • ReplaceHistoryEntry: 履歴スタックの現在のエントリを置き換えます。 false の場合は、履歴スタックに新しいエントリを追加します。 既定値は false です。
  • HistoryEntryState: 履歴エントリに追加する状態を取得または設定します。
Navigation.NavigateTo("/path", new NavigationOptions
{
    HistoryEntryState = "Navigation state"
});

場所の変更の処理中にターゲット履歴エントリに関連付けられている状態を取得する方法の詳細については、「場所の変更を処理/防止する」セクション参照してください。

クエリ文字列

[Parameter] 属性と共に [SupplyParameterFromQuery] 属性を使用して、"ルーティング可能な" コンポーネントのコンポーネント パラメーターがクエリ文字列から取得可能であることを指定します。

Note

コンポーネント パラメーターでは、@page ディレクティブを使用したルーティング可能なコンポーネントのクエリ パラメーター値のみを受け取ることができます。

トップダウンの情報フローが妨害されないようにし、フレームワークとアプリの両方でパラメーターの処理順序を明確にするために、クエリ パラメーターを直接受け取るのはルーティング可能なコンポーネントのみです。 この設計により、特定のパラメーターの処理順序を想定して記述されたアプリ コードの特定しにくいバグを回避できます。 クエリ パラメーターの値をルーティング可能でないコンポーネントに渡すためには、自由にカスタム カスケード パラメーターを定義したり、通常のコンポーネント パラメーターに直接割り当てたりできます。

クエリ文字列から提供されるコンポーネント パラメーターでは、次の型がサポートされます。

  • bool, DateTime, decimal, double, float, Guid, int, long, string.
  • 上記の型の Null 許容バリアント。
  • 上記の型の配列 (Null 許容、Null 非許容どちらでも)。

指定された型に対して、適切なカルチャに依存しない書式設定が適用されます (CultureInfo.InvariantCulture)。

コンポーネント パラメーター名とは異なるクエリ パラメーター名を使用するには、[SupplyParameterFromQuery] 属性の Name プロパティを指定します。 次の例では、コンポーネント パラメーターの C# 名は {COMPONENT PARAMETER NAME} です。 {QUERY PARAMETER NAME} プレースホルダーに対して異なるクエリ パラメーター名が指定されています。

[Parameter]
[SupplyParameterFromQuery(Name = "{QUERY PARAMETER NAME}")]
public string? {COMPONENT PARAMETER NAME} { get; set; }

URL が /search?filter=scifi%20stars&page=3&star=LeVar%20Burton&star=Gary%20Oldman である次の例の場合:

  • Filter プロパティは scifi stars に解決されます。
  • Page プロパティは 3 に解決されます。
  • 配列 Starsstar という名前 (Name = "star") のクエリ パラメーターから入力され、LeVar BurtonGary Oldman に解決されます。

Pages/Search.razor:

@page "/search"

<h1>Search Example</h1>

<p>Filter: @Filter</p>

<p>Page: @Page</p>

@if (Stars is not null)
{
    <p>Assignees:</p>

    <ul>
        @foreach (var name in Stars)
        {
            <li>@name</li>
        }
    </ul>
}

@code {
    [Parameter]
    [SupplyParameterFromQuery]
    public string? Filter { get; set; }

    [Parameter]
    [SupplyParameterFromQuery]
    public int? Page { get; set; }

    [Parameter]
    [SupplyParameterFromQuery(Name = "star")]
    public string[]? Stars { get; set; }
}

NavigationManager.GetUriWithQueryParameter を使用して、現在の URL の 1 つ以上のクエリ パラメーターを追加、変更、または削除します。

@inject NavigationManager Navigation

...

Navigation.GetUriWithQueryParameter("{NAME}", {VALUE})

前の例の場合:

  • {NAME} プレースホルダーでは、クエリ パラメーター名が指定されます。 {VALUE} プレースホルダーでは、サポートされている型として値が指定されます。 サポートされている型の一覧については、このセクションで後述します。
  • 1 つのパラメーターを含む現在の URL と等しい文字列が返されます。
    • クエリ パラメーター名が現在の URL に存在しない場合に追加されます。
    • クエリ パラメーターが現在の URL に存在する場合、指定された値に更新されます。
    • 指定された値の型が Null 許容で、値が null の場合は、削除されます。
  • 指定された型に対して、適切なカルチャに依存しない書式設定が適用されます (CultureInfo.InvariantCulture)。
  • クエリ パラメーターの名前と値は URL エンコードされます。
  • 型のインスタンスが複数ある場合、一致するクエリ パラメーター名を持つすべての値が置き換えられます。

NavigationManager.GetUriWithQueryParameters を呼び出して、Uri から構築され、複数のパラメーターが追加、更新、または削除された URI を作成します。 各値について、フレームワークでは value?.GetType() を使用して各クエリ パラメーターのランタイム型が決定され、適切なカルチャに依存しない書式設定が選択されます。 サポートされていない型に対しては、フレームワークによってエラーがスローされます。

@inject NavigationManager Navigation

...

Navigation.GetUriWithQueryParameters({PARAMETERS})

{PARAMETERS} プレースホルダーは IReadOnlyDictionary<string, object> です。

URI 文字列を GetUriWithQueryParameters に渡して、指定された URI から、複数のパラメーターを追加、更新、または削除して、新しい URI を生成します。 各値について、フレームワークでは value?.GetType() を使用して各クエリ パラメーターのランタイム型が決定され、適切なカルチャに依存しない書式設定が選択されます。 サポートされていない型に対しては、フレームワークによってエラーがスローされます。 サポートされている型の一覧については、このセクションで後述します。

@inject NavigationManager Navigation

...

Navigation.GetUriWithQueryParameters("{URI}", {PARAMETERS})
  • {URI} プレースホルダーは、クエリ文字列を含む URI、または含まない URI です。
  • {PARAMETERS} プレースホルダーは IReadOnlyDictionary<string, object> です。

サポートされている型は、ルート制約でサポートされている型と同じです。

  • bool
  • DateTime
  • decimal
  • double
  • float
  • Guid
  • int
  • long
  • string

サポートされる型には次のようなものがあります。

  • 上記の型の Null 許容バリアント。
  • 上記の型の配列 (Null 許容、Null 非許容どちらでも)。

パラメーターが存在する場合にクエリ パラメーター値を置き換える

Navigation.GetUriWithQueryParameter("full name", "Morena Baccarin")
現在の URL 生成された URL
scheme://host/?full%20name=David%20Krumholtz&age=42 scheme://host/?full%20name=Morena%20Baccarin&age=42
scheme://host/?fUlL%20nAmE=David%20Krumholtz&AgE=42 scheme://host/?full%20name=Morena%20Baccarin&AgE=42
scheme://host/?full%20name=Jewel%20Staite&age=42&full%20name=Summer%20Glau scheme://host/?full%20name=Morena%20Baccarin&age=42&full%20name=Morena%20Baccarin
scheme://host/?full%20name=&age=42 scheme://host/?full%20name=Morena%20Baccarin&age=42
scheme://host/?full%20name= scheme://host/?full%20name=Morena%20Baccarin

パラメーターが存在しない場合にクエリ パラメーターと値を追加する

Navigation.GetUriWithQueryParameter("name", "Morena Baccarin")
現在の URL 生成された URL
scheme://host/?age=42 scheme://host/?age=42&name=Morena%20Baccarin
scheme://host/ scheme://host/?name=Morena%20Baccarin
scheme://host/? scheme://host/?name=Morena%20Baccarin

パラメーター値が null の場合にクエリ パラメーターを削除する

Navigation.GetUriWithQueryParameter("full name", (string)null)
現在の URL 生成された URL
scheme://host/?full%20name=David%20Krumholtz&age=42 scheme://host/?age=42
scheme://host/?full%20name=Sally%20Smith&age=42&full%20name=Summer%20Glau scheme://host/?age=42
scheme://host/?full%20name=Sally%20Smith&age=42&FuLl%20NaMe=Summer%20Glau scheme://host/?age=42
scheme://host/?full%20name=&age=42 scheme://host/?age=42
scheme://host/?full%20name= scheme://host/

クエリ パラメーターの追加、更新、削除

次に例を示します。

  • name が削除されます (存在する場合)。
  • age が値 25 (int) で追加されます (存在しない場合)。 存在する場合、age は値 25 に更新されます。
  • eye color が値 green として追加または更新されます。
Navigation.GetUriWithQueryParameters(
    new Dictionary<string, object?>
    {
        ["name"] = null,
        ["age"] = (int?)25,
        ["eye color"] = "green"
    })
現在の URL 生成された URL
scheme://host/?name=David%20Krumholtz&age=42 scheme://host/?age=25&eye%20color=green
scheme://host/?NaMe=David%20Krumholtz&AgE=42 scheme://host/?age=25&eye%20color=green
scheme://host/?name=David%20Krumholtz&age=42&keepme=true scheme://host/?age=25&keepme=true&eye%20color=green
scheme://host/?age=42&eye%20color=87 scheme://host/?age=25&eye%20color=green
scheme://host/? scheme://host/?age=25&eye%20color=green
scheme://host/ scheme://host/?age=25&eye%20color=green

列挙可能な値のサポート

次に例を示します。

  • full name が単一の値 Morena Baccarin として追加または更新されます。
  • ping パラメーターが 351687240 として追加されるか置き換えられます。
Navigation.GetUriWithQueryParameters(
    new Dictionary<string, object?>
    {
        ["full name"] = "Morena Baccarin",
        ["ping"] = new int?[] { 35, 16, null, 87, 240 }
    })
現在の URL 生成された URL
scheme://host/?full%20name=David%20Krumholtz&ping=8&ping=300 scheme://host/?full%20name=Morena%20Baccarin&ping=35&ping=16&ping=87&ping=240
scheme://host/?ping=8&full%20name=David%20Krumholtz&ping=300 scheme://host/?ping=35&full%20name=Morena%20Baccarin&ping=16&ping=87&ping=240
scheme://host/?ping=8&ping=300&ping=50&ping=68&ping=42 scheme://host/?ping=35&ping=16&ping=87&ping=240&full%20name=Morena%20Baccarin

追加または変更されたクエリ文字列を使用して移動するには、生成された URL を NavigateTo に渡します。

次の例では以下を呼び出します。

  • GetUriWithQueryParameter を呼び出し、値 Morena Baccarin を使用して name クエリ パラメーターを追加または置き換えます。
  • NavigateTo を呼び出して、新しい URL へのナビゲーションをトリガーします。
Navigation.NavigateTo(
    Navigation.GetUriWithQueryParameter("name", "Morena Baccarin"));

要求のクエリ文字列は、NavigationManager.Uri プロパティから取得されます。

@inject NavigationManager Navigation

...

var query = new Uri(Navigation.Uri).Query;

クエリ文字列のパラメーターを解析するための 1 つの方法は、JavaScript (JS) 相互運用URLSearchParams を使用することです。

export createQueryString = (string queryString) => new URLSearchParams(queryString);

JavaScript モジュールを使用した JavaScript の分離について詳しくは、「ASP.NET Core Blazor で .NET メソッドから JavaScript 関数を呼び出す」をご覧ください。

名前付き要素へのハッシュされたルーティング

要素へのハッシュされた (#) 参照による次の方法を使って、名前付き要素に移動します。 コンポーネント内の要素へのルートと、外部コンポーネント内の要素へのルートでは、ルート (root) 相対パスが使われます。 先頭のスラッシュ (/) は省略できます。

次の各方法の例では、Counter コンポーネント内の idtargetElement の要素への移動を示します。

  • アンカー要素 (<a>) と href:

    <a href="/counter#targetElement">
    
  • NavLink コンポーネントと href:

    <NavLink href="/counter#targetElement">
    
  • NavigationManager.NavigateTo に相対 URL を渡す:

    Navigation.NavigateTo("/counter#targetElement");
    

次の例では、コンポーネント内の名前付きの H2 見出しと外部コンポーネントへの、ハッシュされたルーティングを示します。

Index (Pages/Index.razor) と Counter (Pages/Counter.razor) コンポーネントでは、ナビゲーション ターゲットとして機能するように、次のマークアップを既存のコンポーネント マークアップの末尾に配置します。 <div> では、ブラウザーのスクロール動作を示すために、わざと縦方向のスペースを作成しています。

<div class="border border-info rounded bg-info" style="height:500px"></div>

<h2 id="targetElement">Target H2 heading</h2>
<p>Content!</p>

次の HashedRouting コンポーネントをアプリに追加します。

Pages/HashedRouting.razor:

@page "/hashed-routing"
@inject NavigationManager Navigation

<PageTitle>Hashed routing</PageTitle>

<h1>Hashed routing to named elements</h1>

<ul>
    <li>
        <a href="/hashed-routing#targetElement">
            Anchor in this component
        </a>
    </li>
    <li>
        <a href="/#targetElement">
            Anchor to the <code>Index</code> component
        </a>
    </li>
    <li>
        <a href="/counter#targetElement">
            Anchor to the <code>Counter</code> component
        </a>
    </li>
    <li>
        <NavLink href="/hashed-routing#targetElement">
            Use a `NavLink` component in this component
        </NavLink>
    </li>
    <li>
        <button @onclick="NavigateToElement">
            Navigate with <code>NavigationManager</code> to the 
            <code>Counter</code> component
        </button>
    </li>
</ul>

<div class="border border-info rounded bg-info" style="height:500px"></div>

<h2 id="targetElement">Target H2 heading</h2>
<p>Content!</p>

@code {
    private void NavigateToElement()
    {
        Navigation.NavigateTo("/counter#targetElement");
    }
}

<Navigating> コンテンツとのユーザー操作

Router コンポーネントによって、ページ切り替えの発生をユーザーに示すことができます。

App コンポーネント (App.razor) の上部に、Microsoft.AspNetCore.Components.Routing 名前空間の @using ディレクティブを追加します。

@using Microsoft.AspNetCore.Components.Routing

ページ切り替えイベント中に表示するマークアップを含むコンポーネントに <Navigating> タグを追加します。 詳細については、Navigating (API ドキュメント) を参照してください。

App コンポーネント (App.razor) のルーター要素コンテンツ (<Router>...</Router>) は、次のとおりです。

<Navigating>
    <p>Loading the requested page&hellip;</p>
</Navigating>

Navigating プロパティを使う例については、「ASP.NET Core Blazor WebAssembly でのアセンブリの遅延読み込み」をご覧ください。

OnNavigateAsync で非同期ナビゲーション イベントを処理する

Router コンポーネントは、OnNavigateAsync 機能をサポートしています。 OnNavigateAsync ハンドラーは、ユーザーが次のことを行った場合に呼び出されます。

  • ブラウザー内でルートに直接移動して、初めてアクセスする。
  • リンクまたは NavigationManager.NavigateTo 呼び出しを使用して新しいルートに移動する。

App コンポーネント (App.razor) 内は、次のようになっています。

<Router AppAssembly="@typeof(App).Assembly" 
    OnNavigateAsync="@OnNavigateAsync">
    ...
</Router>

@code {
    private async Task OnNavigateAsync(NavigationContext args)
    {
        ...
    }
}
<Router AppAssembly="@typeof(Program).Assembly" 
    OnNavigateAsync="@OnNavigateAsync">
    ...
</Router>

@code {
    private async Task OnNavigateAsync(NavigationContext args)
    {
        ...
    }
}

Note

ASP.NET Core 5.0.1 のリリースと、その他の 5.x リリースでは、Router コンポーネントに @trueに設定された PreferExactMatches パラメーターが含まれています。 詳細については、「ASP.NET Core 3.1 から 5.0 への移行」を参照してください。

OnNavigateAsync を使う例については、「ASP.NET Core Blazor WebAssembly でのアセンブリの遅延読み込み」をご覧ください。

Blazor Server アプリ、またはホストされている Blazor WebAssembly アプリのサーバー上でプリレンダリングする場合、OnNavigateAsync が "2 回" 実行されます。

  • 1 回目は、要求されたエンドポイント コンポーネントが、最初に静的にレンダリングされるとき。
  • 2 回目は、エンドポイント コンポーネントがブラウザーによってレンダリングされるとき。

OnNavigateAsync で開発者コードが 2 回実行されないようにするには、App コンポーネントに、OnAfterRender{Async} で使用する NavigationContext を格納します (firstRender がチェックされている場合)。 詳細については、「Blazor のライフサイクル」の記事にある「JavaScript 相互運用を使用したプリレンダリング」を参照してください。

OnNavigateAsync でキャンセルを処理する

OnNavigateAsync コールバックに渡される NavigationContext オブジェクトには、新しいナビゲーション イベントが発生したときに設定される CancellationToken が含まれています。 このキャンセル トークンが、古いナビゲーションに対して OnNavigateAsync コールバックを継続して実行しないように設定されている場合は、OnNavigateAsync コールバックをスローする必要があります。

ユーザーがエンドポイントに移動したものの、その後すぐに新しいエンドポイントに移動する場合、アプリで最初のエンドポイントの OnNavigateAsync コールバックを実行し続けるべきではありません。

App コンポーネントの例を次に示します。

  • キャンセル トークンは、PostAsJsonAsync への呼び出しで渡されます。ユーザーが /about エンドポイントから離れた場合は、POST が取り消されます。
  • ユーザーが /store エンドポイントから移動した場合は、製品のプリフェッチ操作中にキャンセル トークンが設定されます。

App.razor:

@inject HttpClient Http
@inject ProductCatalog Products

<Router AppAssembly="@typeof(App).Assembly" 
    OnNavigateAsync="@OnNavigateAsync">
    ...
</Router>

@code {
    private async Task OnNavigateAsync(NavigationContext context)
    {
        if (context.Path == "/about") 
        {
            var stats = new Stats { Page = "/about" };
            await Http.PostAsJsonAsync("api/visited", stats, 
                context.CancellationToken);
        }
        else if (context.Path == "/store")
        {
            var productIds = new[] { 345, 789, 135, 689 };

            foreach (var productId in productIds) 
            {
                context.CancellationToken.ThrowIfCancellationRequested();
                Products.Prefetch(productId);
            }
        }
    }
}
@inject HttpClient Http
@inject ProductCatalog Products

<Router AppAssembly="@typeof(Program).Assembly" 
    OnNavigateAsync="@OnNavigateAsync">
    ...
</Router>

@code {
    private async Task OnNavigateAsync(NavigationContext context)
    {
        if (context.Path == "/about") 
        {
            var stats = new Stats { Page = "/about" };
            await Http.PostAsJsonAsync("api/visited", stats, 
                context.CancellationToken);
        }
        else if (context.Path == "/store")
        {
            var productIds = new[] { 345, 789, 135, 689 };

            foreach (var productId in productIds) 
            {
                context.CancellationToken.ThrowIfCancellationRequested();
                Products.Prefetch(productId);
            }
        }
    }
}

注意

ASP.NET Core 5.0.1 のリリースと、その他の 5.x リリースでは、Router コンポーネントに @trueに設定された PreferExactMatches パラメーターが含まれています。 詳細については、「ASP.NET Core 3.1 から 5.0 への移行」を参照してください。

Note

NavigationContext 内のキャンセル トークンが取り消された場合にスローしないと、前のナビゲーションからのコンポーネントをレンダリングするなど、意図しない動作が発生する可能性があります。

場所の変更を処理/防止する

RegisterLocationChangingHandler では、受信ナビゲーション イベントを処理するハンドラーを登録します。 LocationChangingContext によって提供されるハンドラーのコンテキストには、次のプロパティが含まれます。

  • TargetLocation: ターゲットの場所を取得します。
  • HistoryEntryState: ターゲット履歴エントリに関連付けられている状態を取得します。
  • IsNavigationIntercepted: ナビゲーションがリンクからインターセプトされたかどうかを取得します。
  • CancellationToken: ナビゲーションが取り消されたかどうかを判断する CancellationToken を取得します。たとえば、ユーザーが別のナビゲーションをトリガーしたかどうかを判断します。
  • PreventNavigation: ナビゲーションが続行されないようにするために呼び出されます。

コンポーネントでは、OnAfterRender または OnAfterRenderAsync メソッドに複数の場所変更ハンドラーを登録できます。 ナビゲーションでは、(複数のコンポーネントにまたがって) アプリ全体に登録されているすべての場所変更ハンドラーを呼び出し、すべての内部ナビゲーションでそれらをすべて並列で実行します。 NavigateTo に加え、次の場合にハンドラーが呼び出されます。

  • 内部リンクを選択する場合。これは、アプリのベース パスの下にある URL を指すリンクです。
  • ブラウザーの [進む] ボタンと [戻る] ボタンを使用して移動する場合。

ハンドラーは、アプリ内の内部ナビゲーションに対してのみ実行されます。 ユーザーが別のサイトに移動するリンクを選択した場合、またはアドレス バーを別のサイトに手動で変更した場合、場所変更ハンドラーは実行されません。

IDisposable を実装し、登録済みハンドラーを破棄して登録を解除します。 詳しくは、「ASP.NET Core Razor コンポーネントのライフサイクル」をご覧ください。

重要

場所の変更を処理するときは、JavaScript (JS) 相互運用機能を使って、ドキュメント オブジェクト モデル (DOM) のクリーンアップ タスクを実行しないでください。 クライアントの JS で MutationObserver パターンを使います。 詳しくは、「ASP.NET Core Blazor で .NET メソッドから JavaScript 関数を呼び出す」をご覧ください。

次の例では、ナビゲーション イベントの場所変更ハンドラーが登録されています。

Pages/NavHandler.razor:

@page "/nav-handler"
@inject NavigationManager Navigation
@implements IDisposable

<p>
    <button @onclick="@(() => Navigation.NavigateTo("/"))">
        Home (Allowed)
    </button>
    <button @onclick="@(() => Navigation.NavigateTo("/counter"))">
        Counter (Prevented)
    </button>
</p>

@code {
    private IDisposable? registration;

    protected override void OnAfterRender(bool firstRender)
    {
        if (firstRender)
        {
            registration = 
                Navigation.RegisterLocationChangingHandler(OnLocationChanging);
        }
    }

    private ValueTask OnLocationChanging(LocationChangingContext context)
    {
        if (context.TargetLocation == "/counter")
        {
            context.PreventNavigation();
        }

        return ValueTask.CompletedTask;
    }

    public void Dispose() => registration?.Dispose();
}

内部ナビゲーションは非同期的に取り消すことができるため、登録されたハンドラーに対して複数の重複する呼び出しが発生する可能性があります。 たとえば、ユーザーがすぐにページの [戻る] ボタンを選択したり、ナビゲーションが実行される前に複数のリンクを選択したりすると、複数のハンドラー呼び出しが発生することがあります。 非同期ナビゲーション ロジックの概要を以下に示します。

  • 場所変更ハンドラーが登録されている場合は、最初にすべてのナビゲーションが元に戻されてから、ナビゲーションが取り消されていない場合は再生されます。
  • 重複するナビゲーション要求が行われた場合、最新の要求では常に以前の要求を取り消します。これは、次のことを意味します。
    • アプリで、複数の [戻る] と [進む] ボタンの選択が 1 つの選択として扱われる場合があります。
    • ナビゲーションが完了する前にユーザーが複数のリンクを選択した場合、最後に選択したリンクによってナビゲーションが決まります。

ナビゲーション履歴スタックのエントリと状態を制御するために NavigateToNavigationOptions を渡す方法の詳細については、「ナビゲーション オプション」セクションを参照してください。

その他のコード例については、「BasicTestApp」(dotnet/aspnetcore 参照ソース) の NavigationManagerComponent に関するページを参照してください。

注意

通常、.NET 参照ソースへのドキュメント リンクを使用すると、リポジトリの既定のブランチが読み込まれます。このブランチは、.NET の次回リリースに向けて行われている現在の開発を表します。 特定のリリースのタグを選択するには、[Switch branches or tags](ブランチまたはタグの切り替え) ドロップダウン リストを使います。 詳細については、「ASP.NET Core ソース コードのバージョン タグを選択する方法」 (dotnet/AspNetCore.Docs #26205) を参照してください。

表示されている限り NavigationLock コンポーネントはナビゲーション イベントをインターセプトし、続行またはキャンセルの決定が行われるまで、特定のナビゲーションを効果的に "ロック" します。 ナビゲーション インターセプトのスコープをコンポーネントの有効期間に設定できる場合、NavigationLock を使用します。

NavigationLock パラメーター:

  • ConfirmExternalNavigation では、外部ナビゲーションの確認またはキャンセルをユーザーに求めるブラウザー ダイアログを設定します。 既定値は false です。 確認ダイアログを表示するには、ブラウザーのアドレス バーの URL を使用して外部ナビゲーションをトリガーする前に、最初にユーザーがページを操作する必要があります。 操作の要件について詳しくは、「Window: beforeunload イベント」(MDN ドキュメント) を参照してください。
  • OnBeforeInternalNavigation では、内部ナビゲーション イベントのコールバックを設定します。

次の NavLock コンポーネントでは、以下のことを行います。

  • https://www.microsoft.com へのナビゲーションを成功させるには、Microsoft の Web サイトに従う試みをユーザーが確認する必要があります。
  • PreventNavigation は、JSconfirm ダイアログを生成する JavaScript (JS) 相互運用機能呼び出しによるナビゲーションの確認をユーザーが拒否した場合に、ナビゲーションが発生しないようにするために呼び出されます。

Pages/NavLock.razor:

@page "/nav-lock"
@inject IJSRuntime JSRuntime
@inject NavigationManager Navigation

<NavigationLock ConfirmExternalNavigation="true" 
    OnBeforeInternalNavigation="OnBeforeInternalNavigation" />

<p>
    <button @onclick="Navigate">Navigate</button>
</p>

<p>
    <a href="https://www.microsoft.com">Microsoft homepage</a>
</p>

@code {
    private void Navigate()
    {
        Navigation.NavigateTo("/");
    }

    private async Task OnBeforeInternalNavigation(LocationChangingContext context)
    {
        var isConfirmed = await JSRuntime.InvokeAsync<bool>("confirm", 
            "Are you sure you want to navigate to the Index page?");

        if (!isConfirmed)
        {
            context.PreventNavigation();
        }
    }
}

その他のコード例については、「BasicTestApp」(dotnet/aspnetcore 参照ソース) の ConfigurableNavigationLock コンポーネントに関するページを参照してください。

ナビゲーション リンクを作成するときは、HTML ハイパーリンク要素 (<a>) の代わりに NavLink コンポーネントを使用します。 NavLink コンポーネントは <a> 要素のように動作しますが、href が現在の URL と一致するかどうかに基づいて active CSS クラスを切り替える点が異なります。 active クラスは、表示されているナビゲーション リンクの中でどのページがアクティブ ページであるかをユーザーが理解するのに役立ちます。 必要に応じて、CSS クラス名を NavLink.ActiveClass に割り当てて、現在のルートが href と一致したときに、レンダリングされるリンクにカスタム CSS クラスを適用します。

Note

NavMenu コンポーネント (NavMenu.razor) は、Blazor プロジェクト テンプレートから生成されたアプリの Shared フォルダーにあります。

<NavLink> 要素の Match 属性に割り当てられる 2 つの NavLinkMatch オプションがあります。

  • NavLinkMatch.All:NavLink は、現在の URL 全体に一致する場合にアクティブになります。
  • NavLinkMatch.Prefix (既定値):NavLink は、現在の URL の任意のプレフィックスに一致する場合にアクティブになります。

前の例では、HomeNavLinkhref="" はホーム URL と一致し、アプリの既定のベース パス (/) でのみ active CSS クラスを受け取ります。 2 番目の NavLink は、ユーザーが component プレフィックスを含む任意の URL (/component/component/another-segment など) にアクセスしたときに、active クラスを受け取ります。

追加の NavLink コンポーネント属性は、レンダリングされるアンカー タグに渡されます。 次の例では、NavLink コンポーネントに target 属性が含まれています。

<NavLink href="example-page" target="_blank">Example page</NavLink>

次の HTML マークアップがレンダリングされます。

<a href="example-page" target="_blank">Example page</a>

警告

Blazor による子コンテンツのレンダリング方法により、for ループ内の NavLink コンポーネントのレンダリングでは、インクリメントするループ変数が NavLink (子) コンポーネントのコンテンツ内で使用されている場合、ローカル インデックス変数が必要になります。

@for (int c = 0; c < 10; c++)
{
    var current = c;
    <li ...>
        <NavLink ... href="@c">
            <span ...></span> @current
        </NavLink>
    </li>
}

このシナリオでのインデックス変数の使用は、NavLink コンポーネントだけでなく、子コンテンツでループ変数を使用するすべての子コンポーネントで必須です。

または、Enumerable.Range と共に foreach ループを使用します。

@foreach (var c in Enumerable.Range(0,10))
{
    <li ...>
        <NavLink ... href="@c">
            <span ...></span> @c
        </NavLink>
    </li>
}

ASP.NET Core エンドポイントのルーティングの統合

"このセクションは Blazor Server アプリにのみ適用されます。 "

Blazor Server は ASP.NET Core エンドポイントのルーティングに統合されています。 ASP.NET Core アプリは、Program.csMapBlazorHub を使用して、対話型コンポーネントの着信接続を受け入れるように構成します。

app.UseRouting();

app.MapBlazorHub();
app.MapFallbackToPage("/_Host");

Blazor Server は ASP.NET Core エンドポイントのルーティングに統合されています。 ASP.NET Core アプリは、Startup.ConfigureMapBlazorHub を使用して、対話型コンポーネントの着信接続を受け入れるように構成されています。

Startup.cs:

using Microsoft.AspNetCore.Builder;

public class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        app.UseRouting();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapBlazorHub();
            endpoints.MapFallbackToPage("/_Host");
        });
    }
}
using Microsoft.AspNetCore.Builder;

public class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        app.UseRouting();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapBlazorHub();
            endpoints.MapFallbackToPage("/_Host");
        });
    }
}

一般的な構成は、すべての要求を Razor ページにルーティングすることです。これは、Blazor Server アプリのサーバー側部分のホストとして機能します。 慣例により、"ホスト" のページは通常、アプリの Pages フォルダーでは _Host.cshtml という名前になります。

ホスト ファイルに指定されるルートは、ルート照合で低い優先順位で動作するため、フォールバック ルートと呼ばれます。 フォールバック ルートは、他のルートが一致しない場合に使用されます。 これにより、Blazor Server アプリのコンポーネント ルーティングに干渉することなく、他のコントローラーやページをアプリで使用できるようになります。

ルート以外の URL のサーバー ホスト用に MapFallbackToPage を構成する方法については、「ASP.NET Core Blazor のホストと展開」をご覧ください。