Поделиться через


маршрутизация ASP.NET Core Blazor

Примечание.

Это не последняя версия этой статьи. В текущей версии см. версию .NET 10 этой статьи.

Предупреждение

Эта версия ASP.NET Core больше не поддерживается. Дополнительные сведения см. в политике поддержки .NET и .NET Core. В текущей версии см. версию .NET 10 этой статьи.

В этой статье объясняется Blazor маршрутизация запросов приложений с рекомендациями по статической и интерактивной маршрутизации, интеграции маршрутизации конечных точек ASP.NET Core, событиям навигации и шаблонам маршрутов и ограничений для компонентов Razor.

Маршрутизация в Blazor достигается путем предоставления шаблона маршрута каждому доступному компоненту в приложении с директивой @page. При компиляции файла Razor с директивой @page созданному классу предоставляется атрибут RouteAttribute, указывающий шаблон маршрута. Во время выполнения маршрутизатор ищет классы компонентов с RouteAttribute и отображает тот компонент, шаблон маршрута которого соответствует запрошенному URL-адресу.

Следующий компонент HelloWorld использует шаблон маршрута /hello-world, а веб-страница для этого компонента доступна по относительному URL-адресу /hello-world.

HelloWorld.razor:

@page "/hello-world"

<h1>Hello World!</h1>

Предыдущий компонент загружается в браузере /hello-world независимо от того, добавляете ли компонент в навигацию пользовательского интерфейса приложения в качестве ссылки.

Статическая и интерактивная маршрутизация

Этот раздел относится к Blazor Web Apps.

Если предварительная отрисовка включена, Blazor маршрутизатор (Router компонент) <Router>Routes.razor выполняет статическую маршрутизацию к компонентам во время статического рендеринга на стороне сервера (статическое SSR). Этот тип маршрутизации называется статической маршрутизацией.

Когда компоненту назначен интерактивный режим отрисовки Routes, маршрутизатор Blazor становится интерактивным после выполнения статического SSR и статической маршрутизации на сервере. Этот тип маршрутизации называется интерактивной маршрутизацией.

Статические маршрутизаторы используют маршрутизацию конечных точек и путь HTTP-запроса для определения компонента для отрисовки. Когда маршрутизатор становится интерактивным, он использует URL-адрес документа (URL-адрес в адресной строке браузера) для определения компонента для отрисовки. Это означает, что интерактивный маршрутизатор может динамически изменять, какой компонент отображается, если URL-адрес документа динамически изменяется на другой допустимый внутренний URL-адрес, и он может сделать это без выполнения HTTP-запроса для получения нового содержимого страницы.

Интерактивная маршрутизация также предотвращает предварительное отображение, так как новое содержимое страницы не запрашивается с сервера с обычным запросом страницы. Дополнительные сведения см. в разделе ASP.NET Сохраняемость предварительно созданного состояния CoreBlazor.

Интеграция маршрутизации конечных точек ASP.NET Core

Этот раздел относится к Blazor Web Appсистемам, работающим через цепь.

A Blazor Web App интегрируется в маршрутизацию конечных точек ASP.NET Core. Приложение ASP.NET Core настроено с конечными точками для маршрутизируемых компонентов и корневого компонента для их отрисовки в файле MapRazorComponentsProgram. Корневой компонент по умолчанию (первый загруженный компонент) — это App компонент (App.razor):

app.MapRazorComponents<App>();

Этот раздел относится к Blazor Server приложениям, работающим по каналу.

Blazor Server интегрирован с функцией маршрутизации конечных точек ASP.NET Core. Приложение ASP.NET Core настроено для приема входящих подключений для интерактивных компонентов через MapBlazorHub в файле Program.

app.UseRouting();

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

Этот раздел относится к Blazor Server приложениям, работающим по схеме.

Blazor Server интегрирован с функцией маршрутизации конечных точек ASP.NET Core. Приложение ASP.NET Core сконфигурировано для принятия входящих подключений для интерактивных компонентов с помощью MapBlazorHub в Startup.Configure.

Типичная конфигурация — маршрутизация всех запросов на страницу Razor, которая выступает в качестве узла для серверной части приложения Blazor Server. По соглашению страница узла обычно называется _Host.cshtml и находится в папке Pages приложения.

Маршрут, указанный в файле узла, называется резервным маршрутом, так как он работает с низким приоритетом в соответствии с правилами маршрутизации. Резервный маршрут используется, когда другие маршруты не сопоставляются. Это позволяет приложению использовать другие контроллеры и страницы, не мешая маршрутизации компонента в приложении Blazor Server.

Сведения о настройке MapFallbackToPage для размещения сервера с некорневым URL см. в разделе ASP.NET Core: Базовый путь к приложениюBlazor.

Шаблоны маршрутов

Компонент Router обеспечивает маршрутизацию к Razor компонентам и находится в компоненте приложения Routes (Components/Routes.razor).

Компонент Router обеспечивает маршрутизацию к Razor компонентам. Компонент Router используется в компоненте App (App.razor).

При компиляции компонента Razor (.razor) с директивой @page созданный класс компонента предоставляет атрибут RouteAttribute для указания шаблона маршрута.

При запуске приложения выполняется проверка сборки, указанной как AppAssembly маршрутизатора, для сбора сведений о маршрутах для компонентов приложения с RouteAttribute.

В среде выполнения компонент RouteView выполняет следующие операции:

  • получает RouteData от Router вместе со всеми параметрами маршрута;
  • Отображает указанный компонент с его макетом, включая любые дополнительные вложенные макеты.

При необходимости укажите параметр DefaultLayout с классом макета для компонентов, которые не задают макет с помощью директивы @layout. Шаблоны проекта платформы Blazor определяют компонент MainLayout (MainLayout.razor) как макет приложения по умолчанию. Дополнительные сведения о макетах см. в статье Макеты ASP.NET Core Blazor.

Компоненты поддерживают несколько шаблонов маршрутов с помощью нескольких директив @page. Приведенный ниже пример компонента загружается при запросах к /blazor-route и /different-blazor-route.

BlazorRoute.razor:

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

<h1>Routing Example</h1>

<p>
    This page is reached at either <code>/blazor-route</code> or 
    <code>/different-blazor-route</code>.
</p>

Внимание

Для правильного разрешения URL-адресов приложение должно содержать тег <base> (расположение содержимого <head>) с базовым путем к приложению, указанным в атрибуте href. Дополнительные сведения см. в разделе Базовый путь к приложениям ASP.NET CoreBlazor.

Router не взаимодействует со строковыми значениями запроса. Сведения о работе со строками запросов см. в разделе "Строки запроса".

В качестве альтернативы указанию шаблона маршрута как строкового литерала с директивой @page, шаблоны маршрутов на основе констант могут быть указаны с директивой @attribute.

В следующем примере директива @page в компоненте заменяется на директиву @attribute, а шаблон маршрута на основе констант в Constants.CounterRoute в приложении устанавливается в значение "/counter":

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

Примечание.

В релизе .NET 5.0.1, и для любых дополнительных релизов 5.x, компонент включает набор параметров Router, установленный на PreferExactMatches. Дополнительные сведения см. в разделе "Миграция с ASP.NET Core 3.1 на .NET 5".

Фокусировка элемента при навигации

Компонент FocusOnNavigate задает фокус пользовательского интерфейса элементу на основе селектора CSS после перехода с одной страницы на другую.

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

Когда компонент Router переходит на новую страницу, компонент FocusOnNavigate устанавливает фокус на заголовок верхнего уровня страницы (<h1>). Это распространенная стратегия для обеспечения объявления навигации по страницам при использовании пользователем средства чтения с экрана.

Предоставление пользовательского содержимого, когда содержимое не найдено

Для запросов, где содержимое не найдено, компонент Razor можно назначить параметру NotFoundPage компонента Router. Параметр работает вместе с NavigationManager.NotFound методом, вызываемым в коде разработчика, активирующим ответ Not Found. NavigationManager.NotFound описывается в следующей статье, ASP.NET Core навигацияBlazor.

Шаблон Blazor проекта содержит страницу NotFound.razor . Эта страница автоматически отрисовывается всякий раз, когда вызывается NavigationManager.NotFound, что позволяет обрабатывать отсутствующие маршруты с единым пользовательским опытом.

NotFound.razor:

@page "/not-found"
@layout MainLayout

<h3>Not Found</h3>
<p>Sorry, the content you are looking for does not exist.</p>

Компонент NotFound назначается параметру маршрутизатора NotFoundPage . NotFoundPage поддерживает маршрутизацию, которую можно использовать в промежуточном слое повторного выполнения страниц кодов состояния, включая промежуточные слои, отличные от Blazor.

В следующем примере предыдущий NotFound компонент присутствует в папке приложения Pages и передается параметру NotFoundPage :

<Router AppAssembly="@typeof(Program).Assembly" NotFoundPage="typeof(Pages.NotFound)">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" />
        <FocusOnNavigate RouteData="@routeData" Selector="h1" />
    </Found>
</Router>

Дополнительные сведения см. в следующей статье о навигации ASP.NET CoreBlazor.

Компонент Router позволяет приложению указать пользовательское содержимое, если содержимое для запрошенного маршрута не найдено.

Задайте настраиваемое содержимое для Router параметра компонента NotFound :

<Router ...>
    ...
    <NotFound>
        ...
    </NotFound>
</Router>

Произвольные элементы поддерживаются в качестве содержимого NotFound параметра, например других интерактивных компонентов. Сведения о применении макета по умолчанию к содержимому NotFound см. в статье Макеты Blazor в ASP.NET Core.

Blazor Web Appне используйте NotFound параметр (<NotFound>...</NotFound> разметку), но параметр поддерживается† для обратной совместимости в .NET 8/9, чтобы избежать критического изменения в платформе. Конвейер промежуточного программного обеспечения ASP.NET Core обрабатывает запросы на сервере. Используйте методы на стороне сервера для обработки плохих запросов.

Поддержка в этом контексте означает, что помещение разметки <NotFound>...</NotFound> не приводит к исключению, но и использование разметки не приносит результата.

Дополнительные сведения см. в следующих ресурсах:

Маршрутизация к компонентам из множества сборок

Этот раздел относится к Blazor Web Apps.

Используйте параметр Router компонента AdditionalAssemblies и создатель соглашений для конечных точек AddAdditionalAssemblies для обнаружения маршрутизируемых компонентов в дополнительных сборках. В следующих подразделах объясняется, когда и как использовать каждый API.

Статическая маршрутизация

Чтобы обнаружить маршрутизируемые компоненты из дополнительных сборок для статической серверной отрисовки (SSR), даже если маршрутизатор затем становится интерактивным для интерактивной отрисовки, сборки должны быть предоставлены платформе Blazor. Вызовите метод AddAdditionalAssemblies с дополнительными сборками, связанными с MapRazorComponents в файле Program проекта сервера.

Пример ниже включает маршрутизируемые компоненты в сборке проекта BlazorSample.Client с использованием файла проекта _Imports.razor.

app.MapRazorComponents<App>()
    .AddAdditionalAssemblies(typeof(BlazorSample.Client._Imports).Assembly);

Примечание.

Приведенные выше рекомендации также применяются в сценариях библиотеки классов компонентов . Дополнительные важные рекомендации по библиотекам классов и статическим SSR находятся в библиотеках классов ASP.NET Core Razor (RCLs) со статическим отображением на стороне сервера (статический SSR).

Интерактивная маршрутизация

Интерактивный режим отрисовки можно назначить компоненту Routes (Routes.razor), который делает маршрутизатор Blazor становящимся интерактивным после выполнения статического SSR и статической маршрутизации на сервере. Например, <Routes @rendermode="InteractiveServer" /> назначает интерактивную отрисовку на стороне сервера (Interactive SSR) для компонента Routes. Компонент Router наследует интерактивную серверную отрисовку (интерактивное SSR) от компонента Routes. Маршрутизатор становится интерактивным после статической маршрутизации на сервере.

Внутренняя навигация для интерактивной маршрутизации не включает запрос нового содержимого страницы с сервера. Поэтому предварительное отображение не выполняется для внутренних запросов страниц. Дополнительные сведения см. в разделе ASP.NET Сохраняемость предварительно созданного состояния CoreBlazor.

Если компонент Routes определен в серверном проекте, то параметр AdditionalAssemblies компонента Router должен включать сборку проекта .Client. Это позволяет маршрутизатору работать правильно при интерактивном отображении.

В следующем примере компонент Routes находится в серверном проекте, а файл _Imports.razor проекта BlazorSample.Client указывает сборку, в которой следует искать маршрутизируемые компоненты.

<Router
    AppAssembly="..."
    AdditionalAssemblies="[ typeof(BlazorSample.Client._Imports).Assembly ]">
    ...
</Router>

Дополнительные сборки проверяются в дополнение к сборке, указанной в AppAssembly.

Примечание.

Приведенные выше рекомендации также применяются в сценариях библиотеки классов компонентов .

Кроме этого, в проекте .Client существуют только маршрутизируемые компоненты с глобальным Interactive WebAssembly или Auto rendering, а компонент Routes определен в проекте .Client, а не в серверном проекте. В этом случае нет внешних сборок с маршрутизируемыми компонентами, поэтому не нужно указывать значение для AdditionalAssemblies.

Этот раздел относится к приложениям Blazor Server.

Используйте параметр Router компонента AdditionalAssemblies и создатель соглашений для конечных точек AddAdditionalAssemblies для обнаружения маршрутизируемых компонентов в дополнительных сборках.

В следующем примере Component1 — это маршрутизируемый компонент, определенный в указанной библиотеке классов компонентов с именемComponentLibrary.

<Router
    AppAssembly="..."
    AdditionalAssemblies="new[] { typeof(ComponentLibrary.Component1).Assembly }">
    ...
</Router>

Дополнительные сборки проверяются в дополнение к сборке, указанной в AppAssembly.

Параметры маршрута

Маршрутизатор использует параметры маршрута для заполнения соответствующих параметров компонента с тем же именем. Имена параметров маршрута нечувствительны к регистру. В приведенном ниже примере параметр text присваивает значение сегмента маршрута свойству Text компонента. При выполнении /route-parameter-1/amazingзапроса содержимое отображается как Blazor is amazing!.

RouteParameter1.razor:

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

<h1>Route Parameter Example 1</h1>

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

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

Поддерживаются необязательные параметры. В следующем примере необязательный параметр text назначает значение сегмента маршрута свойству Text компонента. Если сегмента нет, для Text устанавливается значение fantastic.

Необязательные параметры не поддерживаются. В приведенном ниже примере применяются две директивы @page. Первая директива позволяет переходить к компоненту без параметра. Вторая директива присваивает значение параметра маршрута {text} свойству Text компонента.

RouteParameter2.razor:

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

<h1>Route Parameter Example 2</h1>

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

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

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

Когда метод жизненного цикла OnInitialized{Async} используется вместо метода жизненного цикла OnParametersSet{Async}, назначение свойства Text по умолчанию на fantastic не происходит, если пользователь перемещается в пределах того же компонента. Например, эта ситуация возникает, когда пользователь переходит из /route-parameter-2/amazing/route-parameter-2. Так как экземпляр компонента сохраняется и принимает новые параметры, OnInitialized метод не вызывается снова.

Примечание.

Параметры маршрута не работают со значениями строки запроса. Сведения о работе со строками запросов см. в разделе "Строки запроса".

Ограничения маршрута

Ограничение маршрута обеспечивает соответствие типа сегмента маршрута компоненту.

В следующем примере маршрут к компоненту User соответствует только в следующих случаях:

  • в URL-адресе запроса имеется сегмент маршрута Id;
  • сегмент Id имеет целочисленный тип (int).

User.razor:

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

<h1>User Example</h1>

<p>User Id: @Id</p>

@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} 00001111-aaaa-2222-bbbb-3333cccc4444, {00001111-aaaa-2222-bbbb-3333cccc4444} Нет
int {id:int} 123456789, -123456789 Да
long {ticks:long} 123456789, -123456789 Да
nonfile {parameter:nonfile} Не BlazorSample.styles.css, не favicon.ico Да

Предупреждение

Ограничения маршрута, которые проверяют URL-адрес и могут быть преобразованы в тип CLR (например, int или DateTime), всегда используют инвариантные культурные настройки. Эти ограничения предполагают, что URL-адрес является нелокализуемым.

Ограничения маршрута также работают с необязательными параметрами. В следующем примере Id является обязательным параметром, а Option — необязательным логическим параметром маршрута.

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

Избегайте записи файлов в параметре маршрута

Следующий шаблон маршрута непреднамеренно фиксирует пути статических ресурсов в необязательном параметре маршрута (Optional). Например, захватывается таблица стилей приложения (.styles.css), что нарушает стили приложения.

@page "/{optional?}"

...

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

Чтобы ограничить параметр маршрута записью путей, отличных от файлов, используйте :nonfile ограничение в шаблоне маршрута:

@page "/{optional:nonfile?}"

Маршрутизация URL-адресов, содержащих точки

Шаблон маршрута на стороне сервера по умолчанию предполагает, что если последний сегмент URL-адреса запроса содержит точку (.), то запрашивается файл. Например, относительный URL-адрес /example/some.thing интерпретируется маршрутизатором как запрос файла с именем some.thing. Без дополнительной настройки приложение возвращает ответ 404 — не найден, если some.thing предназначен для маршрутизации на компонент с @page директивой и some.thing является значением параметра маршрута. Чтобы использовать маршрут с одним параметром или несколькими, содержащими точку, в приложении необходимо настроить маршрут с помощью пользовательского шаблона.

Рассмотрим приведенный ниже компонент Example, который может получать параметр маршрута из последнего сегмента URL-адреса.

Example.razor:

@page "/example/{param?}"

<p>
    Param: @Param
</p>

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

Чтобы разрешить Server приложению хостингового Blazor WebAssemblyрешения маршрутизировать запрос с точкой в param параметре маршрута, добавьте резервный шаблон маршрута файла с опциональным параметром в Program файле:

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

Чтобы настроить приложение Blazor Server для маршрутизации запроса, содержащего точку, в параметре маршрута param, добавьте в файл Program шаблон резервного маршрута страницы с необязательным параметром:

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

Подробные сведения см. в статье Маршрутизация в ASP.NET Core.

Чтобы разрешить приложению Server размещенного решения Blazor WebAssemblyмаршрутизировать запрос с точкой в параметре маршрута param, добавьте шаблон маршрута резервного файла с необязательным параметром в Startup.Configure.

Startup.cs:

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

Чтобы настроить приложение Blazor Server для маршрутизации запроса с точкой в параметре маршрута param, добавьте шаблон резервного маршрута страницы с дополнительным параметром в Startup.Configure.

Startup.cs:

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

Подробные сведения см. в статье Маршрутизация в ASP.NET Core.

Параметры универсального маршрута

В компонентах поддерживаются catch-all параметры маршрутов, которые захватывают пути, проходящие через несколько границ папок.

Параметры маршрутов общего типа:

  • Его имя должно соответствовать имени сегмента маршрута. Именование не чувствительно к регистру.
  • Тип string. Фреймворк не обеспечивает автоматическое приведение типов данных.
  • В конце URL-адреса.

CatchAll.razor:

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

<h1>Catch All Parameters Example</h1>

<p>Add some URI segments to the route and request the page again.</p>

<p>
    PageRoute: @PageRoute
</p>

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

Для URL-адреса /catch-all/this/is/a/test с шаблоном маршрута /catch-all/{*pageRoute} значение PageRoute равно this/is/a/test.

Косые черты и сегменты обработанного пути декодированы. Для шаблона маршрута /catch-all/{*pageRoute}, URL-адрес /catch-all/this/is/a%2Ftest%2A дает this/is/a/test*.

Обрабатывайте события асинхронной навигации с использованием OnNavigateAsync

Компонент Router поддерживает функцию OnNavigateAsync. Обработчик OnNavigateAsync вызывается, когда пользователь выполняет следующие действия:

  • попадает на маршрут в первый раз, перейдя к нему непосредственно в браузере;
  • Переходит к новому маршруту с помощью ссылки или вызова NavigationManager.NavigateTo, который вызывается в коде разработчика для перехода к URI. NavigationManager API описан в следующей статье, навигация ASP.NET CoreBlazor.
<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)
    {
        ...
    }
}

Пример, в котором используется OnNavigateAsync, см. Сборки с отложенной загрузкой в ASP.NET Core Blazor WebAssembly.

При пререндиринге на сервере OnNavigateAsync выполняется дважды:

  • Один раз, когда запрошенный компонент конечной точки впервые отрисовывается статически.
  • Когда браузер во второй раз отрисовывает компонент конечной точки.

Чтобы предотвратить повторное выполнение кода разработчика в OnNavigateAsync, компонент Routes может сохранять NavigationContext для использования в методе OnAfterRender{Async} жизненного цикла, где можно проверить firstRender. Для получения дополнительной информации ознакомьтесь с "Предварительной отрисовкой с помощью взаимодействия JavaScript".

Чтобы код разработчика в OnNavigateAsync не выполнялся дважды, компонент App может хранить NavigationContext для использования в OnAfterRender{Async}, где можно проверить firstRender. Для получения дополнительной информации ознакомьтесь с "Предварительной отрисовкой с помощью взаимодействия JavaScript".

Обработка отмен в OnNavigateAsync

Объект NavigationContext, переданный в обратный вызов OnNavigateAsync, содержит CancellationToken, который задается при возникновении нового события навигации. Обратный вызов OnNavigateAsync должен вызываться, если этот токен отмены установлен так, чтобы не выполнять обратный вызов OnNavigateAsync для устаревшей навигации.

Если пользователь переходит на конечную точку, а затем сразу переходит к новой конечной точке, приложение не должно продолжать выполнение обратного вызова OnNavigateAsync к первой конечной точке.

В следующем примере :

  • Токен отмены передается в функцию, вызываемую через PostAsJsonAsync, которая может отменить запрос POST, если пользователь покидает данную конечную точку /about.
  • Токен отмены задается во время операции предварительной выборки продукта, если пользователь покидает конечную точку /store.
@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);
            }
        }
    }
}

Примечание.

Если не выбрасывать исключение при отмене токена отмены в NavigationContext, это может привести к непредсказуемому поведению, например, к рендерингу компонента из предыдущей навигации.

Взаимодействие пользователей с содержимым <Navigating>

Если во время навигации наблюдается значительная задержка, например при отложенной загрузке сборок в Blazor WebAssembly приложении или медленном сетевом подключении к Blazor серверному приложению, компонент может указать пользователю, Router что переход страницы происходит.

В верхней части компонента, определяющего Router компонент, добавьте директиву @using для пространства имен Microsoft.AspNetCore.Components.Routing.

@using Microsoft.AspNetCore.Components.Routing

Предоставьте содержимое параметру Navigating для отображения во время событий перехода страницы.

Содержимое элемента маршрутизатора (<Router>...</Router>):

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

Пример, в котором используется свойство Navigating, см. Сборки с отложенной загрузкой в ASP.NET Core Blazor WebAssembly.