Маршрутизация ASP.NET Core Blazor и навигация

Примечание.

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

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

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

Внимание

Эта информация относится к предварительному выпуску продукта, который может быть существенно изменен до его коммерческого выпуска. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.

В текущем выпуске см . версию .NET 8 этой статьи.

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

Внимание

Примеры кода в этой статье показывают методы, которые используются NavigationNavigationManager в классах и компонентах.

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

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

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

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

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

Интерактивная маршрутизация также предотвращает предварительное отображение, так как новое содержимое страницы не запрашивается с сервера с обычным запросом страницы. Дополнительные сведения см. в разделе "Предварительная ASP.NET Основные Razor компоненты".

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

Компонент 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"

<PageTitle>Routing</PageTitle>

<h1>Routing Example</h1>

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

<PageTitle>Routing</PageTitle>

<h1>Routing Example</h1>

<p>
    This page is reached at either <code>/blazor-route</code> or 
    <code>/different-blazor-route</code>.
</p>
@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)]

Примечание.

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

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

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

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

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

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

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

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

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

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

Внимание

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

Маршрутизация к компонентам из нескольких сборок

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

Router Используйте параметр компонента AdditionalAssemblies и построитель AddAdditionalAssemblies соглашений о конечной точке для обнаружения routable компонентов в дополнительных сборках. В следующих подразделах объясняется, когда и как использовать каждый 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" /> компоненту назначается интерактивная отрисовка на стороне Routes сервера (интерактивная служба SSR). Компонент Router наследует интерактивную отрисовку на стороне Routes сервера (интерактивная служба SSR) от компонента. Маршрутизатор становится интерактивным после статической маршрутизации на сервере.

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

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

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

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

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

Примечание.

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

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

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

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

В следующем примере — это routable компонент, 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}"

<PageTitle>Route Parameter 1</PageTitle>

<h1>Route Parameter Example 1</h1>

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

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

<PageTitle>Route Parameter 1</PageTitle>

<h1>Route Parameter Example 1</h1>

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

@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; }
}
@page "/route-parameter-1/{text}"

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

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

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

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

RouteParameter2.razor:

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

<PageTitle>Route Parameter 2</PageTitle>

<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";
}
@page "/route-parameter-2/{text?}"

<PageTitle>Route Parameter 2</PageTitle>

<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";
}
@page "/route-parameter-2/{text?}"

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

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

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

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

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

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

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

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

    protected override void OnParametersSet()
    {
        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 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}"

<PageTitle>User</PageTitle>

<h1>User Example</h1>

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

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

Примечание.

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

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

Ограничение Пример Примеры совпадений Инвариант
Культура
накладных
bool {active:bool} true, FALSE No
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} No
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; }
}
@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; }
}

Чтобы разрешить 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

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

Параметры маршрута catch-all

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

CatchAll.razor:

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

<PageTitle>Catch All</PageTitle>

<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; }
}
@page "/catch-all/{*pageRoute}"

<PageTitle>Catch All</PageTitle>

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

Для 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*.

URI и вспомогательные инструменты состояния навигации

Используйте NavigationManager для управления кодами URI и навигацией в коде C#. NavigationManager предоставляет события и методы, приведенные в следующей таблице.

Элемент Description
Uri Возвращает текущий абсолютный URI.
BaseUri Получает базовый URI (с завершающей косой чертой), который можно добавить в начало относительных путей URI для получения абсолютного URI. Как правило, BaseUri соответствует атрибуту href элемента <base> документа (расположение содержимого <head>).
NavigateTo Переходит по указанному URI. Если значение forceLoad равно false:
  • И расширенная навигация доступна по текущему URL-адресу, Blazorактивируется расширенная навигация.
  • Blazor В противном случае выполняется полная перезагрузка страницы для запрошенного URL-адреса.
Если значение forceLoad равно true:
  • маршрутизация на стороне клиента обходится;
  • Браузер вынужден загрузить новую страницу с сервера, независимо от того, обрабатывается ли URI на стороне клиента интерактивным маршрутизатором.

Дополнительные сведения см. в разделе "Расширенная навигация и обработка форм".

Если replace имеет значение true, текущий URI в журнале браузера заменяется вместо отправки нового URI в стек журнала.

LocationChanged Событие, возникающее при изменении расположения навигации. Дополнительные сведения см. в разделе Изменения расположения.
ToAbsoluteUri Преобразует относительный URI в абсолютный.
ToBaseRelativePath На основе базового URI приложения преобразует абсолютный URI в универсальный код ресурса (URI) относительно префикса базового URI. Пример см. в разделе "Создание URI" относительно базового префикса URI.
RegisterLocationChangingHandler Регистрирует обработчик для обработки входящих событий навигации. Вызов NavigateTo всегда вызывает обработчик.
GetUriWithQueryParameter Возвращает URI, созданный путем обновления NavigationManager.Uri с добавлением, обновлением или удалением одного параметра. Дополнительные сведения см. в разделе Строки запросов.
Элемент Description
Uri Возвращает текущий абсолютный URI.
BaseUri Получает базовый URI (с завершающей косой чертой), который можно добавить в начало относительных путей URI для получения абсолютного URI. Как правило, BaseUri соответствует атрибуту href элемента <base> документа (расположение содержимого <head>).
NavigateTo Переходит по указанному URI. Если значение forceLoad равно true:
  • маршрутизация на стороне клиента обходится;
  • браузер принуждается к загрузке новой страницы с сервера, независимо от того, обрабатывается ли универсальный код ресурса клиентским маршрутизатором.
Если replace имеет значение true, текущий URI в журнале браузера заменяется вместо отправки нового URI в стек журнала.
LocationChanged Событие, возникающее при изменении расположения навигации. Дополнительные сведения см. в разделе Изменения расположения.
ToAbsoluteUri Преобразует относительный URI в абсолютный.
ToBaseRelativePath На основе базового URI приложения преобразует абсолютный URI в универсальный код ресурса (URI) относительно префикса базового URI. Пример см. в разделе "Создание URI" относительно базового префикса URI.
RegisterLocationChangingHandler Регистрирует обработчик для обработки входящих событий навигации. Вызов NavigateTo всегда вызывает обработчик.
GetUriWithQueryParameter Возвращает URI, созданный путем обновления NavigationManager.Uri с добавлением, обновлением или удалением одного параметра. Дополнительные сведения см. в разделе Строки запросов.
Элемент Description
Uri Возвращает текущий абсолютный URI.
BaseUri Получает базовый URI (с завершающей косой чертой), который можно добавить в начало относительных путей URI для получения абсолютного URI. Как правило, BaseUri соответствует атрибуту href элемента <base> документа (расположение содержимого <head>).
NavigateTo Переходит по указанному URI. Если значение forceLoad равно true:
  • маршрутизация на стороне клиента обходится;
  • браузер принуждается к загрузке новой страницы с сервера, независимо от того, обрабатывается ли универсальный код ресурса клиентским маршрутизатором.
Если replace имеет значение true, текущий URI в журнале браузера заменяется вместо отправки нового URI в стек журнала.
LocationChanged Событие, возникающее при изменении расположения навигации. Дополнительные сведения см. в разделе Изменения расположения.
ToAbsoluteUri Преобразует относительный URI в абсолютный.
ToBaseRelativePath На основе базового URI приложения преобразует абсолютный URI в универсальный код ресурса (URI) относительно префикса базового URI. Пример см. в разделе "Создание URI" относительно базового префикса URI.
GetUriWithQueryParameter Возвращает URI, созданный путем обновления NavigationManager.Uri с добавлением, обновлением или удалением одного параметра. Дополнительные сведения см. в разделе Строки запросов.
Элемент Description
Uri Возвращает текущий абсолютный URI.
BaseUri Получает базовый URI (с завершающей косой чертой), который можно добавить в начало относительных путей URI для получения абсолютного URI. Как правило, BaseUri соответствует атрибуту href элемента <base> документа (расположение содержимого <head>).
NavigateTo Переходит по указанному URI. Если значение forceLoad равно true:
  • маршрутизация на стороне клиента обходится;
  • браузер принуждается к загрузке новой страницы с сервера, независимо от того, обрабатывается ли универсальный код ресурса клиентским маршрутизатором.
LocationChanged Событие, возникающее при изменении расположения навигации.
ToAbsoluteUri Преобразует относительный URI в абсолютный.
ToBaseRelativePath На основе базового URI приложения преобразует абсолютный URI в универсальный код ресурса (URI) относительно префикса базового URI. Пример см. в разделе "Создание URI" относительно базового префикса URI.

Изменения расположения

Для события LocationChanged LocationChangedEventArgs предоставляет следующие сведения о событиях навигации.

Приведенный ниже компонент делает следующее.

  • переходит к компоненту Counter приложения (Counter.razor) при нажатии кнопки с помощью NavigateTo;
  • обрабатывает событие изменения расположения путем оформления подписки на NavigationManager.LocationChanged.
    • При вызове Dispose платформой метод HandleLocationChanged отсоединяется. После отсоединения метода становится возможной сборка мусора для компонента.

    • При нажатии кнопки реализация средства ведения журнала записывает следующие сведения.

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

Navigate.razor:

@page "/navigate"
@implements IDisposable
@inject ILogger<Navigate> Logger
@inject NavigationManager Navigation

<PageTitle>Navigate</PageTitle>

<h1>Navigate 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"
@implements IDisposable
@inject ILogger<Navigate> Logger
@inject NavigationManager Navigation

<PageTitle>Navigate</PageTitle>

<h1>Navigate 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;
    }
}
@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;
    }
}

Дополнительные сведения об удалении компонентов см. в разделе Жизненный цикл компонента RazorASP.NET Core.

Улучшенная навигация и обработка форм

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

Blazor Web Apps поддерживает два типа маршрутизации для запросов навигации по страницам и обработки форм:

  • Обычная навигация (перекрестная навигация по документу): для URL-адреса запроса активируется полная перезагрузка.
  • Улучшенная навигация (навигация с тем же документом): Blazor перехватывает запрос и выполняет fetch запрос. Blazor затем исправляет содержимое ответа в DOM страницы. BlazorУлучшенная навигация и обработка форм избежать необходимости полностраничной перезагрузки и сохраняет больше состояния страницы, поэтому страницы загружаются быстрее, как правило, без потери позиции прокрутки пользователя на странице.

Улучшенная навигация доступна при следующих случаях:

  • Скрипт Blazor Web App (blazor.web.js) используется, а не Blazor Server скрипт (blazor.server.js) или Blazor WebAssembly скрипт (blazor.webassembly.js).
  • Эта функция не отключена явным образом.
  • URL-адрес назначения находится в пределах внутреннего базового пространства URI (базовый путь приложения).

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

Когда происходит расширенная навигация, обработчики событий, LocationChanged зарегистрированные в интерактивном сервере и среде выполнения WebAssembly, обычно вызываются. Существуют случаи, когда обработчики изменения расположения могут не перехватывать расширенную навигацию. Например, пользователь может переключиться на другую страницу перед тем, как интерактивная среда выполнения станет доступной. Поэтому важно, чтобы логика приложения не зависела от вызова обработчика изменения расположения, так как не гарантируется выполнение обработчика.

При вызове NavigateTo:

  • falseЗначение forceLoad по умолчанию:
    • И расширенная навигация доступна по текущему URL-адресу, Blazorактивируется расширенная навигация.
    • Blazor В противном случае выполняется полная перезагрузка страницы для запрошенного URL-адреса.
  • Если forceLoad это true: Blazor выполняет полную перезагрузку страницы для запрошенного URL-адреса, независимо от того, доступна ли расширенная навигация.

Вы можете обновить текущую страницу, вызвав NavigationManager.Refresh(bool forceLoad = false)функцию, которая всегда выполняет расширенную навигацию, если она доступна. Если расширенная навигация недоступна, Blazor выполняет полную перезагрузку страницы.

Navigation.Refresh();

Передайте true параметру forceLoad , чтобы убедиться, что полная перезагрузка страницы всегда выполняется, даже если расширенная навигация доступна:

Navigation.Refresh(true);

Расширенная навигация включена по умолчанию, но она может управляться иерархически и на основе каждой ссылки с помощью атрибута data-enhance-nav HTML.

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

<a href="redirect" data-enhance-nav="false">
    GET without enhanced navigation
</a>
<ul data-enhance-nav="false">
    <li>
        <a href="redirect">GET without enhanced navigation</a>
    </li>
    <li>
        <a href="redirect-2">GET without enhanced navigation</a>
    </li>
</ul>

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

Чтобы включить расширенную обработку форм, добавьте Enhance параметр в EditForm формы или data-enhance атрибут в HTML-формы (<form>):

<EditForm ... Enhance ...>
    ...
</EditForm>
<form ... data-enhance ...>
    ...
</form>

Улучшенная обработка форм не является иерархической и не будет передаваться в дочерние формы:

Неподдерживаемый: нельзя задать расширенную навигацию по элементу предка формы, чтобы включить расширенную навигацию для формы.

<div ... data-enhance ...>
    <form ...>
        <!-- NOT enhanced -->
    </form>
</div>

Расширенные записи форм работают только с Blazor конечными точками. Публикация расширенной формы в неконечнуюBlazor точку приводит к ошибке.

Чтобы отключить расширенную навигацию, выполните приведенные действия.

  • EditFormДля параметра удалите Enhance параметр из элемента формы (или задайте для него falseзначение : Enhance="false").
  • Для HTML <form>удалите data-enhance атрибут из элемента формы (или задайте для него falseзначение : data-enhance="false").

BlazorУлучшенная навигация и передача форм могут отменить динамические изменения в DOM, если обновленное содержимое не является частью отрисовки сервера. Чтобы сохранить содержимое элемента, используйте data-permanent атрибут.

В следующем примере содержимое <div> элемента динамически обновляется скриптом при загрузке страницы:

<div data-permanent>
    ...
</div>

После Blazor запуска на клиенте можно использовать enhancedload событие для прослушивания расширенных обновлений страниц. Это позволяет повторно применять изменения к DOM, которые, возможно, были отменены расширенным обновлением страницы.

Blazor.addEventListener('enhancedload', () => console.log('Enhanced update!'));

Сведения об отключении расширенной навигации и глобальной обработки форм см. в разделе ASP.NET Запуск CoreBlazor.

Улучшенная навигация с помощью статической отрисовки на стороне сервера (статический SSR) требует особого внимания при загрузке JavaScript. Дополнительные сведения см. в разделе ASP.NET Core Blazor JavaScript со статическим отображением на стороне сервера (статический SSR).

Создание URI относительно префикса базового URI

На основе базового URI приложения преобразует абсолютный URI в универсальный код ToBaseRelativePath ресурса (URI) относительно префикса базового URI.

Рассмотрим следующий пример:

try
{
    baseRelativePath = Navigation.ToBaseRelativePath(inputURI);
}
catch (ArgumentException ex)
{
    ...
}

Если базовый универсальный код ресурса (URI) приложения имеет https://localhost:8000следующий результат:

  • inputURI Передача https://localhost:8000/segment результатов в baseRelativePath segmentвиде .
  • inputURI Передача https://localhost:8000/segment1/segment2 результатов в baseRelativePath segment1/segment2виде .

Если базовый универсальный код ресурса (URI) приложения не соответствует базовому URI inputURI, ArgumentException создается исключение.

Передача https://localhost:8001/segment результатов приводит inputURI к следующему исключению:

System.ArgumentException: 'The URI 'https://localhost:8001/segment' is not contained by the base URI 'https://localhost:8000/'.'

NavigationManager использует API журнала браузера, чтобы поддерживать состояние журнала навигации, куда заносятся изменения расположения, внесенные приложением. Состояние журнала особенно полезно в сценариях внешнего перенаправления, например при проверке подлинности пользователей с внешними identity поставщиками. Дополнительные сведения см. в разделе Параметры навигации.

Передайте NavigationOptions для NavigateTo для управления следующим поведением:

  • ForceLoad: обход маршрутизации на стороне клиента и принудительная загрузка новой страницы с сервера, независимо от того, обрабатывается ли универсальный код ресурса клиентским маршрутизатором. Значение по умолчанию — false.
  • ReplaceHistoryEntry: замена текущей записи в стеке журнала. Если false, добавьте новую запись в стек журнала. Значение по умолчанию — false.
  • HistoryEntryState: возвращает или задает состояние для добавления к записи журнала.
Navigation.NavigateTo("/path", new NavigationOptions
{
    HistoryEntryState = "Navigation state"
});

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

Строки запросов

[SupplyParameterFromQuery] Используйте атрибут, чтобы указать, что параметр компонента поступает из строки запроса.

Используйте атрибут с [Parameter] атрибутом, чтобы указать, что параметр компонента routable компонента поступает из строки запроса.[SupplyParameterFromQuery]

Примечание.

Параметры компонента могут принимать значения параметров запроса в маршрутизируемых компонентах с помощью директивы @page.

Только маршрутизируемые компоненты напрямую получают параметры запроса, чтобы избежать переключения потока сведений сверху вниз и очистить порядок обработки параметров, как платформы, так и приложения. Эта конструкция позволяет избежать тонких ошибок в коде приложения, написанном при условии определенного порядка обработки параметров. Вы можете определить настраиваемые каскадные параметры или напрямую назначить регулярным параметрам компонента, чтобы передать значения параметров запроса в неизменяемые компоненты.

Параметры компонента, предоставляемые из строки запроса, поддерживают следующие типы:

  • bool, DateTime, decimalintdoublestringfloatGuidlong.
  • Варианты, допускающие значение NULL, для перечисленных выше типов.
  • Массивы предыдущих типов, допускающие или не допускающие значение NULL.

Корректное форматирование для инвариантных языка и региональных параметров применяется для данного типа (CultureInfo.InvariantCulture).

Укажите свойство Name атрибута [SupplyParameterFromQuery], чтобы использовать имя параметра запроса, отличное от имени параметра компонента. В следующем примере в C# именем параметра компонента является {COMPONENT PARAMETER NAME}. Для заполнителя {QUERY PARAMETER NAME} указано другое имя параметра запроса:

В отличие от свойств параметра компонента ([Parameter]), [SupplyParameterFromQuery] свойства можно пометить private в дополнение к public.

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

Как и свойства параметра компонента ([Parameter]), [SupplyParameterFromQuery] свойства всегда public являются свойствами в .NET 6/7. В .NET 8 или более поздней версии [SupplyParameterFromQuery] свойства можно пометить public или private.

[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.
  • Массив Stars заполняется из параметров запроса с именем star (Name = "star") и разрешается в LeVar Burton и Gary Oldman.

Примечание.

Параметры строки запроса в следующем компоненте страницы routable также работают в неизменяемом компоненте без @page директивы (например, для общего Search компонента, Search.razor используемого в других компонентах).

Search.razor:

@page "/search"

<h1>Search Example</h1>

<p>Filter: @Filter</p>

<p>Page: @Page</p>

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

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

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

    [SupplyParameterFromQuery]
    private int? Page { get; set; }

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

Search.razor:

@page "/search"

<h1>Search Example</h1>

<p>Filter: @Filter</p>

<p>Page: @Page</p>

@if (Stars is not null)
{
    <p>Stars:</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; }
}

Используйте GetUriWithQueryParameter для добавления, изменения или удаления одного или нескольких параметров запроса для текущего URL-адреса:

@inject NavigationManager Navigation

...

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

В предыдущем примере:

  • Заполнитель {NAME} указывает имя параметра запроса. Заполнитель {VALUE} указывает значение в качестве поддерживаемого типа. Поддерживаемые типы перечислены далее в этом разделе.
  • Строка возвращается равным текущему URL-адресу с одним параметром:
    • Добавляется, если имя параметра запроса не существует в текущем URL-адресе.
    • Изменено на значение, указываемое в том случае, если параметр запроса существует в текущем URL-адресе.
    • Удаляется, если тип предоставленного значения допускает значение NULL, а значение равно null.
  • Корректное форматирование для инвариантных языка и региональных параметров применяется для данного типа (CultureInfo.InvariantCulture).
  • Имя и значение параметра запроса кодируются в виде URL-адреса.
  • Все значения с соответствующим именем параметра запроса заменяются при наличии нескольких экземпляров типа.

Вызовите 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) со строкой запроса или без нее.
  • Заполнитель {PARAMETERS} является IReadOnlyDictionary<string, object>.

Поддерживаемые типы идентичны поддерживаемым типам для ограничений маршрута:

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

К поддерживаемым типам относятся:

  • Варианты, допускающие значение NULL, для перечисленных выше типов.
  • Массивы предыдущих типов, допускающие или не допускающие значение NULL.

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

С помощью сжатия, который включен по умолчанию, избегайте создания безопасных (прошедших проверку подлинности или авторизованных) интерактивных компонентов на стороне сервера, отрисовывающих данные из ненадежных источников. Ненадежные источники включают параметры маршрута, строки запроса, данные из JS взаимодействия и любой другой источник данных, которые сторонний пользователь может контролировать (базы данных, внешние службы). Дополнительные сведения см. в руководстве ASP.NET Основных BlazorSignalR руководствах по устранению угроз и устранении угроз для ASP.NET интерактивной отрисовки на стороне сервера ASP.NET CoreBlazor.

Замена значения параметра запроса, если параметр существует

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 добавляются или заменяются параметрами 35, 16, 87 и 240.
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 для добавления или замены параметра запроса name с помощью значения Morena Baccarin.
  • Вызывает NavigateTo, чтобы активировать навигацию по новому URL-адресу.
Navigation.NavigateTo(
    Navigation.GetUriWithQueryParameter("name", "Morena Baccarin"));

Строка запроса получается из свойства NavigationManager.Uri.

@inject NavigationManager Navigation

...

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

Для анализа параметров строки запроса можно воспользоваться URLSearchParams в сочетании со взаимодействием JavaScript (JS):

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

Дополнительные сведения об изоляции JavaScript с модулями JavaScript см. в статье Вызов функций JavaScript из методов .NET в ASP.NET Core Blazor.

Хэшированная маршрутизация в именованные элементы

Перейдите к именованным элементу, используя следующие подходы с хэш-ссылкой на# элемент. Маршруты к элементам в компоненте и маршруты к элементам во внешних компонентах используют корневой относительный путь. Косая черта/ () является необязательной.

Примеры для каждого из следующих подходов демонстрируют навигацию к элементу с элементом с компонентом id targetElement Counter :

  • Элемент Привязки (<a>) с элементом href:

    <a href="/counter#targetElement">
    
  • NavLink компонент с параметром href:

    <NavLink href="/counter#targetElement">
    
  • NavigationManager.NavigateTo передача относительного URL-адреса:

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

В следующем примере показана хэш-маршрутизация в заголовки H2 в компоненте и во внешние компоненты.

Home В компонентах (Home.razor) и Counter (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 компонент в приложение.

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>Home</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>

Если во время навигации наблюдается значительная задержка, например при отложенной загрузке сборок в 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.

Обработка события асинхронной навигации с помощью OnNavigateAsync

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

  • попадает на маршрут в первый раз, перейдя к нему непосредственно в браузере;
  • переходит на новый маршрут с помощью ссылки или вызова NavigationManager.NavigateTo.
<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 выполняется дважды:

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

Чтобы предотвратить выполнение кода разработчика дважды, Routes компонент может хранить NavigationContext для использования в OnNavigateAsync методе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 отменяется, то это может привести к непредсказуемому поведению, например рендерингу компонента из предыдущей навигации.

Обработка и предотвращение изменений расположения

RegisterLocationChangingHandler: регистрирует обработчик для обработки входящих событий навигации. Контекст обработчика, предоставляемый LocationChangingContext, включает следующие свойства:

  • TargetLocation: возвращает конечное расположение.
  • HistoryEntryState: возвращает состояние, связанное с записью в целевой журнал.
  • IsNavigationIntercepted: возвращает значение, указывающее, была ли перехвачена навигация из ссылки.
  • CancellationToken: возвращает значение CancellationToken, определяющее, была ли отменена навигация, например, чтобы определить, активировал ли пользователь другую навигацию.
  • PreventNavigation: вызывается, чтобы предотвратить продолжение навигации.

Компонент может зарегистрировать несколько обработчиков изменения расположения в методе жизненного OnAfterRender{Async} цикла. Навигация вызывает все обработчики изменения расположения, зарегистрированные во всем приложении (между несколькими компонентами), и любая внутренняя навигация выполняет их одновременно. В дополнение к NavigateTo обработчики вызываются в следующих случаях:

  • При нажатии на внутренние ссылки, которые указывают на URL-адреса в базовом пути приложения.
  • При навигации с помощью кнопок "Вперед" и "Назад" в браузере.

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

Реализуйте IDisposable и удалите зарегистрированные обработчики для отмены регистрации. Дополнительные сведения см. в статье Жизненный цикл компонентов Razor ASP.NET Core.

Внимание

Не пытайтесь выполнять задачи очистки DOM с помощью взаимодействия JavaScript (JS) при обработке изменений расположения. MutationObserver Используйте шаблон в JS клиенте. Дополнительные сведения см. в разделе Взаимодействие JavaScript приложения Blazor ASP.NET Core (взаимодействие JS).

В следующем примере обработчик изменения расположения регистрируется для событий навигации.

NavHandler.razor:

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

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

Так как внутренняя навигация может быть отменена асинхронно, может возникнуть несколько перекрывающихся вызовов зарегистрированных обработчиков. Например, несколько вызовов обработчика могут возникать, когда пользователь быстро нажимает кнопку "Назад" на странице или несколько ссылок перед выполнением навигации. Ниже приведена сводка по логике асинхронной навигации:

  • Если регистрируются какие-либо обработчики изменения расположения, все навигации изначально отменяется, а затем воспроизводится, если навигация не отменена.
  • Если выполняются перекрывающиеся запросы навигации, последний запрос всегда отменяет предыдущие запросы, что означает следующее:
    • Приложение может рассматривать несколько нажатий кнопки "Назад" и "Вперед" как одно.
    • Если пользователь нажимает на несколько ссылок до завершения навигации, приоритет имеет последняя выбранная ссылка.

Дополнительные сведения о передаче NavigationOptions в NavigateTo для в управления записями и состоянием стека журнала навигации см. в разделе Параметры навигации.

Дополнительные примеры кода: NavigationManagerComponent в BasicTestApp (справочные материалы по dotnet/aspnetcore).

Примечание.

По ссылкам в документации на справочные материалы по .NET обычно загружается ветвь репозитория по умолчанию, которая представляет текущую разработку для следующего выпуска .NET. Чтобы выбрать тег для определенного выпуска, используйте раскрывающийся список Switch branches or tags (Переключение ветвей или тегов). Дополнительные сведения см. в статье Выбор тега версии исходного кода ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Компонент NavigationLock перехватывает события навигации до тех пор, пока он отрисовывается, эффективно "блокировка" любой заданной навигации до тех пор, пока не будет принято решение о продолжении или отмене. Используется NavigationLock при перехвате навигации до времени существования компонента.

Параметры NavigationLock:

  • ConfirmExternalNavigation задает диалоговое окно браузера, чтобы предложить пользователю подтвердить или отменить внешнюю навигацию. Значение по умолчанию — false. Для отображения диалогового окна подтверждения требуется начальное взаимодействие пользователя со страницей перед запуском внешней навигации по URL-адресу в адресной строке браузера. Дополнительные сведения о требованиях взаимодействия см. в разделе Окно: событие beforeunload (документация по MDN).
  • OnBeforeInternalNavigation задает обратный вызов для внутренних событий навигации.

Следующий компонент NavLock:

  • Пользователь должен подтвердить попытку перейти по ссылке на веб-сайт Майкрософт перед успешной навигацией https://www.microsoft.com.
  • PreventNavigation вызывается, чтобы предотвратить переход, если пользователь отказывается подтвердить навигацию с помощью вызова взаимодействия JavaScript (JS), который создает диалоговое окно JSconfirm.

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 root page?");

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

Дополнительные примеры кода: компонент ConfigurableNavigationLock в BasicTestApp (справочные материалы по dotnet/aspnetcore).

Используйте при создании ссылок навигации компонент NavLink вместо HTML-элементов гиперссылок (<a>). Компонент NavLink ведет себя как элемент <a>, за исключением того, что он переключает класс CSS active в зависимости от того, соответствует ли его href текущему URL-адресу. Класс active помогает пользователю понять, какая страница является активной страницей среди отображаемых ссылок навигации. При необходимости назначьте имя класса CSS свойству NavLink.ActiveClass, чтобы применить пользовательский класс CSS к отображаемой ссылке, если текущий маршрут совпадает с href.

Существует два параметра NavLinkMatch, которые можно назначить атрибуту Match элемента <NavLink>:

  • NavLinkMatch.AllNavLink: активен при совпадении всего текущего URL-адреса.
  • NavLinkMatch.Prefix (по умолчанию) NavLink активен, если он соответствует любому префиксу текущего URL-адреса.

В предыдущем примере HomeNavLink href="" url-адрес совпадает active с URL-адресом home и получает только класс CSS по базовому пути по умолчанию приложения./ Второй NavLink получает класс active, когда пользователь посещает любой URL-адрес с префиксом component (например, /component и /component/another-segment).

Дополнительные атрибуты компонента NavLink передаются в отображаемый тег привязки. В следующем примере компонент NavLink включает атрибут target.

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

Отобразится следующая разметка HTML.

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

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

В связи с тем, как Blazor выполняет рендеринг дочернего содержимого, для рендеринга компонентов NavLink в цикле for требуется задать локальную переменную индекса, если в содержимом дочернего компонента NavLink используется переменная цикла приращения:

@for (int c = 1; c < 4; c++)
{
    var ct = c;
    <li ...>
        <NavLink ...>
            <span ...></span> Product #@ct
        </NavLink>
    </li>
}

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

Вместо этого можно использовать цикл foreach с Enumerable.Range:

@foreach (var c in Enumerable.Range(1, 3))
{
    <li ...>
        <NavLink ...>
            <span ...></span> Product #@c
        </NavLink>
    </li>
}

NavLink Записи компонентов можно динамически создавать из компонентов приложения с помощью отражения. В следующем примере показан общий подход к дальнейшей настройке.

Для следующей демонстрации для компонентов приложения используется согласованное стандартное соглашение об именовании:

  • Имена файлов routable компонентов используют регистр Pascal†, например Pages/ProductDetail.razor.
  • Пути к файлам компонента routable соответствуют URL-адресам в случае kebab с дефисом, отображаемым между словами в шаблоне маршрута компонента. Например, компонент ProductDetail с шаблоном маршрута /product-detail (@page "/product-detail") запрашивается в браузере по относительному URL-адресу /product-detail.

†Регистр Pascal (верхний горбатый регистр) — это соглашение об именовании без пробелов и знаков препинания, где все слова, включая первое, пишутся с прописной буквы.
'Kebab case — это соглашение об именовании без пробелов и препинания, которое использует строчные буквы и дефисы между словами.

Razor В разметке NavMenu компонента (NavMenu.razor) на странице NavLink по умолчанию Home компоненты добавляются из коллекции:

<div class="nav-scrollable" 
    onclick="document.querySelector('.navbar-toggler').click()">
    <nav class="flex-column">
        <div class="nav-item px-3">
            <NavLink class="nav-link" href="" Match="NavLinkMatch.All">
                <span class="bi bi-house-door-fill-nav-menu" 
                    aria-hidden="true"></span> Home
            </NavLink>
        </div>

+       @foreach (var name in GetRoutableComponents())
+       {
+           <div class="nav-item px-3">
+               <NavLink class="nav-link" 
+                       href="@Regex.Replace(name, @"(\B[A-Z]|\d+)", "-$1").ToLower()">
+                   @Regex.Replace(name, @"(\B[A-Z]|\d+)", " $1")
+               </NavLink>
+           </div>
+       }

    </nav>
</div>

Метод GetRoutableComponents в блоке @code :

public IEnumerable<string> GetRoutableComponents() => 
    Assembly.GetExecutingAssembly()
        .ExportedTypes
        .Where(t => t.IsSubclassOf(typeof(ComponentBase)))
        .Where(c => c.GetCustomAttributes(inherit: true)
                     .OfType<RouteAttribute>()
                     .Any())
        .Where(c => c.Name != "Home" && c.Name != "Error")
        .OrderBy(o => o.Name)
        .Select(c => c.Name);

Приведенный выше пример не содержит следующие страницы в отрисованном списке компонентов:

  • Home страница: страница отображается отдельно от автоматически созданных ссылок, так как она должна отображаться в верхней части списка и задать Match параметр.
  • Error страница: страница ошибок перемещается только платформой и не должна быть указана.

Пример приведенного выше кода в примере приложения, которое можно запустить локально, получите Blazor Web App или Blazor WebAssembly пример приложения.

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

Этот раздел относится к Blazor Web Appоперационным системам по каналу.

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

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

app.MapRazorComponents<App>();

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

app.UseRouting();

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

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.